blob: 9f093edc42b49f97a9803afb5077fdbb6373de7c [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) {
5949 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5950 (*cur == '.') || (*cur == '-') ||
5951 (*cur == '_') || (*cur == ':') ||
5952 (IS_COMBINING(*cur)) ||
5953 (IS_EXTENDER(*cur)))
5954 cur++;
5955
5956 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5957
5958 ID = xmlStrndup(ids, cur - ids);
5959 attr = xmlGetID(doc, ID);
5960 if (attr != NULL) {
5961 elem = attr->parent;
5962 xmlXPathNodeSetAdd(ret, elem);
5963 }
5964 if (ID != NULL)
5965 xmlFree(ID);
5966
5967 while (IS_BLANK(*cur)) cur++;
5968 ids = cur;
5969 }
5970 return(ret);
5971}
5972
5973/**
Owen Taylor3473f882001-02-23 17:55:21 +00005974 * xmlXPathIdFunction:
5975 * @ctxt: the XPath Parser context
5976 * @nargs: the number of arguments
5977 *
5978 * Implement the id() XPath function
5979 * node-set id(object)
5980 * The id function selects elements by their unique ID
5981 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5982 * then the result is the union of the result of applying id to the
5983 * string value of each of the nodes in the argument node-set. When the
5984 * argument to id is of any other type, the argument is converted to a
5985 * string as if by a call to the string function; the string is split
5986 * into a whitespace-separated list of tokens (whitespace is any sequence
5987 * of characters matching the production S); the result is a node-set
5988 * containing the elements in the same document as the context node that
5989 * have a unique ID equal to any of the tokens in the list.
5990 */
5991void
5992xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005993 xmlChar *tokens;
5994 xmlNodeSetPtr ret;
5995 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005996
5997 CHECK_ARITY(1);
5998 obj = valuePop(ctxt);
5999 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006000 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006001 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006002 int i;
6003
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006004 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006005
Daniel Veillard911f49a2001-04-07 15:39:35 +00006006 if (obj->nodesetval != NULL) {
6007 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006008 tokens =
6009 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6010 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6011 ret = xmlXPathNodeSetMerge(ret, ns);
6012 xmlXPathFreeNodeSet(ns);
6013 if (tokens != NULL)
6014 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006015 }
Owen Taylor3473f882001-02-23 17:55:21 +00006016 }
6017
6018 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006019 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006020 return;
6021 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006022 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006023
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006024 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6025 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006026
Owen Taylor3473f882001-02-23 17:55:21 +00006027 xmlXPathFreeObject(obj);
6028 return;
6029}
6030
6031/**
6032 * xmlXPathLocalNameFunction:
6033 * @ctxt: the XPath Parser context
6034 * @nargs: the number of arguments
6035 *
6036 * Implement the local-name() XPath function
6037 * string local-name(node-set?)
6038 * The local-name function returns a string containing the local part
6039 * of the name of the node in the argument node-set that is first in
6040 * document order. If the node-set is empty or the first node has no
6041 * name, an empty string is returned. If the argument is omitted it
6042 * defaults to the context node.
6043 */
6044void
6045xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6046 xmlXPathObjectPtr cur;
6047
6048 if (nargs == 0) {
6049 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6050 nargs = 1;
6051 }
6052
6053 CHECK_ARITY(1);
6054 if ((ctxt->value == NULL) ||
6055 ((ctxt->value->type != XPATH_NODESET) &&
6056 (ctxt->value->type != XPATH_XSLT_TREE)))
6057 XP_ERROR(XPATH_INVALID_TYPE);
6058 cur = valuePop(ctxt);
6059
Daniel Veillard911f49a2001-04-07 15:39:35 +00006060 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006061 valuePush(ctxt, xmlXPathNewCString(""));
6062 } else {
6063 int i = 0; /* Should be first in document order !!!!! */
6064 switch (cur->nodesetval->nodeTab[i]->type) {
6065 case XML_ELEMENT_NODE:
6066 case XML_ATTRIBUTE_NODE:
6067 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006068 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6069 valuePush(ctxt, xmlXPathNewCString(""));
6070 else
6071 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006072 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6073 break;
6074 case XML_NAMESPACE_DECL:
6075 valuePush(ctxt, xmlXPathNewString(
6076 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6077 break;
6078 default:
6079 valuePush(ctxt, xmlXPathNewCString(""));
6080 }
6081 }
6082 xmlXPathFreeObject(cur);
6083}
6084
6085/**
6086 * xmlXPathNamespaceURIFunction:
6087 * @ctxt: the XPath Parser context
6088 * @nargs: the number of arguments
6089 *
6090 * Implement the namespace-uri() XPath function
6091 * string namespace-uri(node-set?)
6092 * The namespace-uri function returns a string containing the
6093 * namespace URI of the expanded name of the node in the argument
6094 * node-set that is first in document order. If the node-set is empty,
6095 * the first node has no name, or the expanded name has no namespace
6096 * URI, an empty string is returned. If the argument is omitted it
6097 * defaults to the context node.
6098 */
6099void
6100xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6101 xmlXPathObjectPtr cur;
6102
6103 if (nargs == 0) {
6104 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6105 nargs = 1;
6106 }
6107 CHECK_ARITY(1);
6108 if ((ctxt->value == NULL) ||
6109 ((ctxt->value->type != XPATH_NODESET) &&
6110 (ctxt->value->type != XPATH_XSLT_TREE)))
6111 XP_ERROR(XPATH_INVALID_TYPE);
6112 cur = valuePop(ctxt);
6113
Daniel Veillard911f49a2001-04-07 15:39:35 +00006114 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006115 valuePush(ctxt, xmlXPathNewCString(""));
6116 } else {
6117 int i = 0; /* Should be first in document order !!!!! */
6118 switch (cur->nodesetval->nodeTab[i]->type) {
6119 case XML_ELEMENT_NODE:
6120 case XML_ATTRIBUTE_NODE:
6121 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6122 valuePush(ctxt, xmlXPathNewCString(""));
6123 else
6124 valuePush(ctxt, xmlXPathNewString(
6125 cur->nodesetval->nodeTab[i]->ns->href));
6126 break;
6127 default:
6128 valuePush(ctxt, xmlXPathNewCString(""));
6129 }
6130 }
6131 xmlXPathFreeObject(cur);
6132}
6133
6134/**
6135 * xmlXPathNameFunction:
6136 * @ctxt: the XPath Parser context
6137 * @nargs: the number of arguments
6138 *
6139 * Implement the name() XPath function
6140 * string name(node-set?)
6141 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006142 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006143 * order. The QName must represent the name with respect to the namespace
6144 * declarations in effect on the node whose name is being represented.
6145 * Typically, this will be the form in which the name occurred in the XML
6146 * source. This need not be the case if there are namespace declarations
6147 * in effect on the node that associate multiple prefixes with the same
6148 * namespace. However, an implementation may include information about
6149 * the original prefix in its representation of nodes; in this case, an
6150 * implementation can ensure that the returned string is always the same
6151 * as the QName used in the XML source. If the argument it omitted it
6152 * defaults to the context node.
6153 * Libxml keep the original prefix so the "real qualified name" used is
6154 * returned.
6155 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006156static void
Daniel Veillard04383752001-07-08 14:27:15 +00006157xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6158{
Owen Taylor3473f882001-02-23 17:55:21 +00006159 xmlXPathObjectPtr cur;
6160
6161 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006162 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6163 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006164 }
6165
6166 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006167 if ((ctxt->value == NULL) ||
6168 ((ctxt->value->type != XPATH_NODESET) &&
6169 (ctxt->value->type != XPATH_XSLT_TREE)))
6170 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006171 cur = valuePop(ctxt);
6172
Daniel Veillard911f49a2001-04-07 15:39:35 +00006173 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006174 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006175 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006176 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006177
Daniel Veillard04383752001-07-08 14:27:15 +00006178 switch (cur->nodesetval->nodeTab[i]->type) {
6179 case XML_ELEMENT_NODE:
6180 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006181 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6182 valuePush(ctxt, xmlXPathNewCString(""));
6183 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6184 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006185 valuePush(ctxt,
6186 xmlXPathNewString(cur->nodesetval->
6187 nodeTab[i]->name));
6188
Daniel Veillard652d8a92003-02-04 19:28:49 +00006189 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006190 char name[2000];
6191
6192 snprintf(name, sizeof(name), "%s:%s",
6193 (char *) cur->nodesetval->nodeTab[i]->ns->
6194 prefix,
6195 (char *) cur->nodesetval->nodeTab[i]->name);
6196 name[sizeof(name) - 1] = 0;
6197 valuePush(ctxt, xmlXPathNewCString(name));
6198 }
6199 break;
6200 default:
6201 valuePush(ctxt,
6202 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6203 xmlXPathLocalNameFunction(ctxt, 1);
6204 }
Owen Taylor3473f882001-02-23 17:55:21 +00006205 }
6206 xmlXPathFreeObject(cur);
6207}
6208
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006209
6210/**
Owen Taylor3473f882001-02-23 17:55:21 +00006211 * xmlXPathStringFunction:
6212 * @ctxt: the XPath Parser context
6213 * @nargs: the number of arguments
6214 *
6215 * Implement the string() XPath function
6216 * string string(object?)
6217 * he string function converts an object to a string as follows:
6218 * - A node-set is converted to a string by returning the value of
6219 * the node in the node-set that is first in document order.
6220 * If the node-set is empty, an empty string is returned.
6221 * - A number is converted to a string as follows
6222 * + NaN is converted to the string NaN
6223 * + positive zero is converted to the string 0
6224 * + negative zero is converted to the string 0
6225 * + positive infinity is converted to the string Infinity
6226 * + negative infinity is converted to the string -Infinity
6227 * + if the number is an integer, the number is represented in
6228 * decimal form as a Number with no decimal point and no leading
6229 * zeros, preceded by a minus sign (-) if the number is negative
6230 * + otherwise, the number is represented in decimal form as a
6231 * Number including a decimal point with at least one digit
6232 * before the decimal point and at least one digit after the
6233 * decimal point, preceded by a minus sign (-) if the number
6234 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006235 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006236 * before the decimal point; beyond the one required digit
6237 * after the decimal point there must be as many, but only as
6238 * many, more digits as are needed to uniquely distinguish the
6239 * number from all other IEEE 754 numeric values.
6240 * - The boolean false value is converted to the string false.
6241 * The boolean true value is converted to the string true.
6242 *
6243 * If the argument is omitted, it defaults to a node-set with the
6244 * context node as its only member.
6245 */
6246void
6247xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6248 xmlXPathObjectPtr cur;
6249
6250 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006251 valuePush(ctxt,
6252 xmlXPathWrapString(
6253 xmlXPathCastNodeToString(ctxt->context->node)));
6254 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006255 }
6256
6257 CHECK_ARITY(1);
6258 cur = valuePop(ctxt);
6259 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006260 cur = xmlXPathConvertString(cur);
6261 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006262}
6263
6264/**
6265 * xmlXPathStringLengthFunction:
6266 * @ctxt: the XPath Parser context
6267 * @nargs: the number of arguments
6268 *
6269 * Implement the string-length() XPath function
6270 * number string-length(string?)
6271 * The string-length returns the number of characters in the string
6272 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6273 * the context node converted to a string, in other words the value
6274 * of the context node.
6275 */
6276void
6277xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6278 xmlXPathObjectPtr cur;
6279
6280 if (nargs == 0) {
6281 if (ctxt->context->node == NULL) {
6282 valuePush(ctxt, xmlXPathNewFloat(0));
6283 } else {
6284 xmlChar *content;
6285
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006286 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006287 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006288 xmlFree(content);
6289 }
6290 return;
6291 }
6292 CHECK_ARITY(1);
6293 CAST_TO_STRING;
6294 CHECK_TYPE(XPATH_STRING);
6295 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006296 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006297 xmlXPathFreeObject(cur);
6298}
6299
6300/**
6301 * xmlXPathConcatFunction:
6302 * @ctxt: the XPath Parser context
6303 * @nargs: the number of arguments
6304 *
6305 * Implement the concat() XPath function
6306 * string concat(string, string, string*)
6307 * The concat function returns the concatenation of its arguments.
6308 */
6309void
6310xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6311 xmlXPathObjectPtr cur, newobj;
6312 xmlChar *tmp;
6313
6314 if (nargs < 2) {
6315 CHECK_ARITY(2);
6316 }
6317
6318 CAST_TO_STRING;
6319 cur = valuePop(ctxt);
6320 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6321 xmlXPathFreeObject(cur);
6322 return;
6323 }
6324 nargs--;
6325
6326 while (nargs > 0) {
6327 CAST_TO_STRING;
6328 newobj = valuePop(ctxt);
6329 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6330 xmlXPathFreeObject(newobj);
6331 xmlXPathFreeObject(cur);
6332 XP_ERROR(XPATH_INVALID_TYPE);
6333 }
6334 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6335 newobj->stringval = cur->stringval;
6336 cur->stringval = tmp;
6337
6338 xmlXPathFreeObject(newobj);
6339 nargs--;
6340 }
6341 valuePush(ctxt, cur);
6342}
6343
6344/**
6345 * xmlXPathContainsFunction:
6346 * @ctxt: the XPath Parser context
6347 * @nargs: the number of arguments
6348 *
6349 * Implement the contains() XPath function
6350 * boolean contains(string, string)
6351 * The contains function returns true if the first argument string
6352 * contains the second argument string, and otherwise returns false.
6353 */
6354void
6355xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6356 xmlXPathObjectPtr hay, needle;
6357
6358 CHECK_ARITY(2);
6359 CAST_TO_STRING;
6360 CHECK_TYPE(XPATH_STRING);
6361 needle = valuePop(ctxt);
6362 CAST_TO_STRING;
6363 hay = valuePop(ctxt);
6364 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6365 xmlXPathFreeObject(hay);
6366 xmlXPathFreeObject(needle);
6367 XP_ERROR(XPATH_INVALID_TYPE);
6368 }
6369 if (xmlStrstr(hay->stringval, needle->stringval))
6370 valuePush(ctxt, xmlXPathNewBoolean(1));
6371 else
6372 valuePush(ctxt, xmlXPathNewBoolean(0));
6373 xmlXPathFreeObject(hay);
6374 xmlXPathFreeObject(needle);
6375}
6376
6377/**
6378 * xmlXPathStartsWithFunction:
6379 * @ctxt: the XPath Parser context
6380 * @nargs: the number of arguments
6381 *
6382 * Implement the starts-with() XPath function
6383 * boolean starts-with(string, string)
6384 * The starts-with function returns true if the first argument string
6385 * starts with the second argument string, and otherwise returns false.
6386 */
6387void
6388xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6389 xmlXPathObjectPtr hay, needle;
6390 int n;
6391
6392 CHECK_ARITY(2);
6393 CAST_TO_STRING;
6394 CHECK_TYPE(XPATH_STRING);
6395 needle = valuePop(ctxt);
6396 CAST_TO_STRING;
6397 hay = valuePop(ctxt);
6398 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6399 xmlXPathFreeObject(hay);
6400 xmlXPathFreeObject(needle);
6401 XP_ERROR(XPATH_INVALID_TYPE);
6402 }
6403 n = xmlStrlen(needle->stringval);
6404 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6405 valuePush(ctxt, xmlXPathNewBoolean(0));
6406 else
6407 valuePush(ctxt, xmlXPathNewBoolean(1));
6408 xmlXPathFreeObject(hay);
6409 xmlXPathFreeObject(needle);
6410}
6411
6412/**
6413 * xmlXPathSubstringFunction:
6414 * @ctxt: the XPath Parser context
6415 * @nargs: the number of arguments
6416 *
6417 * Implement the substring() XPath function
6418 * string substring(string, number, number?)
6419 * The substring function returns the substring of the first argument
6420 * starting at the position specified in the second argument with
6421 * length specified in the third argument. For example,
6422 * substring("12345",2,3) returns "234". If the third argument is not
6423 * specified, it returns the substring starting at the position specified
6424 * in the second argument and continuing to the end of the string. For
6425 * example, substring("12345",2) returns "2345". More precisely, each
6426 * character in the string (see [3.6 Strings]) is considered to have a
6427 * numeric position: the position of the first character is 1, the position
6428 * of the second character is 2 and so on. The returned substring contains
6429 * those characters for which the position of the character is greater than
6430 * or equal to the second argument and, if the third argument is specified,
6431 * less than the sum of the second and third arguments; the comparisons
6432 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6433 * - substring("12345", 1.5, 2.6) returns "234"
6434 * - substring("12345", 0, 3) returns "12"
6435 * - substring("12345", 0 div 0, 3) returns ""
6436 * - substring("12345", 1, 0 div 0) returns ""
6437 * - substring("12345", -42, 1 div 0) returns "12345"
6438 * - substring("12345", -1 div 0, 1 div 0) returns ""
6439 */
6440void
6441xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6442 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006443 double le=0, in;
6444 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006445 xmlChar *ret;
6446
Owen Taylor3473f882001-02-23 17:55:21 +00006447 if (nargs < 2) {
6448 CHECK_ARITY(2);
6449 }
6450 if (nargs > 3) {
6451 CHECK_ARITY(3);
6452 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006453 /*
6454 * take care of possible last (position) argument
6455 */
Owen Taylor3473f882001-02-23 17:55:21 +00006456 if (nargs == 3) {
6457 CAST_TO_NUMBER;
6458 CHECK_TYPE(XPATH_NUMBER);
6459 len = valuePop(ctxt);
6460 le = len->floatval;
6461 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006462 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006463
Owen Taylor3473f882001-02-23 17:55:21 +00006464 CAST_TO_NUMBER;
6465 CHECK_TYPE(XPATH_NUMBER);
6466 start = valuePop(ctxt);
6467 in = start->floatval;
6468 xmlXPathFreeObject(start);
6469 CAST_TO_STRING;
6470 CHECK_TYPE(XPATH_STRING);
6471 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006472 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006473
Daniel Veillard97ac1312001-05-30 19:14:17 +00006474 /*
6475 * If last pos not present, calculate last position
6476 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006477 if (nargs != 3) {
6478 le = (double)m;
6479 if (in < 1.0)
6480 in = 1.0;
6481 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006482
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006483 /* Need to check for the special cases where either
6484 * the index is NaN, the length is NaN, or both
6485 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006486 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006487 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006488 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006489 * To meet the requirements of the spec, the arguments
6490 * must be converted to integer format before
6491 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006492 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006493 * First we go to integer form, rounding up
6494 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006495 */
6496 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006497 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006498
Daniel Veillard9e412302002-06-10 15:59:44 +00006499 if (xmlXPathIsInf(le) == 1) {
6500 l = m;
6501 if (i < 1)
6502 i = 1;
6503 }
6504 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6505 l = 0;
6506 else {
6507 l = (int) le;
6508 if (((double)l)+0.5 <= le) l++;
6509 }
6510
6511 /* Now we normalize inidices */
6512 i -= 1;
6513 l += i;
6514 if (i < 0)
6515 i = 0;
6516 if (l > m)
6517 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006518
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006519 /* number of chars to copy */
6520 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006521
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006522 ret = xmlUTF8Strsub(str->stringval, i, l);
6523 }
6524 else {
6525 ret = NULL;
6526 }
6527
Owen Taylor3473f882001-02-23 17:55:21 +00006528 if (ret == NULL)
6529 valuePush(ctxt, xmlXPathNewCString(""));
6530 else {
6531 valuePush(ctxt, xmlXPathNewString(ret));
6532 xmlFree(ret);
6533 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006534
Owen Taylor3473f882001-02-23 17:55:21 +00006535 xmlXPathFreeObject(str);
6536}
6537
6538/**
6539 * xmlXPathSubstringBeforeFunction:
6540 * @ctxt: the XPath Parser context
6541 * @nargs: the number of arguments
6542 *
6543 * Implement the substring-before() XPath function
6544 * string substring-before(string, string)
6545 * The substring-before function returns the substring of the first
6546 * argument string that precedes the first occurrence of the second
6547 * argument string in the first argument string, or the empty string
6548 * if the first argument string does not contain the second argument
6549 * string. For example, substring-before("1999/04/01","/") returns 1999.
6550 */
6551void
6552xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6553 xmlXPathObjectPtr str;
6554 xmlXPathObjectPtr find;
6555 xmlBufferPtr target;
6556 const xmlChar *point;
6557 int offset;
6558
6559 CHECK_ARITY(2);
6560 CAST_TO_STRING;
6561 find = valuePop(ctxt);
6562 CAST_TO_STRING;
6563 str = valuePop(ctxt);
6564
6565 target = xmlBufferCreate();
6566 if (target) {
6567 point = xmlStrstr(str->stringval, find->stringval);
6568 if (point) {
6569 offset = (int)(point - str->stringval);
6570 xmlBufferAdd(target, str->stringval, offset);
6571 }
6572 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6573 xmlBufferFree(target);
6574 }
6575
6576 xmlXPathFreeObject(str);
6577 xmlXPathFreeObject(find);
6578}
6579
6580/**
6581 * xmlXPathSubstringAfterFunction:
6582 * @ctxt: the XPath Parser context
6583 * @nargs: the number of arguments
6584 *
6585 * Implement the substring-after() XPath function
6586 * string substring-after(string, string)
6587 * The substring-after function returns the substring of the first
6588 * argument string that follows the first occurrence of the second
6589 * argument string in the first argument string, or the empty stringi
6590 * if the first argument string does not contain the second argument
6591 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6592 * and substring-after("1999/04/01","19") returns 99/04/01.
6593 */
6594void
6595xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6596 xmlXPathObjectPtr str;
6597 xmlXPathObjectPtr find;
6598 xmlBufferPtr target;
6599 const xmlChar *point;
6600 int offset;
6601
6602 CHECK_ARITY(2);
6603 CAST_TO_STRING;
6604 find = valuePop(ctxt);
6605 CAST_TO_STRING;
6606 str = valuePop(ctxt);
6607
6608 target = xmlBufferCreate();
6609 if (target) {
6610 point = xmlStrstr(str->stringval, find->stringval);
6611 if (point) {
6612 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6613 xmlBufferAdd(target, &str->stringval[offset],
6614 xmlStrlen(str->stringval) - offset);
6615 }
6616 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6617 xmlBufferFree(target);
6618 }
6619
6620 xmlXPathFreeObject(str);
6621 xmlXPathFreeObject(find);
6622}
6623
6624/**
6625 * xmlXPathNormalizeFunction:
6626 * @ctxt: the XPath Parser context
6627 * @nargs: the number of arguments
6628 *
6629 * Implement the normalize-space() XPath function
6630 * string normalize-space(string?)
6631 * The normalize-space function returns the argument string with white
6632 * space normalized by stripping leading and trailing whitespace
6633 * and replacing sequences of whitespace characters by a single
6634 * space. Whitespace characters are the same allowed by the S production
6635 * in XML. If the argument is omitted, it defaults to the context
6636 * node converted to a string, in other words the value of the context node.
6637 */
6638void
6639xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6640 xmlXPathObjectPtr obj = NULL;
6641 xmlChar *source = NULL;
6642 xmlBufferPtr target;
6643 xmlChar blank;
6644
6645 if (nargs == 0) {
6646 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006647 valuePush(ctxt,
6648 xmlXPathWrapString(
6649 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006650 nargs = 1;
6651 }
6652
6653 CHECK_ARITY(1);
6654 CAST_TO_STRING;
6655 CHECK_TYPE(XPATH_STRING);
6656 obj = valuePop(ctxt);
6657 source = obj->stringval;
6658
6659 target = xmlBufferCreate();
6660 if (target && source) {
6661
6662 /* Skip leading whitespaces */
6663 while (IS_BLANK(*source))
6664 source++;
6665
6666 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6667 blank = 0;
6668 while (*source) {
6669 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006670 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006671 } else {
6672 if (blank) {
6673 xmlBufferAdd(target, &blank, 1);
6674 blank = 0;
6675 }
6676 xmlBufferAdd(target, source, 1);
6677 }
6678 source++;
6679 }
6680
6681 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6682 xmlBufferFree(target);
6683 }
6684 xmlXPathFreeObject(obj);
6685}
6686
6687/**
6688 * xmlXPathTranslateFunction:
6689 * @ctxt: the XPath Parser context
6690 * @nargs: the number of arguments
6691 *
6692 * Implement the translate() XPath function
6693 * string translate(string, string, string)
6694 * The translate function returns the first argument string with
6695 * occurrences of characters in the second argument string replaced
6696 * by the character at the corresponding position in the third argument
6697 * string. For example, translate("bar","abc","ABC") returns the string
6698 * BAr. If there is a character in the second argument string with no
6699 * character at a corresponding position in the third argument string
6700 * (because the second argument string is longer than the third argument
6701 * string), then occurrences of that character in the first argument
6702 * string are removed. For example, translate("--aaa--","abc-","ABC")
6703 * returns "AAA". If a character occurs more than once in second
6704 * argument string, then the first occurrence determines the replacement
6705 * character. If the third argument string is longer than the second
6706 * argument string, then excess characters are ignored.
6707 */
6708void
6709xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006710 xmlXPathObjectPtr str;
6711 xmlXPathObjectPtr from;
6712 xmlXPathObjectPtr to;
6713 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006714 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006715 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006716 xmlChar *point;
6717 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006718
Daniel Veillarde043ee12001-04-16 14:08:07 +00006719 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006720
Daniel Veillarde043ee12001-04-16 14:08:07 +00006721 CAST_TO_STRING;
6722 to = valuePop(ctxt);
6723 CAST_TO_STRING;
6724 from = valuePop(ctxt);
6725 CAST_TO_STRING;
6726 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006727
Daniel Veillarde043ee12001-04-16 14:08:07 +00006728 target = xmlBufferCreate();
6729 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006730 max = xmlUTF8Strlen(to->stringval);
6731 for (cptr = str->stringval; (ch=*cptr); ) {
6732 offset = xmlUTF8Strloc(from->stringval, cptr);
6733 if (offset >= 0) {
6734 if (offset < max) {
6735 point = xmlUTF8Strpos(to->stringval, offset);
6736 if (point)
6737 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6738 }
6739 } else
6740 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6741
6742 /* Step to next character in input */
6743 cptr++;
6744 if ( ch & 0x80 ) {
6745 /* if not simple ascii, verify proper format */
6746 if ( (ch & 0xc0) != 0xc0 ) {
6747 xmlGenericError(xmlGenericErrorContext,
6748 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6749 break;
6750 }
6751 /* then skip over remaining bytes for this char */
6752 while ( (ch <<= 1) & 0x80 )
6753 if ( (*cptr++ & 0xc0) != 0x80 ) {
6754 xmlGenericError(xmlGenericErrorContext,
6755 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6756 break;
6757 }
6758 if (ch & 0x80) /* must have had error encountered */
6759 break;
6760 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006761 }
Owen Taylor3473f882001-02-23 17:55:21 +00006762 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006763 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6764 xmlBufferFree(target);
6765 xmlXPathFreeObject(str);
6766 xmlXPathFreeObject(from);
6767 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006768}
6769
6770/**
6771 * xmlXPathBooleanFunction:
6772 * @ctxt: the XPath Parser context
6773 * @nargs: the number of arguments
6774 *
6775 * Implement the boolean() XPath function
6776 * boolean boolean(object)
6777 * he boolean function converts its argument to a boolean as follows:
6778 * - a number is true if and only if it is neither positive or
6779 * negative zero nor NaN
6780 * - a node-set is true if and only if it is non-empty
6781 * - a string is true if and only if its length is non-zero
6782 */
6783void
6784xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6785 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006786
6787 CHECK_ARITY(1);
6788 cur = valuePop(ctxt);
6789 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006790 cur = xmlXPathConvertBoolean(cur);
6791 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006792}
6793
6794/**
6795 * xmlXPathNotFunction:
6796 * @ctxt: the XPath Parser context
6797 * @nargs: the number of arguments
6798 *
6799 * Implement the not() XPath function
6800 * boolean not(boolean)
6801 * The not function returns true if its argument is false,
6802 * and false otherwise.
6803 */
6804void
6805xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6806 CHECK_ARITY(1);
6807 CAST_TO_BOOLEAN;
6808 CHECK_TYPE(XPATH_BOOLEAN);
6809 ctxt->value->boolval = ! ctxt->value->boolval;
6810}
6811
6812/**
6813 * xmlXPathTrueFunction:
6814 * @ctxt: the XPath Parser context
6815 * @nargs: the number of arguments
6816 *
6817 * Implement the true() XPath function
6818 * boolean true()
6819 */
6820void
6821xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6822 CHECK_ARITY(0);
6823 valuePush(ctxt, xmlXPathNewBoolean(1));
6824}
6825
6826/**
6827 * xmlXPathFalseFunction:
6828 * @ctxt: the XPath Parser context
6829 * @nargs: the number of arguments
6830 *
6831 * Implement the false() XPath function
6832 * boolean false()
6833 */
6834void
6835xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6836 CHECK_ARITY(0);
6837 valuePush(ctxt, xmlXPathNewBoolean(0));
6838}
6839
6840/**
6841 * xmlXPathLangFunction:
6842 * @ctxt: the XPath Parser context
6843 * @nargs: the number of arguments
6844 *
6845 * Implement the lang() XPath function
6846 * boolean lang(string)
6847 * The lang function returns true or false depending on whether the
6848 * language of the context node as specified by xml:lang attributes
6849 * is the same as or is a sublanguage of the language specified by
6850 * the argument string. The language of the context node is determined
6851 * by the value of the xml:lang attribute on the context node, or, if
6852 * the context node has no xml:lang attribute, by the value of the
6853 * xml:lang attribute on the nearest ancestor of the context node that
6854 * has an xml:lang attribute. If there is no such attribute, then lang
6855 * returns false. If there is such an attribute, then lang returns
6856 * true if the attribute value is equal to the argument ignoring case,
6857 * or if there is some suffix starting with - such that the attribute
6858 * value is equal to the argument ignoring that suffix of the attribute
6859 * value and ignoring case.
6860 */
6861void
6862xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6863 xmlXPathObjectPtr val;
6864 const xmlChar *theLang;
6865 const xmlChar *lang;
6866 int ret = 0;
6867 int i;
6868
6869 CHECK_ARITY(1);
6870 CAST_TO_STRING;
6871 CHECK_TYPE(XPATH_STRING);
6872 val = valuePop(ctxt);
6873 lang = val->stringval;
6874 theLang = xmlNodeGetLang(ctxt->context->node);
6875 if ((theLang != NULL) && (lang != NULL)) {
6876 for (i = 0;lang[i] != 0;i++)
6877 if (toupper(lang[i]) != toupper(theLang[i]))
6878 goto not_equal;
6879 ret = 1;
6880 }
6881not_equal:
6882 xmlXPathFreeObject(val);
6883 valuePush(ctxt, xmlXPathNewBoolean(ret));
6884}
6885
6886/**
6887 * xmlXPathNumberFunction:
6888 * @ctxt: the XPath Parser context
6889 * @nargs: the number of arguments
6890 *
6891 * Implement the number() XPath function
6892 * number number(object?)
6893 */
6894void
6895xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6896 xmlXPathObjectPtr cur;
6897 double res;
6898
6899 if (nargs == 0) {
6900 if (ctxt->context->node == NULL) {
6901 valuePush(ctxt, xmlXPathNewFloat(0.0));
6902 } else {
6903 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6904
6905 res = xmlXPathStringEvalNumber(content);
6906 valuePush(ctxt, xmlXPathNewFloat(res));
6907 xmlFree(content);
6908 }
6909 return;
6910 }
6911
6912 CHECK_ARITY(1);
6913 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006914 cur = xmlXPathConvertNumber(cur);
6915 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006916}
6917
6918/**
6919 * xmlXPathSumFunction:
6920 * @ctxt: the XPath Parser context
6921 * @nargs: the number of arguments
6922 *
6923 * Implement the sum() XPath function
6924 * number sum(node-set)
6925 * The sum function returns the sum of the values of the nodes in
6926 * the argument node-set.
6927 */
6928void
6929xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6930 xmlXPathObjectPtr cur;
6931 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006932 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006933
6934 CHECK_ARITY(1);
6935 if ((ctxt->value == NULL) ||
6936 ((ctxt->value->type != XPATH_NODESET) &&
6937 (ctxt->value->type != XPATH_XSLT_TREE)))
6938 XP_ERROR(XPATH_INVALID_TYPE);
6939 cur = valuePop(ctxt);
6940
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006941 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006942 valuePush(ctxt, xmlXPathNewFloat(0.0));
6943 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006944 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6945 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006946 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006947 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006948 }
6949 xmlXPathFreeObject(cur);
6950}
6951
6952/**
6953 * xmlXPathFloorFunction:
6954 * @ctxt: the XPath Parser context
6955 * @nargs: the number of arguments
6956 *
6957 * Implement the floor() XPath function
6958 * number floor(number)
6959 * The floor function returns the largest (closest to positive infinity)
6960 * number that is not greater than the argument and that is an integer.
6961 */
6962void
6963xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006964 double f;
6965
Owen Taylor3473f882001-02-23 17:55:21 +00006966 CHECK_ARITY(1);
6967 CAST_TO_NUMBER;
6968 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006969
6970 f = (double)((int) ctxt->value->floatval);
6971 if (f != ctxt->value->floatval) {
6972 if (ctxt->value->floatval > 0)
6973 ctxt->value->floatval = f;
6974 else
6975 ctxt->value->floatval = f - 1;
6976 }
Owen Taylor3473f882001-02-23 17:55:21 +00006977}
6978
6979/**
6980 * xmlXPathCeilingFunction:
6981 * @ctxt: the XPath Parser context
6982 * @nargs: the number of arguments
6983 *
6984 * Implement the ceiling() XPath function
6985 * number ceiling(number)
6986 * The ceiling function returns the smallest (closest to negative infinity)
6987 * number that is not less than the argument and that is an integer.
6988 */
6989void
6990xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6991 double f;
6992
6993 CHECK_ARITY(1);
6994 CAST_TO_NUMBER;
6995 CHECK_TYPE(XPATH_NUMBER);
6996
6997#if 0
6998 ctxt->value->floatval = ceil(ctxt->value->floatval);
6999#else
7000 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007001 if (f != ctxt->value->floatval) {
7002 if (ctxt->value->floatval > 0)
7003 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007004 else {
7005 if (ctxt->value->floatval < 0 && f == 0)
7006 ctxt->value->floatval = xmlXPathNZERO;
7007 else
7008 ctxt->value->floatval = f;
7009 }
7010
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007011 }
Owen Taylor3473f882001-02-23 17:55:21 +00007012#endif
7013}
7014
7015/**
7016 * xmlXPathRoundFunction:
7017 * @ctxt: the XPath Parser context
7018 * @nargs: the number of arguments
7019 *
7020 * Implement the round() XPath function
7021 * number round(number)
7022 * The round function returns the number that is closest to the
7023 * argument and that is an integer. If there are two such numbers,
7024 * then the one that is even is returned.
7025 */
7026void
7027xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7028 double f;
7029
7030 CHECK_ARITY(1);
7031 CAST_TO_NUMBER;
7032 CHECK_TYPE(XPATH_NUMBER);
7033
Daniel Veillardcda96922001-08-21 10:56:31 +00007034 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7035 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7036 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007037 (ctxt->value->floatval == 0.0))
7038 return;
7039
Owen Taylor3473f882001-02-23 17:55:21 +00007040 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007041 if (ctxt->value->floatval < 0) {
7042 if (ctxt->value->floatval < f - 0.5)
7043 ctxt->value->floatval = f - 1;
7044 else
7045 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007046 if (ctxt->value->floatval == 0)
7047 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007048 } else {
7049 if (ctxt->value->floatval < f + 0.5)
7050 ctxt->value->floatval = f;
7051 else
7052 ctxt->value->floatval = f + 1;
7053 }
Owen Taylor3473f882001-02-23 17:55:21 +00007054}
7055
7056/************************************************************************
7057 * *
7058 * The Parser *
7059 * *
7060 ************************************************************************/
7061
7062/*
7063 * a couple of forward declarations since we use a recursive call based
7064 * implementation.
7065 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007066static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007067static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007068static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007069static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007070static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7071 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007072
7073/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007074 * xmlXPathCurrentChar:
7075 * @ctxt: the XPath parser context
7076 * @cur: pointer to the beginning of the char
7077 * @len: pointer to the length of the char read
7078 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007079 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007080 * bytes in the input buffer.
7081 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007082 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007083 */
7084
7085static int
7086xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7087 unsigned char c;
7088 unsigned int val;
7089 const xmlChar *cur;
7090
7091 if (ctxt == NULL)
7092 return(0);
7093 cur = ctxt->cur;
7094
7095 /*
7096 * We are supposed to handle UTF8, check it's valid
7097 * From rfc2044: encoding of the Unicode values on UTF-8:
7098 *
7099 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7100 * 0000 0000-0000 007F 0xxxxxxx
7101 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7102 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7103 *
7104 * Check for the 0x110000 limit too
7105 */
7106 c = *cur;
7107 if (c & 0x80) {
7108 if ((cur[1] & 0xc0) != 0x80)
7109 goto encoding_error;
7110 if ((c & 0xe0) == 0xe0) {
7111
7112 if ((cur[2] & 0xc0) != 0x80)
7113 goto encoding_error;
7114 if ((c & 0xf0) == 0xf0) {
7115 if (((c & 0xf8) != 0xf0) ||
7116 ((cur[3] & 0xc0) != 0x80))
7117 goto encoding_error;
7118 /* 4-byte code */
7119 *len = 4;
7120 val = (cur[0] & 0x7) << 18;
7121 val |= (cur[1] & 0x3f) << 12;
7122 val |= (cur[2] & 0x3f) << 6;
7123 val |= cur[3] & 0x3f;
7124 } else {
7125 /* 3-byte code */
7126 *len = 3;
7127 val = (cur[0] & 0xf) << 12;
7128 val |= (cur[1] & 0x3f) << 6;
7129 val |= cur[2] & 0x3f;
7130 }
7131 } else {
7132 /* 2-byte code */
7133 *len = 2;
7134 val = (cur[0] & 0x1f) << 6;
7135 val |= cur[1] & 0x3f;
7136 }
7137 if (!IS_CHAR(val)) {
7138 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7139 }
7140 return(val);
7141 } else {
7142 /* 1-byte code */
7143 *len = 1;
7144 return((int) *cur);
7145 }
7146encoding_error:
7147 /*
7148 * If we detect an UTF8 error that probably mean that the
7149 * input encoding didn't get properly advertized in the
7150 * declaration header. Report the error and switch the encoding
7151 * to ISO-Latin-1 (if you don't like this policy, just declare the
7152 * encoding !)
7153 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007154 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007155 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007156}
7157
7158/**
Owen Taylor3473f882001-02-23 17:55:21 +00007159 * xmlXPathParseNCName:
7160 * @ctxt: the XPath Parser context
7161 *
7162 * parse an XML namespace non qualified name.
7163 *
7164 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7165 *
7166 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7167 * CombiningChar | Extender
7168 *
7169 * Returns the namespace name or NULL
7170 */
7171
7172xmlChar *
7173xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007174 const xmlChar *in;
7175 xmlChar *ret;
7176 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007177
Daniel Veillard2156a562001-04-28 12:24:34 +00007178 /*
7179 * Accelerator for simple ASCII names
7180 */
7181 in = ctxt->cur;
7182 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7183 ((*in >= 0x41) && (*in <= 0x5A)) ||
7184 (*in == '_')) {
7185 in++;
7186 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7187 ((*in >= 0x41) && (*in <= 0x5A)) ||
7188 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007189 (*in == '_') || (*in == '.') ||
7190 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007191 in++;
7192 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7193 (*in == '[') || (*in == ']') || (*in == ':') ||
7194 (*in == '@') || (*in == '*')) {
7195 count = in - ctxt->cur;
7196 if (count == 0)
7197 return(NULL);
7198 ret = xmlStrndup(ctxt->cur, count);
7199 ctxt->cur = in;
7200 return(ret);
7201 }
7202 }
7203 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007204}
7205
Daniel Veillard2156a562001-04-28 12:24:34 +00007206
Owen Taylor3473f882001-02-23 17:55:21 +00007207/**
7208 * xmlXPathParseQName:
7209 * @ctxt: the XPath Parser context
7210 * @prefix: a xmlChar **
7211 *
7212 * parse an XML qualified name
7213 *
7214 * [NS 5] QName ::= (Prefix ':')? LocalPart
7215 *
7216 * [NS 6] Prefix ::= NCName
7217 *
7218 * [NS 7] LocalPart ::= NCName
7219 *
7220 * Returns the function returns the local part, and prefix is updated
7221 * to get the Prefix if any.
7222 */
7223
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007224static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007225xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7226 xmlChar *ret = NULL;
7227
7228 *prefix = NULL;
7229 ret = xmlXPathParseNCName(ctxt);
7230 if (CUR == ':') {
7231 *prefix = ret;
7232 NEXT;
7233 ret = xmlXPathParseNCName(ctxt);
7234 }
7235 return(ret);
7236}
7237
7238/**
7239 * xmlXPathParseName:
7240 * @ctxt: the XPath Parser context
7241 *
7242 * parse an XML name
7243 *
7244 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7245 * CombiningChar | Extender
7246 *
7247 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7248 *
7249 * Returns the namespace name or NULL
7250 */
7251
7252xmlChar *
7253xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007254 const xmlChar *in;
7255 xmlChar *ret;
7256 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007257
Daniel Veillard61d80a22001-04-27 17:13:01 +00007258 /*
7259 * Accelerator for simple ASCII names
7260 */
7261 in = ctxt->cur;
7262 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7263 ((*in >= 0x41) && (*in <= 0x5A)) ||
7264 (*in == '_') || (*in == ':')) {
7265 in++;
7266 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7267 ((*in >= 0x41) && (*in <= 0x5A)) ||
7268 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007269 (*in == '_') || (*in == '-') ||
7270 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007271 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007272 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007273 count = in - ctxt->cur;
7274 ret = xmlStrndup(ctxt->cur, count);
7275 ctxt->cur = in;
7276 return(ret);
7277 }
7278 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007279 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007280}
7281
Daniel Veillard61d80a22001-04-27 17:13:01 +00007282static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007283xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007284 xmlChar buf[XML_MAX_NAMELEN + 5];
7285 int len = 0, l;
7286 int c;
7287
7288 /*
7289 * Handler for more complex cases
7290 */
7291 c = CUR_CHAR(l);
7292 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007293 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7294 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007295 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007296 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007297 return(NULL);
7298 }
7299
7300 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7301 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7302 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007303 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007304 (IS_COMBINING(c)) ||
7305 (IS_EXTENDER(c)))) {
7306 COPY_BUF(l,buf,len,c);
7307 NEXTL(l);
7308 c = CUR_CHAR(l);
7309 if (len >= XML_MAX_NAMELEN) {
7310 /*
7311 * Okay someone managed to make a huge name, so he's ready to pay
7312 * for the processing speed.
7313 */
7314 xmlChar *buffer;
7315 int max = len * 2;
7316
7317 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
7318 if (buffer == NULL) {
7319 XP_ERROR0(XPATH_MEMORY_ERROR);
7320 }
7321 memcpy(buffer, buf, len);
7322 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7323 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007324 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007325 (IS_COMBINING(c)) ||
7326 (IS_EXTENDER(c))) {
7327 if (len + 10 > max) {
7328 max *= 2;
7329 buffer = (xmlChar *) xmlRealloc(buffer,
7330 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007331 if (buffer == NULL) {
7332 XP_ERROR0(XPATH_MEMORY_ERROR);
7333 }
7334 }
7335 COPY_BUF(l,buffer,len,c);
7336 NEXTL(l);
7337 c = CUR_CHAR(l);
7338 }
7339 buffer[len] = 0;
7340 return(buffer);
7341 }
7342 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007343 if (len == 0)
7344 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007345 return(xmlStrndup(buf, len));
7346}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007347
7348#define MAX_FRAC 20
7349
7350static double my_pow10[MAX_FRAC] = {
7351 1.0, 10.0, 100.0, 1000.0, 10000.0,
7352 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7353 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7354 100000000000000.0,
7355 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7356 1000000000000000000.0, 10000000000000000000.0
7357};
7358
Owen Taylor3473f882001-02-23 17:55:21 +00007359/**
7360 * xmlXPathStringEvalNumber:
7361 * @str: A string to scan
7362 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007363 * [30a] Float ::= Number ('e' Digits?)?
7364 *
Owen Taylor3473f882001-02-23 17:55:21 +00007365 * [30] Number ::= Digits ('.' Digits?)?
7366 * | '.' Digits
7367 * [31] Digits ::= [0-9]+
7368 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007369 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007370 * In complement of the Number expression, this function also handles
7371 * negative values : '-' Number.
7372 *
7373 * Returns the double value.
7374 */
7375double
7376xmlXPathStringEvalNumber(const xmlChar *str) {
7377 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007378 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007379 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007380 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007381 int exponent = 0;
7382 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007383#ifdef __GNUC__
7384 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007385 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007386#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007387 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007388 while (IS_BLANK(*cur)) cur++;
7389 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7390 return(xmlXPathNAN);
7391 }
7392 if (*cur == '-') {
7393 isneg = 1;
7394 cur++;
7395 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007396
7397#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007398 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007399 * tmp/temp is a workaround against a gcc compiler bug
7400 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007401 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007402 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007403 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007404 ret = ret * 10;
7405 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007406 ok = 1;
7407 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007408 temp = (double) tmp;
7409 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007410 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007411#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007412 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007413 while ((*cur >= '0') && (*cur <= '9')) {
7414 ret = ret * 10 + (*cur - '0');
7415 ok = 1;
7416 cur++;
7417 }
7418#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007419
Owen Taylor3473f882001-02-23 17:55:21 +00007420 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007421 int v, frac = 0;
7422 double fraction = 0;
7423
Owen Taylor3473f882001-02-23 17:55:21 +00007424 cur++;
7425 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7426 return(xmlXPathNAN);
7427 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007428 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7429 v = (*cur - '0');
7430 fraction = fraction * 10 + v;
7431 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007432 cur++;
7433 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007434 fraction /= my_pow10[frac];
7435 ret = ret + fraction;
7436 while ((*cur >= '0') && (*cur <= '9'))
7437 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007438 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007439 if ((*cur == 'e') || (*cur == 'E')) {
7440 cur++;
7441 if (*cur == '-') {
7442 is_exponent_negative = 1;
7443 cur++;
7444 }
7445 while ((*cur >= '0') && (*cur <= '9')) {
7446 exponent = exponent * 10 + (*cur - '0');
7447 cur++;
7448 }
7449 }
Owen Taylor3473f882001-02-23 17:55:21 +00007450 while (IS_BLANK(*cur)) cur++;
7451 if (*cur != 0) return(xmlXPathNAN);
7452 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007453 if (is_exponent_negative) exponent = -exponent;
7454 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007455 return(ret);
7456}
7457
7458/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007459 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007460 * @ctxt: the XPath Parser context
7461 *
7462 * [30] Number ::= Digits ('.' Digits?)?
7463 * | '.' Digits
7464 * [31] Digits ::= [0-9]+
7465 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007466 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007467 *
7468 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007469static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007470xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7471{
Owen Taylor3473f882001-02-23 17:55:21 +00007472 double ret = 0.0;
7473 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007474 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007475 int exponent = 0;
7476 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007477#ifdef __GNUC__
7478 unsigned long tmp = 0;
7479 double temp;
7480#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007481
7482 CHECK_ERROR;
7483 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7484 XP_ERROR(XPATH_NUMBER_ERROR);
7485 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007486#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007487 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007488 * tmp/temp is a workaround against a gcc compiler bug
7489 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007490 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007491 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007492 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007493 ret = ret * 10;
7494 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007495 ok = 1;
7496 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007497 temp = (double) tmp;
7498 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007499 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007500#else
7501 ret = 0;
7502 while ((CUR >= '0') && (CUR <= '9')) {
7503 ret = ret * 10 + (CUR - '0');
7504 ok = 1;
7505 NEXT;
7506 }
7507#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007508 if (CUR == '.') {
7509 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007510 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7511 XP_ERROR(XPATH_NUMBER_ERROR);
7512 }
7513 while ((CUR >= '0') && (CUR <= '9')) {
7514 mult /= 10;
7515 ret = ret + (CUR - '0') * mult;
7516 NEXT;
7517 }
Owen Taylor3473f882001-02-23 17:55:21 +00007518 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007519 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007520 NEXT;
7521 if (CUR == '-') {
7522 is_exponent_negative = 1;
7523 NEXT;
7524 }
7525 while ((CUR >= '0') && (CUR <= '9')) {
7526 exponent = exponent * 10 + (CUR - '0');
7527 NEXT;
7528 }
7529 if (is_exponent_negative)
7530 exponent = -exponent;
7531 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007532 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007533 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007534 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007535}
7536
7537/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007538 * xmlXPathParseLiteral:
7539 * @ctxt: the XPath Parser context
7540 *
7541 * Parse a Literal
7542 *
7543 * [29] Literal ::= '"' [^"]* '"'
7544 * | "'" [^']* "'"
7545 *
7546 * Returns the value found or NULL in case of error
7547 */
7548static xmlChar *
7549xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7550 const xmlChar *q;
7551 xmlChar *ret = NULL;
7552
7553 if (CUR == '"') {
7554 NEXT;
7555 q = CUR_PTR;
7556 while ((IS_CHAR(CUR)) && (CUR != '"'))
7557 NEXT;
7558 if (!IS_CHAR(CUR)) {
7559 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7560 } else {
7561 ret = xmlStrndup(q, CUR_PTR - q);
7562 NEXT;
7563 }
7564 } else if (CUR == '\'') {
7565 NEXT;
7566 q = CUR_PTR;
7567 while ((IS_CHAR(CUR)) && (CUR != '\''))
7568 NEXT;
7569 if (!IS_CHAR(CUR)) {
7570 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7571 } else {
7572 ret = xmlStrndup(q, CUR_PTR - q);
7573 NEXT;
7574 }
7575 } else {
7576 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7577 }
7578 return(ret);
7579}
7580
7581/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007582 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007583 * @ctxt: the XPath Parser context
7584 *
7585 * Parse a Literal and push it on the stack.
7586 *
7587 * [29] Literal ::= '"' [^"]* '"'
7588 * | "'" [^']* "'"
7589 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007590 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007591 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007592static void
7593xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007594 const xmlChar *q;
7595 xmlChar *ret = NULL;
7596
7597 if (CUR == '"') {
7598 NEXT;
7599 q = CUR_PTR;
7600 while ((IS_CHAR(CUR)) && (CUR != '"'))
7601 NEXT;
7602 if (!IS_CHAR(CUR)) {
7603 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7604 } else {
7605 ret = xmlStrndup(q, CUR_PTR - q);
7606 NEXT;
7607 }
7608 } else if (CUR == '\'') {
7609 NEXT;
7610 q = CUR_PTR;
7611 while ((IS_CHAR(CUR)) && (CUR != '\''))
7612 NEXT;
7613 if (!IS_CHAR(CUR)) {
7614 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7615 } else {
7616 ret = xmlStrndup(q, CUR_PTR - q);
7617 NEXT;
7618 }
7619 } else {
7620 XP_ERROR(XPATH_START_LITERAL_ERROR);
7621 }
7622 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007623 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7624 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007625 xmlFree(ret);
7626}
7627
7628/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007629 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007630 * @ctxt: the XPath Parser context
7631 *
7632 * Parse a VariableReference, evaluate it and push it on the stack.
7633 *
7634 * The variable bindings consist of a mapping from variable names
7635 * to variable values. The value of a variable is an object, which
7636 * of any of the types that are possible for the value of an expression,
7637 * and may also be of additional types not specified here.
7638 *
7639 * Early evaluation is possible since:
7640 * The variable bindings [...] used to evaluate a subexpression are
7641 * always the same as those used to evaluate the containing expression.
7642 *
7643 * [36] VariableReference ::= '$' QName
7644 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645static void
7646xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007647 xmlChar *name;
7648 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007649
7650 SKIP_BLANKS;
7651 if (CUR != '$') {
7652 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7653 }
7654 NEXT;
7655 name = xmlXPathParseQName(ctxt, &prefix);
7656 if (name == NULL) {
7657 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7658 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007659 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007660 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7661 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007662 SKIP_BLANKS;
7663}
7664
7665/**
7666 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007667 * @name: a name string
7668 *
7669 * Is the name given a NodeType one.
7670 *
7671 * [38] NodeType ::= 'comment'
7672 * | 'text'
7673 * | 'processing-instruction'
7674 * | 'node'
7675 *
7676 * Returns 1 if true 0 otherwise
7677 */
7678int
7679xmlXPathIsNodeType(const xmlChar *name) {
7680 if (name == NULL)
7681 return(0);
7682
Daniel Veillard1971ee22002-01-31 20:29:19 +00007683 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007684 return(1);
7685 if (xmlStrEqual(name, BAD_CAST "text"))
7686 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007687 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007688 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007689 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007690 return(1);
7691 return(0);
7692}
7693
7694/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007695 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007696 * @ctxt: the XPath Parser context
7697 *
7698 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7699 * [17] Argument ::= Expr
7700 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007701 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007702 * pushed on the stack
7703 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007704static void
7705xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007706 xmlChar *name;
7707 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007708 int nbargs = 0;
7709
7710 name = xmlXPathParseQName(ctxt, &prefix);
7711 if (name == NULL) {
7712 XP_ERROR(XPATH_EXPR_ERROR);
7713 }
7714 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007715#ifdef DEBUG_EXPR
7716 if (prefix == NULL)
7717 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7718 name);
7719 else
7720 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7721 prefix, name);
7722#endif
7723
Owen Taylor3473f882001-02-23 17:55:21 +00007724 if (CUR != '(') {
7725 XP_ERROR(XPATH_EXPR_ERROR);
7726 }
7727 NEXT;
7728 SKIP_BLANKS;
7729
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007730 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007731 if (CUR != ')') {
7732 while (CUR != 0) {
7733 int op1 = ctxt->comp->last;
7734 ctxt->comp->last = -1;
7735 xmlXPathCompileExpr(ctxt);
7736 CHECK_ERROR;
7737 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7738 nbargs++;
7739 if (CUR == ')') break;
7740 if (CUR != ',') {
7741 XP_ERROR(XPATH_EXPR_ERROR);
7742 }
7743 NEXT;
7744 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007745 }
Owen Taylor3473f882001-02-23 17:55:21 +00007746 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007747 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7748 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007749 NEXT;
7750 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007751}
7752
7753/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007754 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007755 * @ctxt: the XPath Parser context
7756 *
7757 * [15] PrimaryExpr ::= VariableReference
7758 * | '(' Expr ')'
7759 * | Literal
7760 * | Number
7761 * | FunctionCall
7762 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007763 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007764 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007765static void
7766xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007767 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007768 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007769 else if (CUR == '(') {
7770 NEXT;
7771 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007772 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007773 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007774 if (CUR != ')') {
7775 XP_ERROR(XPATH_EXPR_ERROR);
7776 }
7777 NEXT;
7778 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007779 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007780 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007781 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007782 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007783 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007784 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007785 }
7786 SKIP_BLANKS;
7787}
7788
7789/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007790 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007791 * @ctxt: the XPath Parser context
7792 *
7793 * [20] FilterExpr ::= PrimaryExpr
7794 * | FilterExpr Predicate
7795 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007796 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007797 * Square brackets are used to filter expressions in the same way that
7798 * they are used in location paths. It is an error if the expression to
7799 * be filtered does not evaluate to a node-set. The context node list
7800 * used for evaluating the expression in square brackets is the node-set
7801 * to be filtered listed in document order.
7802 */
7803
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007804static void
7805xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7806 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007807 CHECK_ERROR;
7808 SKIP_BLANKS;
7809
7810 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007811 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007812 SKIP_BLANKS;
7813 }
7814
7815
7816}
7817
7818/**
7819 * xmlXPathScanName:
7820 * @ctxt: the XPath Parser context
7821 *
7822 * Trickery: parse an XML name but without consuming the input flow
7823 * Needed to avoid insanity in the parser state.
7824 *
7825 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7826 * CombiningChar | Extender
7827 *
7828 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7829 *
7830 * [6] Names ::= Name (S Name)*
7831 *
7832 * Returns the Name parsed or NULL
7833 */
7834
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007835static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007836xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7837 xmlChar buf[XML_MAX_NAMELEN];
7838 int len = 0;
7839
7840 SKIP_BLANKS;
7841 if (!IS_LETTER(CUR) && (CUR != '_') &&
7842 (CUR != ':')) {
7843 return(NULL);
7844 }
7845
7846 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7847 (NXT(len) == '.') || (NXT(len) == '-') ||
7848 (NXT(len) == '_') || (NXT(len) == ':') ||
7849 (IS_COMBINING(NXT(len))) ||
7850 (IS_EXTENDER(NXT(len)))) {
7851 buf[len] = NXT(len);
7852 len++;
7853 if (len >= XML_MAX_NAMELEN) {
7854 xmlGenericError(xmlGenericErrorContext,
7855 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7856 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7857 (NXT(len) == '.') || (NXT(len) == '-') ||
7858 (NXT(len) == '_') || (NXT(len) == ':') ||
7859 (IS_COMBINING(NXT(len))) ||
7860 (IS_EXTENDER(NXT(len))))
7861 len++;
7862 break;
7863 }
7864 }
7865 return(xmlStrndup(buf, len));
7866}
7867
7868/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007869 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007870 * @ctxt: the XPath Parser context
7871 *
7872 * [19] PathExpr ::= LocationPath
7873 * | FilterExpr
7874 * | FilterExpr '/' RelativeLocationPath
7875 * | FilterExpr '//' RelativeLocationPath
7876 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007877 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007878 * The / operator and // operators combine an arbitrary expression
7879 * and a relative location path. It is an error if the expression
7880 * does not evaluate to a node-set.
7881 * The / operator does composition in the same way as when / is
7882 * used in a location path. As in location paths, // is short for
7883 * /descendant-or-self::node()/.
7884 */
7885
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007886static void
7887xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007888 int lc = 1; /* Should we branch to LocationPath ? */
7889 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7890
7891 SKIP_BLANKS;
7892 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007893 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007894 lc = 0;
7895 } else if (CUR == '*') {
7896 /* relative or absolute location path */
7897 lc = 1;
7898 } else if (CUR == '/') {
7899 /* relative or absolute location path */
7900 lc = 1;
7901 } else if (CUR == '@') {
7902 /* relative abbreviated attribute location path */
7903 lc = 1;
7904 } else if (CUR == '.') {
7905 /* relative abbreviated attribute location path */
7906 lc = 1;
7907 } else {
7908 /*
7909 * Problem is finding if we have a name here whether it's:
7910 * - a nodetype
7911 * - a function call in which case it's followed by '('
7912 * - an axis in which case it's followed by ':'
7913 * - a element name
7914 * We do an a priori analysis here rather than having to
7915 * maintain parsed token content through the recursive function
7916 * calls. This looks uglier but makes the code quite easier to
7917 * read/write/debug.
7918 */
7919 SKIP_BLANKS;
7920 name = xmlXPathScanName(ctxt);
7921 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7922#ifdef DEBUG_STEP
7923 xmlGenericError(xmlGenericErrorContext,
7924 "PathExpr: Axis\n");
7925#endif
7926 lc = 1;
7927 xmlFree(name);
7928 } else if (name != NULL) {
7929 int len =xmlStrlen(name);
7930 int blank = 0;
7931
7932
7933 while (NXT(len) != 0) {
7934 if (NXT(len) == '/') {
7935 /* element name */
7936#ifdef DEBUG_STEP
7937 xmlGenericError(xmlGenericErrorContext,
7938 "PathExpr: AbbrRelLocation\n");
7939#endif
7940 lc = 1;
7941 break;
7942 } else if (IS_BLANK(NXT(len))) {
7943 /* skip to next */
7944 blank = 1;
7945 } else if (NXT(len) == ':') {
7946#ifdef DEBUG_STEP
7947 xmlGenericError(xmlGenericErrorContext,
7948 "PathExpr: AbbrRelLocation\n");
7949#endif
7950 lc = 1;
7951 break;
7952 } else if ((NXT(len) == '(')) {
7953 /* Note Type or Function */
7954 if (xmlXPathIsNodeType(name)) {
7955#ifdef DEBUG_STEP
7956 xmlGenericError(xmlGenericErrorContext,
7957 "PathExpr: Type search\n");
7958#endif
7959 lc = 1;
7960 } else {
7961#ifdef DEBUG_STEP
7962 xmlGenericError(xmlGenericErrorContext,
7963 "PathExpr: function call\n");
7964#endif
7965 lc = 0;
7966 }
7967 break;
7968 } else if ((NXT(len) == '[')) {
7969 /* element name */
7970#ifdef DEBUG_STEP
7971 xmlGenericError(xmlGenericErrorContext,
7972 "PathExpr: AbbrRelLocation\n");
7973#endif
7974 lc = 1;
7975 break;
7976 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7977 (NXT(len) == '=')) {
7978 lc = 1;
7979 break;
7980 } else {
7981 lc = 1;
7982 break;
7983 }
7984 len++;
7985 }
7986 if (NXT(len) == 0) {
7987#ifdef DEBUG_STEP
7988 xmlGenericError(xmlGenericErrorContext,
7989 "PathExpr: AbbrRelLocation\n");
7990#endif
7991 /* element name */
7992 lc = 1;
7993 }
7994 xmlFree(name);
7995 } else {
7996 /* make sure all cases are covered explicitely */
7997 XP_ERROR(XPATH_EXPR_ERROR);
7998 }
7999 }
8000
8001 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008002 if (CUR == '/') {
8003 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8004 } else {
8005 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008006 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008007 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008008 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008009 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008010 CHECK_ERROR;
8011 if ((CUR == '/') && (NXT(1) == '/')) {
8012 SKIP(2);
8013 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008014
8015 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8016 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8017 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8018
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008019 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008020 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008021 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008022 }
8023 }
8024 SKIP_BLANKS;
8025}
8026
8027/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008028 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008029 * @ctxt: the XPath Parser context
8030 *
8031 * [18] UnionExpr ::= PathExpr
8032 * | UnionExpr '|' PathExpr
8033 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008034 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008035 */
8036
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008037static void
8038xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8039 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008040 CHECK_ERROR;
8041 SKIP_BLANKS;
8042 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008043 int op1 = ctxt->comp->last;
8044 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008045
8046 NEXT;
8047 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008048 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008049
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008050 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8051
Owen Taylor3473f882001-02-23 17:55:21 +00008052 SKIP_BLANKS;
8053 }
Owen Taylor3473f882001-02-23 17:55:21 +00008054}
8055
8056/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008057 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008058 * @ctxt: the XPath Parser context
8059 *
8060 * [27] UnaryExpr ::= UnionExpr
8061 * | '-' UnaryExpr
8062 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008063 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008064 */
8065
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008066static void
8067xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008068 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008069 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008070
8071 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008072 while (CUR == '-') {
8073 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008074 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008075 NEXT;
8076 SKIP_BLANKS;
8077 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008078
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008079 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008080 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008081 if (found) {
8082 if (minus)
8083 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8084 else
8085 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008086 }
8087}
8088
8089/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008090 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008091 * @ctxt: the XPath Parser context
8092 *
8093 * [26] MultiplicativeExpr ::= UnaryExpr
8094 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8095 * | MultiplicativeExpr 'div' UnaryExpr
8096 * | MultiplicativeExpr 'mod' UnaryExpr
8097 * [34] MultiplyOperator ::= '*'
8098 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008099 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008100 */
8101
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008102static void
8103xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8104 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008105 CHECK_ERROR;
8106 SKIP_BLANKS;
8107 while ((CUR == '*') ||
8108 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8109 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8110 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008111 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008112
8113 if (CUR == '*') {
8114 op = 0;
8115 NEXT;
8116 } else if (CUR == 'd') {
8117 op = 1;
8118 SKIP(3);
8119 } else if (CUR == 'm') {
8120 op = 2;
8121 SKIP(3);
8122 }
8123 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008124 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008125 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008126 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008127 SKIP_BLANKS;
8128 }
8129}
8130
8131/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008132 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008133 * @ctxt: the XPath Parser context
8134 *
8135 * [25] AdditiveExpr ::= MultiplicativeExpr
8136 * | AdditiveExpr '+' MultiplicativeExpr
8137 * | AdditiveExpr '-' MultiplicativeExpr
8138 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008139 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008140 */
8141
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008142static void
8143xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008144
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008145 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008146 CHECK_ERROR;
8147 SKIP_BLANKS;
8148 while ((CUR == '+') || (CUR == '-')) {
8149 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008150 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008151
8152 if (CUR == '+') plus = 1;
8153 else plus = 0;
8154 NEXT;
8155 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008156 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008157 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008158 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008159 SKIP_BLANKS;
8160 }
8161}
8162
8163/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008164 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008165 * @ctxt: the XPath Parser context
8166 *
8167 * [24] RelationalExpr ::= AdditiveExpr
8168 * | RelationalExpr '<' AdditiveExpr
8169 * | RelationalExpr '>' AdditiveExpr
8170 * | RelationalExpr '<=' AdditiveExpr
8171 * | RelationalExpr '>=' AdditiveExpr
8172 *
8173 * A <= B > C is allowed ? Answer from James, yes with
8174 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8175 * which is basically what got implemented.
8176 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008177 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008178 * on the stack
8179 */
8180
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008181static void
8182xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8183 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008184 CHECK_ERROR;
8185 SKIP_BLANKS;
8186 while ((CUR == '<') ||
8187 (CUR == '>') ||
8188 ((CUR == '<') && (NXT(1) == '=')) ||
8189 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008190 int inf, strict;
8191 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008192
8193 if (CUR == '<') inf = 1;
8194 else inf = 0;
8195 if (NXT(1) == '=') strict = 0;
8196 else strict = 1;
8197 NEXT;
8198 if (!strict) NEXT;
8199 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008200 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008201 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008202 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008203 SKIP_BLANKS;
8204 }
8205}
8206
8207/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008208 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008209 * @ctxt: the XPath Parser context
8210 *
8211 * [23] EqualityExpr ::= RelationalExpr
8212 * | EqualityExpr '=' RelationalExpr
8213 * | EqualityExpr '!=' RelationalExpr
8214 *
8215 * A != B != C is allowed ? Answer from James, yes with
8216 * (RelationalExpr = RelationalExpr) = RelationalExpr
8217 * (RelationalExpr != RelationalExpr) != RelationalExpr
8218 * which is basically what got implemented.
8219 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008220 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008221 *
8222 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008223static void
8224xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8225 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008226 CHECK_ERROR;
8227 SKIP_BLANKS;
8228 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008229 int eq;
8230 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008231
8232 if (CUR == '=') eq = 1;
8233 else eq = 0;
8234 NEXT;
8235 if (!eq) NEXT;
8236 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008237 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008238 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008239 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008240 SKIP_BLANKS;
8241 }
8242}
8243
8244/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008245 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008246 * @ctxt: the XPath Parser context
8247 *
8248 * [22] AndExpr ::= EqualityExpr
8249 * | AndExpr 'and' EqualityExpr
8250 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008251 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008252 *
8253 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008254static void
8255xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8256 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008257 CHECK_ERROR;
8258 SKIP_BLANKS;
8259 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008260 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008261 SKIP(3);
8262 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008263 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008264 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008265 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008266 SKIP_BLANKS;
8267 }
8268}
8269
8270/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008271 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008272 * @ctxt: the XPath Parser context
8273 *
8274 * [14] Expr ::= OrExpr
8275 * [21] OrExpr ::= AndExpr
8276 * | OrExpr 'or' AndExpr
8277 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008278 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008279 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008280static void
8281xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8282 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008283 CHECK_ERROR;
8284 SKIP_BLANKS;
8285 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008286 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008287 SKIP(2);
8288 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008289 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008290 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008291 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8292 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008293 SKIP_BLANKS;
8294 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008295 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8296 /* more ops could be optimized too */
8297 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8298 }
Owen Taylor3473f882001-02-23 17:55:21 +00008299}
8300
8301/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008302 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008303 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008304 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008305 *
8306 * [8] Predicate ::= '[' PredicateExpr ']'
8307 * [9] PredicateExpr ::= Expr
8308 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008309 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008310 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008311static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008312xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008313 int op1 = ctxt->comp->last;
8314
8315 SKIP_BLANKS;
8316 if (CUR != '[') {
8317 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8318 }
8319 NEXT;
8320 SKIP_BLANKS;
8321
8322 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008323 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008324 CHECK_ERROR;
8325
8326 if (CUR != ']') {
8327 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8328 }
8329
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008330 if (filter)
8331 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8332 else
8333 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008334
8335 NEXT;
8336 SKIP_BLANKS;
8337}
8338
8339/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008340 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008341 * @ctxt: the XPath Parser context
8342 * @test: pointer to a xmlXPathTestVal
8343 * @type: pointer to a xmlXPathTypeVal
8344 * @prefix: placeholder for a possible name prefix
8345 *
8346 * [7] NodeTest ::= NameTest
8347 * | NodeType '(' ')'
8348 * | 'processing-instruction' '(' Literal ')'
8349 *
8350 * [37] NameTest ::= '*'
8351 * | NCName ':' '*'
8352 * | QName
8353 * [38] NodeType ::= 'comment'
8354 * | 'text'
8355 * | 'processing-instruction'
8356 * | 'node'
8357 *
8358 * Returns the name found and update @test, @type and @prefix appropriately
8359 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008360static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008361xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8362 xmlXPathTypeVal *type, const xmlChar **prefix,
8363 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008364 int blanks;
8365
8366 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8367 STRANGE;
8368 return(NULL);
8369 }
8370 *type = 0;
8371 *test = 0;
8372 *prefix = NULL;
8373 SKIP_BLANKS;
8374
8375 if ((name == NULL) && (CUR == '*')) {
8376 /*
8377 * All elements
8378 */
8379 NEXT;
8380 *test = NODE_TEST_ALL;
8381 return(NULL);
8382 }
8383
8384 if (name == NULL)
8385 name = xmlXPathParseNCName(ctxt);
8386 if (name == NULL) {
8387 XP_ERROR0(XPATH_EXPR_ERROR);
8388 }
8389
8390 blanks = IS_BLANK(CUR);
8391 SKIP_BLANKS;
8392 if (CUR == '(') {
8393 NEXT;
8394 /*
8395 * NodeType or PI search
8396 */
8397 if (xmlStrEqual(name, BAD_CAST "comment"))
8398 *type = NODE_TYPE_COMMENT;
8399 else if (xmlStrEqual(name, BAD_CAST "node"))
8400 *type = NODE_TYPE_NODE;
8401 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8402 *type = NODE_TYPE_PI;
8403 else if (xmlStrEqual(name, BAD_CAST "text"))
8404 *type = NODE_TYPE_TEXT;
8405 else {
8406 if (name != NULL)
8407 xmlFree(name);
8408 XP_ERROR0(XPATH_EXPR_ERROR);
8409 }
8410
8411 *test = NODE_TEST_TYPE;
8412
8413 SKIP_BLANKS;
8414 if (*type == NODE_TYPE_PI) {
8415 /*
8416 * Specific case: search a PI by name.
8417 */
Owen Taylor3473f882001-02-23 17:55:21 +00008418 if (name != NULL)
8419 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008420 name = NULL;
8421 if (CUR != ')') {
8422 name = xmlXPathParseLiteral(ctxt);
8423 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008424 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008425 SKIP_BLANKS;
8426 }
Owen Taylor3473f882001-02-23 17:55:21 +00008427 }
8428 if (CUR != ')') {
8429 if (name != NULL)
8430 xmlFree(name);
8431 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8432 }
8433 NEXT;
8434 return(name);
8435 }
8436 *test = NODE_TEST_NAME;
8437 if ((!blanks) && (CUR == ':')) {
8438 NEXT;
8439
8440 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008441 * Since currently the parser context don't have a
8442 * namespace list associated:
8443 * The namespace name for this prefix can be computed
8444 * only at evaluation time. The compilation is done
8445 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008446 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008447#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008448 *prefix = xmlXPathNsLookup(ctxt->context, name);
8449 if (name != NULL)
8450 xmlFree(name);
8451 if (*prefix == NULL) {
8452 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8453 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008454#else
8455 *prefix = name;
8456#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008457
8458 if (CUR == '*') {
8459 /*
8460 * All elements
8461 */
8462 NEXT;
8463 *test = NODE_TEST_ALL;
8464 return(NULL);
8465 }
8466
8467 name = xmlXPathParseNCName(ctxt);
8468 if (name == NULL) {
8469 XP_ERROR0(XPATH_EXPR_ERROR);
8470 }
8471 }
8472 return(name);
8473}
8474
8475/**
8476 * xmlXPathIsAxisName:
8477 * @name: a preparsed name token
8478 *
8479 * [6] AxisName ::= 'ancestor'
8480 * | 'ancestor-or-self'
8481 * | 'attribute'
8482 * | 'child'
8483 * | 'descendant'
8484 * | 'descendant-or-self'
8485 * | 'following'
8486 * | 'following-sibling'
8487 * | 'namespace'
8488 * | 'parent'
8489 * | 'preceding'
8490 * | 'preceding-sibling'
8491 * | 'self'
8492 *
8493 * Returns the axis or 0
8494 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008495static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008496xmlXPathIsAxisName(const xmlChar *name) {
8497 xmlXPathAxisVal ret = 0;
8498 switch (name[0]) {
8499 case 'a':
8500 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8501 ret = AXIS_ANCESTOR;
8502 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8503 ret = AXIS_ANCESTOR_OR_SELF;
8504 if (xmlStrEqual(name, BAD_CAST "attribute"))
8505 ret = AXIS_ATTRIBUTE;
8506 break;
8507 case 'c':
8508 if (xmlStrEqual(name, BAD_CAST "child"))
8509 ret = AXIS_CHILD;
8510 break;
8511 case 'd':
8512 if (xmlStrEqual(name, BAD_CAST "descendant"))
8513 ret = AXIS_DESCENDANT;
8514 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8515 ret = AXIS_DESCENDANT_OR_SELF;
8516 break;
8517 case 'f':
8518 if (xmlStrEqual(name, BAD_CAST "following"))
8519 ret = AXIS_FOLLOWING;
8520 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8521 ret = AXIS_FOLLOWING_SIBLING;
8522 break;
8523 case 'n':
8524 if (xmlStrEqual(name, BAD_CAST "namespace"))
8525 ret = AXIS_NAMESPACE;
8526 break;
8527 case 'p':
8528 if (xmlStrEqual(name, BAD_CAST "parent"))
8529 ret = AXIS_PARENT;
8530 if (xmlStrEqual(name, BAD_CAST "preceding"))
8531 ret = AXIS_PRECEDING;
8532 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8533 ret = AXIS_PRECEDING_SIBLING;
8534 break;
8535 case 's':
8536 if (xmlStrEqual(name, BAD_CAST "self"))
8537 ret = AXIS_SELF;
8538 break;
8539 }
8540 return(ret);
8541}
8542
8543/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008544 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008545 * @ctxt: the XPath Parser context
8546 *
8547 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8548 * | AbbreviatedStep
8549 *
8550 * [12] AbbreviatedStep ::= '.' | '..'
8551 *
8552 * [5] AxisSpecifier ::= AxisName '::'
8553 * | AbbreviatedAxisSpecifier
8554 *
8555 * [13] AbbreviatedAxisSpecifier ::= '@'?
8556 *
8557 * Modified for XPtr range support as:
8558 *
8559 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8560 * | AbbreviatedStep
8561 * | 'range-to' '(' Expr ')' Predicate*
8562 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008563 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008564 * A location step of . is short for self::node(). This is
8565 * particularly useful in conjunction with //. For example, the
8566 * location path .//para is short for
8567 * self::node()/descendant-or-self::node()/child::para
8568 * and so will select all para descendant elements of the context
8569 * node.
8570 * Similarly, a location step of .. is short for parent::node().
8571 * For example, ../title is short for parent::node()/child::title
8572 * and so will select the title children of the parent of the context
8573 * node.
8574 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008575static void
8576xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008577#ifdef LIBXML_XPTR_ENABLED
8578 int rangeto = 0;
8579 int op2 = -1;
8580#endif
8581
Owen Taylor3473f882001-02-23 17:55:21 +00008582 SKIP_BLANKS;
8583 if ((CUR == '.') && (NXT(1) == '.')) {
8584 SKIP(2);
8585 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008586 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8587 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008588 } else if (CUR == '.') {
8589 NEXT;
8590 SKIP_BLANKS;
8591 } else {
8592 xmlChar *name = NULL;
8593 const xmlChar *prefix = NULL;
8594 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008595 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008596 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008597 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008598
8599 /*
8600 * The modification needed for XPointer change to the production
8601 */
8602#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008603 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008604 name = xmlXPathParseNCName(ctxt);
8605 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008606 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008607 xmlFree(name);
8608 SKIP_BLANKS;
8609 if (CUR != '(') {
8610 XP_ERROR(XPATH_EXPR_ERROR);
8611 }
8612 NEXT;
8613 SKIP_BLANKS;
8614
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008615 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008616 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008617 CHECK_ERROR;
8618
8619 SKIP_BLANKS;
8620 if (CUR != ')') {
8621 XP_ERROR(XPATH_EXPR_ERROR);
8622 }
8623 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008624 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008625 goto eval_predicates;
8626 }
8627 }
8628#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008629 if (CUR == '*') {
8630 axis = AXIS_CHILD;
8631 } else {
8632 if (name == NULL)
8633 name = xmlXPathParseNCName(ctxt);
8634 if (name != NULL) {
8635 axis = xmlXPathIsAxisName(name);
8636 if (axis != 0) {
8637 SKIP_BLANKS;
8638 if ((CUR == ':') && (NXT(1) == ':')) {
8639 SKIP(2);
8640 xmlFree(name);
8641 name = NULL;
8642 } else {
8643 /* an element name can conflict with an axis one :-\ */
8644 axis = AXIS_CHILD;
8645 }
Owen Taylor3473f882001-02-23 17:55:21 +00008646 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008647 axis = AXIS_CHILD;
8648 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008649 } else if (CUR == '@') {
8650 NEXT;
8651 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008652 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008653 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008654 }
Owen Taylor3473f882001-02-23 17:55:21 +00008655 }
8656
8657 CHECK_ERROR;
8658
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008659 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008660 if (test == 0)
8661 return;
8662
8663#ifdef DEBUG_STEP
8664 xmlGenericError(xmlGenericErrorContext,
8665 "Basis : computing new set\n");
8666#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008667
Owen Taylor3473f882001-02-23 17:55:21 +00008668#ifdef DEBUG_STEP
8669 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008670 if (ctxt->value == NULL)
8671 xmlGenericError(xmlGenericErrorContext, "no value\n");
8672 else if (ctxt->value->nodesetval == NULL)
8673 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8674 else
8675 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008676#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008677
8678eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008679 op1 = ctxt->comp->last;
8680 ctxt->comp->last = -1;
8681
Owen Taylor3473f882001-02-23 17:55:21 +00008682 SKIP_BLANKS;
8683 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008684 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008685 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008686
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008687#ifdef LIBXML_XPTR_ENABLED
8688 if (rangeto) {
8689 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8690 } else
8691#endif
8692 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8693 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008694
Owen Taylor3473f882001-02-23 17:55:21 +00008695 }
8696#ifdef DEBUG_STEP
8697 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008698 if (ctxt->value == NULL)
8699 xmlGenericError(xmlGenericErrorContext, "no value\n");
8700 else if (ctxt->value->nodesetval == NULL)
8701 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8702 else
8703 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8704 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008705#endif
8706}
8707
8708/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008709 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008710 * @ctxt: the XPath Parser context
8711 *
8712 * [3] RelativeLocationPath ::= Step
8713 * | RelativeLocationPath '/' Step
8714 * | AbbreviatedRelativeLocationPath
8715 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8716 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008717 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008718 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008719static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008720xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008721(xmlXPathParserContextPtr ctxt) {
8722 SKIP_BLANKS;
8723 if ((CUR == '/') && (NXT(1) == '/')) {
8724 SKIP(2);
8725 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008726 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8727 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008728 } else if (CUR == '/') {
8729 NEXT;
8730 SKIP_BLANKS;
8731 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008732 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008733 SKIP_BLANKS;
8734 while (CUR == '/') {
8735 if ((CUR == '/') && (NXT(1) == '/')) {
8736 SKIP(2);
8737 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008738 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008739 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008740 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008741 } else if (CUR == '/') {
8742 NEXT;
8743 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008744 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008745 }
8746 SKIP_BLANKS;
8747 }
8748}
8749
8750/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008751 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008752 * @ctxt: the XPath Parser context
8753 *
8754 * [1] LocationPath ::= RelativeLocationPath
8755 * | AbsoluteLocationPath
8756 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8757 * | AbbreviatedAbsoluteLocationPath
8758 * [10] AbbreviatedAbsoluteLocationPath ::=
8759 * '//' RelativeLocationPath
8760 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008761 * Compile a location path
8762 *
Owen Taylor3473f882001-02-23 17:55:21 +00008763 * // is short for /descendant-or-self::node()/. For example,
8764 * //para is short for /descendant-or-self::node()/child::para and
8765 * so will select any para element in the document (even a para element
8766 * that is a document element will be selected by //para since the
8767 * document element node is a child of the root node); div//para is
8768 * short for div/descendant-or-self::node()/child::para and so will
8769 * select all para descendants of div children.
8770 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008771static void
8772xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008773 SKIP_BLANKS;
8774 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008775 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008776 } else {
8777 while (CUR == '/') {
8778 if ((CUR == '/') && (NXT(1) == '/')) {
8779 SKIP(2);
8780 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008781 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8782 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008783 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008784 } else if (CUR == '/') {
8785 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008786 SKIP_BLANKS;
8787 if ((CUR != 0 ) &&
8788 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8789 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008790 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008791 }
8792 }
8793 }
8794}
8795
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008796/************************************************************************
8797 * *
8798 * XPath precompiled expression evaluation *
8799 * *
8800 ************************************************************************/
8801
Daniel Veillardf06307e2001-07-03 10:35:50 +00008802static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008803xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8804
8805/**
8806 * xmlXPathNodeCollectAndTest:
8807 * @ctxt: the XPath Parser context
8808 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008809 * @first: pointer to the first element in document order
8810 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008811 *
8812 * This is the function implementing a step: based on the current list
8813 * of nodes, it builds up a new list, looking at all nodes under that
8814 * axis and selecting them it also do the predicate filtering
8815 *
8816 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008817 *
8818 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008819 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008820static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008821xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008822 xmlXPathStepOpPtr op,
8823 xmlNodePtr * first, xmlNodePtr * last)
8824{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008825 xmlXPathAxisVal axis = op->value;
8826 xmlXPathTestVal test = op->value2;
8827 xmlXPathTypeVal type = op->value3;
8828 const xmlChar *prefix = op->value4;
8829 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008830 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008831
8832#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008833 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008834#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008835 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008836 xmlNodeSetPtr ret, list;
8837 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008838 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008839 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008840 xmlNodePtr cur = NULL;
8841 xmlXPathObjectPtr obj;
8842 xmlNodeSetPtr nodelist;
8843 xmlNodePtr tmp;
8844
Daniel Veillardf06307e2001-07-03 10:35:50 +00008845 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008846 obj = valuePop(ctxt);
8847 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008848 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008849 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008850 URI = xmlXPathNsLookup(ctxt->context, prefix);
8851 if (URI == NULL)
8852 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008853 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008854#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008855 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008856#endif
8857 switch (axis) {
8858 case AXIS_ANCESTOR:
8859#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008860 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008861#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008862 first = NULL;
8863 next = xmlXPathNextAncestor;
8864 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008865 case AXIS_ANCESTOR_OR_SELF:
8866#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008867 xmlGenericError(xmlGenericErrorContext,
8868 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008869#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008870 first = NULL;
8871 next = xmlXPathNextAncestorOrSelf;
8872 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008873 case AXIS_ATTRIBUTE:
8874#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008876#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008877 first = NULL;
8878 last = NULL;
8879 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008880 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008881 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008882 case AXIS_CHILD:
8883#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008884 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008885#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008886 last = NULL;
8887 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008888 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008890 case AXIS_DESCENDANT:
8891#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008892 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008893#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008894 last = NULL;
8895 next = xmlXPathNextDescendant;
8896 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008897 case AXIS_DESCENDANT_OR_SELF:
8898#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899 xmlGenericError(xmlGenericErrorContext,
8900 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008901#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 last = NULL;
8903 next = xmlXPathNextDescendantOrSelf;
8904 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008905 case AXIS_FOLLOWING:
8906#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008907 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008908#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008909 last = NULL;
8910 next = xmlXPathNextFollowing;
8911 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008912 case AXIS_FOLLOWING_SIBLING:
8913#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008914 xmlGenericError(xmlGenericErrorContext,
8915 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008916#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 last = NULL;
8918 next = xmlXPathNextFollowingSibling;
8919 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008920 case AXIS_NAMESPACE:
8921#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008922 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008924 first = NULL;
8925 last = NULL;
8926 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008927 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008928 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008929 case AXIS_PARENT:
8930#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008931 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008932#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008933 first = NULL;
8934 next = xmlXPathNextParent;
8935 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008936 case AXIS_PRECEDING:
8937#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008940 first = NULL;
8941 next = xmlXPathNextPrecedingInternal;
8942 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008943 case AXIS_PRECEDING_SIBLING:
8944#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008945 xmlGenericError(xmlGenericErrorContext,
8946 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008947#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948 first = NULL;
8949 next = xmlXPathNextPrecedingSibling;
8950 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008951 case AXIS_SELF:
8952#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008954#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 first = NULL;
8956 last = NULL;
8957 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008958 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008959 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008960 }
8961 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008962 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008963
8964 nodelist = obj->nodesetval;
8965 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008966 xmlXPathFreeObject(obj);
8967 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8968 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008969 }
8970 addNode = xmlXPathNodeSetAddUnique;
8971 ret = NULL;
8972#ifdef DEBUG_STEP
8973 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 case NODE_TEST_NONE:
8977 xmlGenericError(xmlGenericErrorContext,
8978 " searching for none !!!\n");
8979 break;
8980 case NODE_TEST_TYPE:
8981 xmlGenericError(xmlGenericErrorContext,
8982 " searching for type %d\n", type);
8983 break;
8984 case NODE_TEST_PI:
8985 xmlGenericError(xmlGenericErrorContext,
8986 " searching for PI !!!\n");
8987 break;
8988 case NODE_TEST_ALL:
8989 xmlGenericError(xmlGenericErrorContext,
8990 " searching for *\n");
8991 break;
8992 case NODE_TEST_NS:
8993 xmlGenericError(xmlGenericErrorContext,
8994 " searching for namespace %s\n",
8995 prefix);
8996 break;
8997 case NODE_TEST_NAME:
8998 xmlGenericError(xmlGenericErrorContext,
8999 " searching for name %s\n", name);
9000 if (prefix != NULL)
9001 xmlGenericError(xmlGenericErrorContext,
9002 " with namespace %s\n", prefix);
9003 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009004 }
9005 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9006#endif
9007 /*
9008 * 2.3 Node Tests
9009 * - For the attribute axis, the principal node type is attribute.
9010 * - For the namespace axis, the principal node type is namespace.
9011 * - For other axes, the principal node type is element.
9012 *
9013 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009014 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009015 * select all element children of the context node
9016 */
9017 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009018 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009019 ctxt->context->node = nodelist->nodeTab[i];
9020
Daniel Veillardf06307e2001-07-03 10:35:50 +00009021 cur = NULL;
9022 list = xmlXPathNodeSetCreate(NULL);
9023 do {
9024 cur = next(ctxt, cur);
9025 if (cur == NULL)
9026 break;
9027 if ((first != NULL) && (*first == cur))
9028 break;
9029 if (((t % 256) == 0) &&
9030 (first != NULL) && (*first != NULL) &&
9031 (xmlXPathCmpNodes(*first, cur) >= 0))
9032 break;
9033 if ((last != NULL) && (*last == cur))
9034 break;
9035 if (((t % 256) == 0) &&
9036 (last != NULL) && (*last != NULL) &&
9037 (xmlXPathCmpNodes(cur, *last) >= 0))
9038 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009039 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009040#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009041 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9042#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009043 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009044 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009045 ctxt->context->node = tmp;
9046 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009047 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009048 if ((cur->type == type) ||
9049 ((type == NODE_TYPE_NODE) &&
9050 ((cur->type == XML_DOCUMENT_NODE) ||
9051 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9052 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009053 (cur->type == XML_NAMESPACE_DECL) ||
9054 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055 (cur->type == XML_PI_NODE) ||
9056 (cur->type == XML_COMMENT_NODE) ||
9057 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009058 (cur->type == XML_TEXT_NODE))) ||
9059 ((type == NODE_TYPE_TEXT) &&
9060 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009061#ifdef DEBUG_STEP
9062 n++;
9063#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 addNode(list, cur);
9065 }
9066 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009067 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009068 if (cur->type == XML_PI_NODE) {
9069 if ((name != NULL) &&
9070 (!xmlStrEqual(name, cur->name)))
9071 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009072#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009073 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009074#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009075 addNode(list, cur);
9076 }
9077 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009078 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 if (axis == AXIS_ATTRIBUTE) {
9080 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009081#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009083#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 addNode(list, cur);
9085 }
9086 } else if (axis == AXIS_NAMESPACE) {
9087 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009088#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009090#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009091 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9092 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009093 }
9094 } else {
9095 if (cur->type == XML_ELEMENT_NODE) {
9096 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009097#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009099#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 addNode(list, cur);
9101 } else if ((cur->ns != NULL) &&
9102 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009103#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009104 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009105#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106 addNode(list, cur);
9107 }
9108 }
9109 }
9110 break;
9111 case NODE_TEST_NS:{
9112 TODO;
9113 break;
9114 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009115 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009116 switch (cur->type) {
9117 case XML_ELEMENT_NODE:
9118 if (xmlStrEqual(name, cur->name)) {
9119 if (prefix == NULL) {
9120 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009121#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009122 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009123#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009124 addNode(list, cur);
9125 }
9126 } else {
9127 if ((cur->ns != NULL) &&
9128 (xmlStrEqual(URI,
9129 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009130#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009132#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009133 addNode(list, cur);
9134 }
9135 }
9136 }
9137 break;
9138 case XML_ATTRIBUTE_NODE:{
9139 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009140
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 if (xmlStrEqual(name, attr->name)) {
9142 if (prefix == NULL) {
9143 if ((attr->ns == NULL) ||
9144 (attr->ns->prefix == NULL)) {
9145#ifdef DEBUG_STEP
9146 n++;
9147#endif
9148 addNode(list,
9149 (xmlNodePtr) attr);
9150 }
9151 } else {
9152 if ((attr->ns != NULL) &&
9153 (xmlStrEqual(URI,
9154 attr->ns->
9155 href))) {
9156#ifdef DEBUG_STEP
9157 n++;
9158#endif
9159 addNode(list,
9160 (xmlNodePtr) attr);
9161 }
9162 }
9163 }
9164 break;
9165 }
9166 case XML_NAMESPACE_DECL:
9167 if (cur->type == XML_NAMESPACE_DECL) {
9168 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009169
Daniel Veillardf06307e2001-07-03 10:35:50 +00009170 if ((ns->prefix != NULL) && (name != NULL)
9171 && (xmlStrEqual(ns->prefix, name))) {
9172#ifdef DEBUG_STEP
9173 n++;
9174#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009175 xmlXPathNodeSetAddNs(list,
9176 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009177 }
9178 }
9179 break;
9180 default:
9181 break;
9182 }
9183 break;
9184 break;
9185 }
9186 } while (cur != NULL);
9187
9188 /*
9189 * If there is some predicate filtering do it now
9190 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009191 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009192 xmlXPathObjectPtr obj2;
9193
9194 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9195 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9196 CHECK_TYPE0(XPATH_NODESET);
9197 obj2 = valuePop(ctxt);
9198 list = obj2->nodesetval;
9199 obj2->nodesetval = NULL;
9200 xmlXPathFreeObject(obj2);
9201 }
9202 if (ret == NULL) {
9203 ret = list;
9204 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009205 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009206 xmlXPathFreeNodeSet(list);
9207 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009208 }
9209 ctxt->context->node = tmp;
9210#ifdef DEBUG_STEP
9211 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009212 "\nExamined %d nodes, found %d nodes at that step\n",
9213 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009214#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009215 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009216 if ((obj->boolval) && (obj->user != NULL)) {
9217 ctxt->value->boolval = 1;
9218 ctxt->value->user = obj->user;
9219 obj->user = NULL;
9220 obj->boolval = 0;
9221 }
9222 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009223 return(t);
9224}
9225
9226/**
9227 * xmlXPathNodeCollectAndTestNth:
9228 * @ctxt: the XPath Parser context
9229 * @op: the XPath precompiled step operation
9230 * @indx: the index to collect
9231 * @first: pointer to the first element in document order
9232 * @last: pointer to the last element in document order
9233 *
9234 * This is the function implementing a step: based on the current list
9235 * of nodes, it builds up a new list, looking at all nodes under that
9236 * axis and selecting them it also do the predicate filtering
9237 *
9238 * Pushes the new NodeSet resulting from the search.
9239 * Returns the number of node traversed
9240 */
9241static int
9242xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9243 xmlXPathStepOpPtr op, int indx,
9244 xmlNodePtr * first, xmlNodePtr * last)
9245{
9246 xmlXPathAxisVal axis = op->value;
9247 xmlXPathTestVal test = op->value2;
9248 xmlXPathTypeVal type = op->value3;
9249 const xmlChar *prefix = op->value4;
9250 const xmlChar *name = op->value5;
9251 const xmlChar *URI = NULL;
9252 int n = 0, t = 0;
9253
9254 int i;
9255 xmlNodeSetPtr list;
9256 xmlXPathTraversalFunction next = NULL;
9257 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9258 xmlNodePtr cur = NULL;
9259 xmlXPathObjectPtr obj;
9260 xmlNodeSetPtr nodelist;
9261 xmlNodePtr tmp;
9262
9263 CHECK_TYPE0(XPATH_NODESET);
9264 obj = valuePop(ctxt);
9265 addNode = xmlXPathNodeSetAdd;
9266 if (prefix != NULL) {
9267 URI = xmlXPathNsLookup(ctxt->context, prefix);
9268 if (URI == NULL)
9269 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9270 }
9271#ifdef DEBUG_STEP_NTH
9272 xmlGenericError(xmlGenericErrorContext, "new step : ");
9273 if (first != NULL) {
9274 if (*first != NULL)
9275 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9276 (*first)->name);
9277 else
9278 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9279 }
9280 if (last != NULL) {
9281 if (*last != NULL)
9282 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9283 (*last)->name);
9284 else
9285 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9286 }
9287#endif
9288 switch (axis) {
9289 case AXIS_ANCESTOR:
9290#ifdef DEBUG_STEP_NTH
9291 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9292#endif
9293 first = NULL;
9294 next = xmlXPathNextAncestor;
9295 break;
9296 case AXIS_ANCESTOR_OR_SELF:
9297#ifdef DEBUG_STEP_NTH
9298 xmlGenericError(xmlGenericErrorContext,
9299 "axis 'ancestors-or-self' ");
9300#endif
9301 first = NULL;
9302 next = xmlXPathNextAncestorOrSelf;
9303 break;
9304 case AXIS_ATTRIBUTE:
9305#ifdef DEBUG_STEP_NTH
9306 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9307#endif
9308 first = NULL;
9309 last = NULL;
9310 next = xmlXPathNextAttribute;
9311 break;
9312 case AXIS_CHILD:
9313#ifdef DEBUG_STEP_NTH
9314 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9315#endif
9316 last = NULL;
9317 next = xmlXPathNextChild;
9318 break;
9319 case AXIS_DESCENDANT:
9320#ifdef DEBUG_STEP_NTH
9321 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9322#endif
9323 last = NULL;
9324 next = xmlXPathNextDescendant;
9325 break;
9326 case AXIS_DESCENDANT_OR_SELF:
9327#ifdef DEBUG_STEP_NTH
9328 xmlGenericError(xmlGenericErrorContext,
9329 "axis 'descendant-or-self' ");
9330#endif
9331 last = NULL;
9332 next = xmlXPathNextDescendantOrSelf;
9333 break;
9334 case AXIS_FOLLOWING:
9335#ifdef DEBUG_STEP_NTH
9336 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9337#endif
9338 last = NULL;
9339 next = xmlXPathNextFollowing;
9340 break;
9341 case AXIS_FOLLOWING_SIBLING:
9342#ifdef DEBUG_STEP_NTH
9343 xmlGenericError(xmlGenericErrorContext,
9344 "axis 'following-siblings' ");
9345#endif
9346 last = NULL;
9347 next = xmlXPathNextFollowingSibling;
9348 break;
9349 case AXIS_NAMESPACE:
9350#ifdef DEBUG_STEP_NTH
9351 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9352#endif
9353 last = NULL;
9354 first = NULL;
9355 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9356 break;
9357 case AXIS_PARENT:
9358#ifdef DEBUG_STEP_NTH
9359 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9360#endif
9361 first = NULL;
9362 next = xmlXPathNextParent;
9363 break;
9364 case AXIS_PRECEDING:
9365#ifdef DEBUG_STEP_NTH
9366 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9367#endif
9368 first = NULL;
9369 next = xmlXPathNextPrecedingInternal;
9370 break;
9371 case AXIS_PRECEDING_SIBLING:
9372#ifdef DEBUG_STEP_NTH
9373 xmlGenericError(xmlGenericErrorContext,
9374 "axis 'preceding-sibling' ");
9375#endif
9376 first = NULL;
9377 next = xmlXPathNextPrecedingSibling;
9378 break;
9379 case AXIS_SELF:
9380#ifdef DEBUG_STEP_NTH
9381 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9382#endif
9383 first = NULL;
9384 last = NULL;
9385 next = xmlXPathNextSelf;
9386 break;
9387 }
9388 if (next == NULL)
9389 return(0);
9390
9391 nodelist = obj->nodesetval;
9392 if (nodelist == NULL) {
9393 xmlXPathFreeObject(obj);
9394 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9395 return(0);
9396 }
9397 addNode = xmlXPathNodeSetAddUnique;
9398#ifdef DEBUG_STEP_NTH
9399 xmlGenericError(xmlGenericErrorContext,
9400 " context contains %d nodes\n", nodelist->nodeNr);
9401 switch (test) {
9402 case NODE_TEST_NONE:
9403 xmlGenericError(xmlGenericErrorContext,
9404 " searching for none !!!\n");
9405 break;
9406 case NODE_TEST_TYPE:
9407 xmlGenericError(xmlGenericErrorContext,
9408 " searching for type %d\n", type);
9409 break;
9410 case NODE_TEST_PI:
9411 xmlGenericError(xmlGenericErrorContext,
9412 " searching for PI !!!\n");
9413 break;
9414 case NODE_TEST_ALL:
9415 xmlGenericError(xmlGenericErrorContext,
9416 " searching for *\n");
9417 break;
9418 case NODE_TEST_NS:
9419 xmlGenericError(xmlGenericErrorContext,
9420 " searching for namespace %s\n",
9421 prefix);
9422 break;
9423 case NODE_TEST_NAME:
9424 xmlGenericError(xmlGenericErrorContext,
9425 " searching for name %s\n", name);
9426 if (prefix != NULL)
9427 xmlGenericError(xmlGenericErrorContext,
9428 " with namespace %s\n", prefix);
9429 break;
9430 }
9431 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9432#endif
9433 /*
9434 * 2.3 Node Tests
9435 * - For the attribute axis, the principal node type is attribute.
9436 * - For the namespace axis, the principal node type is namespace.
9437 * - For other axes, the principal node type is element.
9438 *
9439 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009440 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009441 * select all element children of the context node
9442 */
9443 tmp = ctxt->context->node;
9444 list = xmlXPathNodeSetCreate(NULL);
9445 for (i = 0; i < nodelist->nodeNr; i++) {
9446 ctxt->context->node = nodelist->nodeTab[i];
9447
9448 cur = NULL;
9449 n = 0;
9450 do {
9451 cur = next(ctxt, cur);
9452 if (cur == NULL)
9453 break;
9454 if ((first != NULL) && (*first == cur))
9455 break;
9456 if (((t % 256) == 0) &&
9457 (first != NULL) && (*first != NULL) &&
9458 (xmlXPathCmpNodes(*first, cur) >= 0))
9459 break;
9460 if ((last != NULL) && (*last == cur))
9461 break;
9462 if (((t % 256) == 0) &&
9463 (last != NULL) && (*last != NULL) &&
9464 (xmlXPathCmpNodes(cur, *last) >= 0))
9465 break;
9466 t++;
9467 switch (test) {
9468 case NODE_TEST_NONE:
9469 ctxt->context->node = tmp;
9470 STRANGE return(0);
9471 case NODE_TEST_TYPE:
9472 if ((cur->type == type) ||
9473 ((type == NODE_TYPE_NODE) &&
9474 ((cur->type == XML_DOCUMENT_NODE) ||
9475 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9476 (cur->type == XML_ELEMENT_NODE) ||
9477 (cur->type == XML_PI_NODE) ||
9478 (cur->type == XML_COMMENT_NODE) ||
9479 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009480 (cur->type == XML_TEXT_NODE))) ||
9481 ((type == NODE_TYPE_TEXT) &&
9482 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009483 n++;
9484 if (n == indx)
9485 addNode(list, cur);
9486 }
9487 break;
9488 case NODE_TEST_PI:
9489 if (cur->type == XML_PI_NODE) {
9490 if ((name != NULL) &&
9491 (!xmlStrEqual(name, cur->name)))
9492 break;
9493 n++;
9494 if (n == indx)
9495 addNode(list, cur);
9496 }
9497 break;
9498 case NODE_TEST_ALL:
9499 if (axis == AXIS_ATTRIBUTE) {
9500 if (cur->type == XML_ATTRIBUTE_NODE) {
9501 n++;
9502 if (n == indx)
9503 addNode(list, cur);
9504 }
9505 } else if (axis == AXIS_NAMESPACE) {
9506 if (cur->type == XML_NAMESPACE_DECL) {
9507 n++;
9508 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009509 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9510 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009511 }
9512 } else {
9513 if (cur->type == XML_ELEMENT_NODE) {
9514 if (prefix == NULL) {
9515 n++;
9516 if (n == indx)
9517 addNode(list, cur);
9518 } else if ((cur->ns != NULL) &&
9519 (xmlStrEqual(URI, cur->ns->href))) {
9520 n++;
9521 if (n == indx)
9522 addNode(list, cur);
9523 }
9524 }
9525 }
9526 break;
9527 case NODE_TEST_NS:{
9528 TODO;
9529 break;
9530 }
9531 case NODE_TEST_NAME:
9532 switch (cur->type) {
9533 case XML_ELEMENT_NODE:
9534 if (xmlStrEqual(name, cur->name)) {
9535 if (prefix == NULL) {
9536 if (cur->ns == NULL) {
9537 n++;
9538 if (n == indx)
9539 addNode(list, cur);
9540 }
9541 } else {
9542 if ((cur->ns != NULL) &&
9543 (xmlStrEqual(URI,
9544 cur->ns->href))) {
9545 n++;
9546 if (n == indx)
9547 addNode(list, cur);
9548 }
9549 }
9550 }
9551 break;
9552 case XML_ATTRIBUTE_NODE:{
9553 xmlAttrPtr attr = (xmlAttrPtr) cur;
9554
9555 if (xmlStrEqual(name, attr->name)) {
9556 if (prefix == NULL) {
9557 if ((attr->ns == NULL) ||
9558 (attr->ns->prefix == NULL)) {
9559 n++;
9560 if (n == indx)
9561 addNode(list, cur);
9562 }
9563 } else {
9564 if ((attr->ns != NULL) &&
9565 (xmlStrEqual(URI,
9566 attr->ns->
9567 href))) {
9568 n++;
9569 if (n == indx)
9570 addNode(list, cur);
9571 }
9572 }
9573 }
9574 break;
9575 }
9576 case XML_NAMESPACE_DECL:
9577 if (cur->type == XML_NAMESPACE_DECL) {
9578 xmlNsPtr ns = (xmlNsPtr) cur;
9579
9580 if ((ns->prefix != NULL) && (name != NULL)
9581 && (xmlStrEqual(ns->prefix, name))) {
9582 n++;
9583 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009584 xmlXPathNodeSetAddNs(list,
9585 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009586 }
9587 }
9588 break;
9589 default:
9590 break;
9591 }
9592 break;
9593 break;
9594 }
9595 } while (n < indx);
9596 }
9597 ctxt->context->node = tmp;
9598#ifdef DEBUG_STEP_NTH
9599 xmlGenericError(xmlGenericErrorContext,
9600 "\nExamined %d nodes, found %d nodes at that step\n",
9601 t, list->nodeNr);
9602#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009603 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009604 if ((obj->boolval) && (obj->user != NULL)) {
9605 ctxt->value->boolval = 1;
9606 ctxt->value->user = obj->user;
9607 obj->user = NULL;
9608 obj->boolval = 0;
9609 }
9610 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009611 return(t);
9612}
9613
9614/**
9615 * xmlXPathCompOpEvalFirst:
9616 * @ctxt: the XPath parser context with the compiled expression
9617 * @op: an XPath compiled operation
9618 * @first: the first elem found so far
9619 *
9620 * Evaluate the Precompiled XPath operation searching only the first
9621 * element in document order
9622 *
9623 * Returns the number of examined objects.
9624 */
9625static int
9626xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9627 xmlXPathStepOpPtr op, xmlNodePtr * first)
9628{
9629 int total = 0, cur;
9630 xmlXPathCompExprPtr comp;
9631 xmlXPathObjectPtr arg1, arg2;
9632
Daniel Veillard556c6682001-10-06 09:59:51 +00009633 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009634 comp = ctxt->comp;
9635 switch (op->op) {
9636 case XPATH_OP_END:
9637 return (0);
9638 case XPATH_OP_UNION:
9639 total =
9640 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9641 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009642 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009643 if ((ctxt->value != NULL)
9644 && (ctxt->value->type == XPATH_NODESET)
9645 && (ctxt->value->nodesetval != NULL)
9646 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9647 /*
9648 * limit tree traversing to first node in the result
9649 */
9650 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9651 *first = ctxt->value->nodesetval->nodeTab[0];
9652 }
9653 cur =
9654 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9655 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009656 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009657 CHECK_TYPE0(XPATH_NODESET);
9658 arg2 = valuePop(ctxt);
9659
9660 CHECK_TYPE0(XPATH_NODESET);
9661 arg1 = valuePop(ctxt);
9662
9663 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9664 arg2->nodesetval);
9665 valuePush(ctxt, arg1);
9666 xmlXPathFreeObject(arg2);
9667 /* optimizer */
9668 if (total > cur)
9669 xmlXPathCompSwap(op);
9670 return (total + cur);
9671 case XPATH_OP_ROOT:
9672 xmlXPathRoot(ctxt);
9673 return (0);
9674 case XPATH_OP_NODE:
9675 if (op->ch1 != -1)
9676 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009677 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009678 if (op->ch2 != -1)
9679 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009680 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009681 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9682 return (total);
9683 case XPATH_OP_RESET:
9684 if (op->ch1 != -1)
9685 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009686 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009687 if (op->ch2 != -1)
9688 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009689 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009690 ctxt->context->node = NULL;
9691 return (total);
9692 case XPATH_OP_COLLECT:{
9693 if (op->ch1 == -1)
9694 return (total);
9695
9696 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009697 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009698
9699 /*
9700 * Optimization for [n] selection where n is a number
9701 */
9702 if ((op->ch2 != -1) &&
9703 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9704 (comp->steps[op->ch2].ch1 == -1) &&
9705 (comp->steps[op->ch2].ch2 != -1) &&
9706 (comp->steps[comp->steps[op->ch2].ch2].op ==
9707 XPATH_OP_VALUE)) {
9708 xmlXPathObjectPtr val;
9709
9710 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9711 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9712 int indx = (int) val->floatval;
9713
9714 if (val->floatval == (float) indx) {
9715 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9716 first, NULL);
9717 return (total);
9718 }
9719 }
9720 }
9721 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9722 return (total);
9723 }
9724 case XPATH_OP_VALUE:
9725 valuePush(ctxt,
9726 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9727 return (0);
9728 case XPATH_OP_SORT:
9729 if (op->ch1 != -1)
9730 total +=
9731 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9732 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009733 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009734 if ((ctxt->value != NULL)
9735 && (ctxt->value->type == XPATH_NODESET)
9736 && (ctxt->value->nodesetval != NULL))
9737 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9738 return (total);
9739 default:
9740 return (xmlXPathCompOpEval(ctxt, op));
9741 }
9742}
9743
9744/**
9745 * xmlXPathCompOpEvalLast:
9746 * @ctxt: the XPath parser context with the compiled expression
9747 * @op: an XPath compiled operation
9748 * @last: the last elem found so far
9749 *
9750 * Evaluate the Precompiled XPath operation searching only the last
9751 * element in document order
9752 *
9753 * Returns the number of node traversed
9754 */
9755static int
9756xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9757 xmlNodePtr * last)
9758{
9759 int total = 0, cur;
9760 xmlXPathCompExprPtr comp;
9761 xmlXPathObjectPtr arg1, arg2;
9762
Daniel Veillard556c6682001-10-06 09:59:51 +00009763 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009764 comp = ctxt->comp;
9765 switch (op->op) {
9766 case XPATH_OP_END:
9767 return (0);
9768 case XPATH_OP_UNION:
9769 total =
9770 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009771 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009772 if ((ctxt->value != NULL)
9773 && (ctxt->value->type == XPATH_NODESET)
9774 && (ctxt->value->nodesetval != NULL)
9775 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9776 /*
9777 * limit tree traversing to first node in the result
9778 */
9779 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9780 *last =
9781 ctxt->value->nodesetval->nodeTab[ctxt->value->
9782 nodesetval->nodeNr -
9783 1];
9784 }
9785 cur =
9786 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009787 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009788 if ((ctxt->value != NULL)
9789 && (ctxt->value->type == XPATH_NODESET)
9790 && (ctxt->value->nodesetval != NULL)
9791 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9792 }
9793 CHECK_TYPE0(XPATH_NODESET);
9794 arg2 = valuePop(ctxt);
9795
9796 CHECK_TYPE0(XPATH_NODESET);
9797 arg1 = valuePop(ctxt);
9798
9799 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9800 arg2->nodesetval);
9801 valuePush(ctxt, arg1);
9802 xmlXPathFreeObject(arg2);
9803 /* optimizer */
9804 if (total > cur)
9805 xmlXPathCompSwap(op);
9806 return (total + cur);
9807 case XPATH_OP_ROOT:
9808 xmlXPathRoot(ctxt);
9809 return (0);
9810 case XPATH_OP_NODE:
9811 if (op->ch1 != -1)
9812 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009813 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814 if (op->ch2 != -1)
9815 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009816 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009817 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9818 return (total);
9819 case XPATH_OP_RESET:
9820 if (op->ch1 != -1)
9821 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009822 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009823 if (op->ch2 != -1)
9824 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009825 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009826 ctxt->context->node = NULL;
9827 return (total);
9828 case XPATH_OP_COLLECT:{
9829 if (op->ch1 == -1)
9830 return (0);
9831
9832 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009833 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009834
9835 /*
9836 * Optimization for [n] selection where n is a number
9837 */
9838 if ((op->ch2 != -1) &&
9839 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9840 (comp->steps[op->ch2].ch1 == -1) &&
9841 (comp->steps[op->ch2].ch2 != -1) &&
9842 (comp->steps[comp->steps[op->ch2].ch2].op ==
9843 XPATH_OP_VALUE)) {
9844 xmlXPathObjectPtr val;
9845
9846 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9847 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9848 int indx = (int) val->floatval;
9849
9850 if (val->floatval == (float) indx) {
9851 total +=
9852 xmlXPathNodeCollectAndTestNth(ctxt, op,
9853 indx, NULL,
9854 last);
9855 return (total);
9856 }
9857 }
9858 }
9859 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9860 return (total);
9861 }
9862 case XPATH_OP_VALUE:
9863 valuePush(ctxt,
9864 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9865 return (0);
9866 case XPATH_OP_SORT:
9867 if (op->ch1 != -1)
9868 total +=
9869 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9870 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009871 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009872 if ((ctxt->value != NULL)
9873 && (ctxt->value->type == XPATH_NODESET)
9874 && (ctxt->value->nodesetval != NULL))
9875 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9876 return (total);
9877 default:
9878 return (xmlXPathCompOpEval(ctxt, op));
9879 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009880}
9881
Owen Taylor3473f882001-02-23 17:55:21 +00009882/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009883 * xmlXPathCompOpEval:
9884 * @ctxt: the XPath parser context with the compiled expression
9885 * @op: an XPath compiled operation
9886 *
9887 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009888 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009889 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009890static int
9891xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9892{
9893 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009894 int equal, ret;
9895 xmlXPathCompExprPtr comp;
9896 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009897 xmlNodePtr bak;
9898 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009899 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009900 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009901
Daniel Veillard556c6682001-10-06 09:59:51 +00009902 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009903 comp = ctxt->comp;
9904 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009905 case XPATH_OP_END:
9906 return (0);
9907 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009908 bakd = ctxt->context->doc;
9909 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009910 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009911 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009913 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009914 xmlXPathBooleanFunction(ctxt, 1);
9915 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9916 return (total);
9917 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009918 ctxt->context->doc = bakd;
9919 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009920 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009921 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009923 if (ctxt->error) {
9924 xmlXPathFreeObject(arg2);
9925 return(0);
9926 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009927 xmlXPathBooleanFunction(ctxt, 1);
9928 arg1 = valuePop(ctxt);
9929 arg1->boolval &= arg2->boolval;
9930 valuePush(ctxt, arg1);
9931 xmlXPathFreeObject(arg2);
9932 return (total);
9933 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009934 bakd = ctxt->context->doc;
9935 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009936 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009937 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009938 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009939 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009940 xmlXPathBooleanFunction(ctxt, 1);
9941 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9942 return (total);
9943 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009944 ctxt->context->doc = bakd;
9945 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009946 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009947 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009949 if (ctxt->error) {
9950 xmlXPathFreeObject(arg2);
9951 return(0);
9952 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009953 xmlXPathBooleanFunction(ctxt, 1);
9954 arg1 = valuePop(ctxt);
9955 arg1->boolval |= arg2->boolval;
9956 valuePush(ctxt, arg1);
9957 xmlXPathFreeObject(arg2);
9958 return (total);
9959 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009960 bakd = ctxt->context->doc;
9961 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009962 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009963 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009964 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009965 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009966 ctxt->context->doc = bakd;
9967 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009968 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009969 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009970 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009971 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +00009972 if (op->value)
9973 equal = xmlXPathEqualValues(ctxt);
9974 else
9975 equal = xmlXPathNotEqualValues(ctxt);
9976 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +00009977 return (total);
9978 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009979 bakd = ctxt->context->doc;
9980 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009981 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009982 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009983 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009984 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009985 ctxt->context->doc = bakd;
9986 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009987 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009988 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009989 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009990 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009991 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9992 valuePush(ctxt, xmlXPathNewBoolean(ret));
9993 return (total);
9994 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009995 bakd = ctxt->context->doc;
9996 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009997 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009998 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009999 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010000 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010001 if (op->ch2 != -1) {
10002 ctxt->context->doc = bakd;
10003 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010004 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010005 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010006 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010007 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010008 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010009 if (op->value == 0)
10010 xmlXPathSubValues(ctxt);
10011 else if (op->value == 1)
10012 xmlXPathAddValues(ctxt);
10013 else if (op->value == 2)
10014 xmlXPathValueFlipSign(ctxt);
10015 else if (op->value == 3) {
10016 CAST_TO_NUMBER;
10017 CHECK_TYPE0(XPATH_NUMBER);
10018 }
10019 return (total);
10020 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010021 bakd = ctxt->context->doc;
10022 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010023 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010024 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010025 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010026 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010027 ctxt->context->doc = bakd;
10028 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010029 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010030 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010031 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010032 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010033 if (op->value == 0)
10034 xmlXPathMultValues(ctxt);
10035 else if (op->value == 1)
10036 xmlXPathDivValues(ctxt);
10037 else if (op->value == 2)
10038 xmlXPathModValues(ctxt);
10039 return (total);
10040 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010041 bakd = ctxt->context->doc;
10042 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010043 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010044 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010045 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010046 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010047 ctxt->context->doc = bakd;
10048 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010049 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010050 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010052 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010053 CHECK_TYPE0(XPATH_NODESET);
10054 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010055
Daniel Veillardf06307e2001-07-03 10:35:50 +000010056 CHECK_TYPE0(XPATH_NODESET);
10057 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010058
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10060 arg2->nodesetval);
10061 valuePush(ctxt, arg1);
10062 xmlXPathFreeObject(arg2);
10063 return (total);
10064 case XPATH_OP_ROOT:
10065 xmlXPathRoot(ctxt);
10066 return (total);
10067 case XPATH_OP_NODE:
10068 if (op->ch1 != -1)
10069 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010070 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010071 if (op->ch2 != -1)
10072 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010073 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010074 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10075 return (total);
10076 case XPATH_OP_RESET:
10077 if (op->ch1 != -1)
10078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010079 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010080 if (op->ch2 != -1)
10081 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010082 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010083 ctxt->context->node = NULL;
10084 return (total);
10085 case XPATH_OP_COLLECT:{
10086 if (op->ch1 == -1)
10087 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010088
Daniel Veillardf06307e2001-07-03 10:35:50 +000010089 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010090 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010091
Daniel Veillardf06307e2001-07-03 10:35:50 +000010092 /*
10093 * Optimization for [n] selection where n is a number
10094 */
10095 if ((op->ch2 != -1) &&
10096 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10097 (comp->steps[op->ch2].ch1 == -1) &&
10098 (comp->steps[op->ch2].ch2 != -1) &&
10099 (comp->steps[comp->steps[op->ch2].ch2].op ==
10100 XPATH_OP_VALUE)) {
10101 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010102
Daniel Veillardf06307e2001-07-03 10:35:50 +000010103 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10104 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10105 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010106
Daniel Veillardf06307e2001-07-03 10:35:50 +000010107 if (val->floatval == (float) indx) {
10108 total +=
10109 xmlXPathNodeCollectAndTestNth(ctxt, op,
10110 indx, NULL,
10111 NULL);
10112 return (total);
10113 }
10114 }
10115 }
10116 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10117 return (total);
10118 }
10119 case XPATH_OP_VALUE:
10120 valuePush(ctxt,
10121 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10122 return (total);
10123 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010124 xmlXPathObjectPtr val;
10125
Daniel Veillardf06307e2001-07-03 10:35:50 +000010126 if (op->ch1 != -1)
10127 total +=
10128 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010129 if (op->value5 == NULL) {
10130 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10131 if (val == NULL) {
10132 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10133 return(0);
10134 }
10135 valuePush(ctxt, val);
10136 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010137 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010138
Daniel Veillardf06307e2001-07-03 10:35:50 +000010139 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10140 if (URI == NULL) {
10141 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010142 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143 op->value4, op->value5);
10144 return (total);
10145 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010146 val = xmlXPathVariableLookupNS(ctxt->context,
10147 op->value4, URI);
10148 if (val == NULL) {
10149 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10150 return(0);
10151 }
10152 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010153 }
10154 return (total);
10155 }
10156 case XPATH_OP_FUNCTION:{
10157 xmlXPathFunction func;
10158 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010159 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010160
10161 if (op->ch1 != -1)
10162 total +=
10163 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010164 if (ctxt->valueNr < op->value) {
10165 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010166 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010167 ctxt->error = XPATH_INVALID_OPERAND;
10168 return (total);
10169 }
10170 for (i = 0; i < op->value; i++)
10171 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10172 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010173 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010174 ctxt->error = XPATH_INVALID_OPERAND;
10175 return (total);
10176 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010177 if (op->cache != NULL)
10178 func = (xmlXPathFunction) op->cache;
10179 else {
10180 const xmlChar *URI = NULL;
10181
10182 if (op->value5 == NULL)
10183 func =
10184 xmlXPathFunctionLookup(ctxt->context,
10185 op->value4);
10186 else {
10187 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10188 if (URI == NULL) {
10189 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010190 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010191 op->value4, op->value5);
10192 return (total);
10193 }
10194 func = xmlXPathFunctionLookupNS(ctxt->context,
10195 op->value4, URI);
10196 }
10197 if (func == NULL) {
10198 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010199 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010200 op->value4);
10201 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010202 }
10203 op->cache = (void *) func;
10204 op->cacheURI = (void *) URI;
10205 }
10206 oldFunc = ctxt->context->function;
10207 oldFuncURI = ctxt->context->functionURI;
10208 ctxt->context->function = op->value4;
10209 ctxt->context->functionURI = op->cacheURI;
10210 func(ctxt, op->value);
10211 ctxt->context->function = oldFunc;
10212 ctxt->context->functionURI = oldFuncURI;
10213 return (total);
10214 }
10215 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010216 bakd = ctxt->context->doc;
10217 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010218 if (op->ch1 != -1)
10219 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010220 ctxt->context->doc = bakd;
10221 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010222 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010223 if (op->ch2 != -1)
10224 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010225 ctxt->context->doc = bakd;
10226 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010227 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010228 return (total);
10229 case XPATH_OP_PREDICATE:
10230 case XPATH_OP_FILTER:{
10231 xmlXPathObjectPtr res;
10232 xmlXPathObjectPtr obj, tmp;
10233 xmlNodeSetPtr newset = NULL;
10234 xmlNodeSetPtr oldset;
10235 xmlNodePtr oldnode;
10236 int i;
10237
10238 /*
10239 * Optimization for ()[1] selection i.e. the first elem
10240 */
10241 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10242 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10243 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10244 xmlXPathObjectPtr val;
10245
10246 val = comp->steps[op->ch2].value4;
10247 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10248 (val->floatval == 1.0)) {
10249 xmlNodePtr first = NULL;
10250
10251 total +=
10252 xmlXPathCompOpEvalFirst(ctxt,
10253 &comp->steps[op->ch1],
10254 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010255 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010256 /*
10257 * The nodeset should be in document order,
10258 * Keep only the first value
10259 */
10260 if ((ctxt->value != NULL) &&
10261 (ctxt->value->type == XPATH_NODESET) &&
10262 (ctxt->value->nodesetval != NULL) &&
10263 (ctxt->value->nodesetval->nodeNr > 1))
10264 ctxt->value->nodesetval->nodeNr = 1;
10265 return (total);
10266 }
10267 }
10268 /*
10269 * Optimization for ()[last()] selection i.e. the last elem
10270 */
10271 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10272 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10273 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10274 int f = comp->steps[op->ch2].ch1;
10275
10276 if ((f != -1) &&
10277 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10278 (comp->steps[f].value5 == NULL) &&
10279 (comp->steps[f].value == 0) &&
10280 (comp->steps[f].value4 != NULL) &&
10281 (xmlStrEqual
10282 (comp->steps[f].value4, BAD_CAST "last"))) {
10283 xmlNodePtr last = NULL;
10284
10285 total +=
10286 xmlXPathCompOpEvalLast(ctxt,
10287 &comp->steps[op->ch1],
10288 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010289 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010290 /*
10291 * The nodeset should be in document order,
10292 * Keep only the last value
10293 */
10294 if ((ctxt->value != NULL) &&
10295 (ctxt->value->type == XPATH_NODESET) &&
10296 (ctxt->value->nodesetval != NULL) &&
10297 (ctxt->value->nodesetval->nodeTab != NULL) &&
10298 (ctxt->value->nodesetval->nodeNr > 1)) {
10299 ctxt->value->nodesetval->nodeTab[0] =
10300 ctxt->value->nodesetval->nodeTab[ctxt->
10301 value->
10302 nodesetval->
10303 nodeNr -
10304 1];
10305 ctxt->value->nodesetval->nodeNr = 1;
10306 }
10307 return (total);
10308 }
10309 }
10310
10311 if (op->ch1 != -1)
10312 total +=
10313 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010314 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010315 if (op->ch2 == -1)
10316 return (total);
10317 if (ctxt->value == NULL)
10318 return (total);
10319
10320 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010321
10322#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010323 /*
10324 * Hum are we filtering the result of an XPointer expression
10325 */
10326 if (ctxt->value->type == XPATH_LOCATIONSET) {
10327 xmlLocationSetPtr newlocset = NULL;
10328 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010329
Daniel Veillardf06307e2001-07-03 10:35:50 +000010330 /*
10331 * Extract the old locset, and then evaluate the result of the
10332 * expression for all the element in the locset. use it to grow
10333 * up a new locset.
10334 */
10335 CHECK_TYPE0(XPATH_LOCATIONSET);
10336 obj = valuePop(ctxt);
10337 oldlocset = obj->user;
10338 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010339
Daniel Veillardf06307e2001-07-03 10:35:50 +000010340 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10341 ctxt->context->contextSize = 0;
10342 ctxt->context->proximityPosition = 0;
10343 if (op->ch2 != -1)
10344 total +=
10345 xmlXPathCompOpEval(ctxt,
10346 &comp->steps[op->ch2]);
10347 res = valuePop(ctxt);
10348 if (res != NULL)
10349 xmlXPathFreeObject(res);
10350 valuePush(ctxt, obj);
10351 CHECK_ERROR0;
10352 return (total);
10353 }
10354 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010355
Daniel Veillardf06307e2001-07-03 10:35:50 +000010356 for (i = 0; i < oldlocset->locNr; i++) {
10357 /*
10358 * Run the evaluation with a node list made of a
10359 * single item in the nodelocset.
10360 */
10361 ctxt->context->node = oldlocset->locTab[i]->user;
10362 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10363 valuePush(ctxt, tmp);
10364 ctxt->context->contextSize = oldlocset->locNr;
10365 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010366
Daniel Veillardf06307e2001-07-03 10:35:50 +000010367 if (op->ch2 != -1)
10368 total +=
10369 xmlXPathCompOpEval(ctxt,
10370 &comp->steps[op->ch2]);
10371 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010372
Daniel Veillardf06307e2001-07-03 10:35:50 +000010373 /*
10374 * The result of the evaluation need to be tested to
10375 * decided whether the filter succeeded or not
10376 */
10377 res = valuePop(ctxt);
10378 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10379 xmlXPtrLocationSetAdd(newlocset,
10380 xmlXPathObjectCopy
10381 (oldlocset->locTab[i]));
10382 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010383
Daniel Veillardf06307e2001-07-03 10:35:50 +000010384 /*
10385 * Cleanup
10386 */
10387 if (res != NULL)
10388 xmlXPathFreeObject(res);
10389 if (ctxt->value == tmp) {
10390 res = valuePop(ctxt);
10391 xmlXPathFreeObject(res);
10392 }
10393
10394 ctxt->context->node = NULL;
10395 }
10396
10397 /*
10398 * The result is used as the new evaluation locset.
10399 */
10400 xmlXPathFreeObject(obj);
10401 ctxt->context->node = NULL;
10402 ctxt->context->contextSize = -1;
10403 ctxt->context->proximityPosition = -1;
10404 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10405 ctxt->context->node = oldnode;
10406 return (total);
10407 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010408#endif /* LIBXML_XPTR_ENABLED */
10409
Daniel Veillardf06307e2001-07-03 10:35:50 +000010410 /*
10411 * Extract the old set, and then evaluate the result of the
10412 * expression for all the element in the set. use it to grow
10413 * up a new set.
10414 */
10415 CHECK_TYPE0(XPATH_NODESET);
10416 obj = valuePop(ctxt);
10417 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010418
Daniel Veillardf06307e2001-07-03 10:35:50 +000010419 oldnode = ctxt->context->node;
10420 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010421
Daniel Veillardf06307e2001-07-03 10:35:50 +000010422 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10423 ctxt->context->contextSize = 0;
10424 ctxt->context->proximityPosition = 0;
10425 if (op->ch2 != -1)
10426 total +=
10427 xmlXPathCompOpEval(ctxt,
10428 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010429 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010430 res = valuePop(ctxt);
10431 if (res != NULL)
10432 xmlXPathFreeObject(res);
10433 valuePush(ctxt, obj);
10434 ctxt->context->node = oldnode;
10435 CHECK_ERROR0;
10436 } else {
10437 /*
10438 * Initialize the new set.
10439 */
10440 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010441
Daniel Veillardf06307e2001-07-03 10:35:50 +000010442 for (i = 0; i < oldset->nodeNr; i++) {
10443 /*
10444 * Run the evaluation with a node list made of
10445 * a single item in the nodeset.
10446 */
10447 ctxt->context->node = oldset->nodeTab[i];
10448 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10449 valuePush(ctxt, tmp);
10450 ctxt->context->contextSize = oldset->nodeNr;
10451 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010452
Daniel Veillardf06307e2001-07-03 10:35:50 +000010453 if (op->ch2 != -1)
10454 total +=
10455 xmlXPathCompOpEval(ctxt,
10456 &comp->steps[op->ch2]);
10457 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010458
Daniel Veillardf06307e2001-07-03 10:35:50 +000010459 /*
10460 * The result of the evaluation need to be tested to
10461 * decided whether the filter succeeded or not
10462 */
10463 res = valuePop(ctxt);
10464 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10465 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10466 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010467
Daniel Veillardf06307e2001-07-03 10:35:50 +000010468 /*
10469 * Cleanup
10470 */
10471 if (res != NULL)
10472 xmlXPathFreeObject(res);
10473 if (ctxt->value == tmp) {
10474 res = valuePop(ctxt);
10475 xmlXPathFreeObject(res);
10476 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010477
Daniel Veillardf06307e2001-07-03 10:35:50 +000010478 ctxt->context->node = NULL;
10479 }
10480
10481 /*
10482 * The result is used as the new evaluation set.
10483 */
10484 xmlXPathFreeObject(obj);
10485 ctxt->context->node = NULL;
10486 ctxt->context->contextSize = -1;
10487 ctxt->context->proximityPosition = -1;
10488 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10489 }
10490 ctxt->context->node = oldnode;
10491 return (total);
10492 }
10493 case XPATH_OP_SORT:
10494 if (op->ch1 != -1)
10495 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010496 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010497 if ((ctxt->value != NULL) &&
10498 (ctxt->value->type == XPATH_NODESET) &&
10499 (ctxt->value->nodesetval != NULL))
10500 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10501 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010502#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010503 case XPATH_OP_RANGETO:{
10504 xmlXPathObjectPtr range;
10505 xmlXPathObjectPtr res, obj;
10506 xmlXPathObjectPtr tmp;
10507 xmlLocationSetPtr newset = NULL;
10508 xmlNodeSetPtr oldset;
10509 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010510
Daniel Veillardf06307e2001-07-03 10:35:50 +000010511 if (op->ch1 != -1)
10512 total +=
10513 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10514 if (op->ch2 == -1)
10515 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010516
Daniel Veillardf06307e2001-07-03 10:35:50 +000010517 CHECK_TYPE0(XPATH_NODESET);
10518 obj = valuePop(ctxt);
10519 oldset = obj->nodesetval;
10520 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010521
Daniel Veillardf06307e2001-07-03 10:35:50 +000010522 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010523
Daniel Veillardf06307e2001-07-03 10:35:50 +000010524 if (oldset != NULL) {
10525 for (i = 0; i < oldset->nodeNr; i++) {
10526 /*
10527 * Run the evaluation with a node list made of a single item
10528 * in the nodeset.
10529 */
10530 ctxt->context->node = oldset->nodeTab[i];
10531 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10532 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010533
Daniel Veillardf06307e2001-07-03 10:35:50 +000010534 if (op->ch2 != -1)
10535 total +=
10536 xmlXPathCompOpEval(ctxt,
10537 &comp->steps[op->ch2]);
10538 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010539
Daniel Veillardf06307e2001-07-03 10:35:50 +000010540 /*
10541 * The result of the evaluation need to be tested to
10542 * decided whether the filter succeeded or not
10543 */
10544 res = valuePop(ctxt);
10545 range =
10546 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10547 res);
10548 if (range != NULL) {
10549 xmlXPtrLocationSetAdd(newset, range);
10550 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010551
Daniel Veillardf06307e2001-07-03 10:35:50 +000010552 /*
10553 * Cleanup
10554 */
10555 if (res != NULL)
10556 xmlXPathFreeObject(res);
10557 if (ctxt->value == tmp) {
10558 res = valuePop(ctxt);
10559 xmlXPathFreeObject(res);
10560 }
10561
10562 ctxt->context->node = NULL;
10563 }
10564 }
10565
10566 /*
10567 * The result is used as the new evaluation set.
10568 */
10569 xmlXPathFreeObject(obj);
10570 ctxt->context->node = NULL;
10571 ctxt->context->contextSize = -1;
10572 ctxt->context->proximityPosition = -1;
10573 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10574 return (total);
10575 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010576#endif /* LIBXML_XPTR_ENABLED */
10577 }
10578 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010579 "XPath: unknown precompiled operation %d\n", op->op);
10580 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010581}
10582
10583/**
10584 * xmlXPathRunEval:
10585 * @ctxt: the XPath parser context with the compiled expression
10586 *
10587 * Evaluate the Precompiled XPath expression in the given context.
10588 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010589static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010590xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10591 xmlXPathCompExprPtr comp;
10592
10593 if ((ctxt == NULL) || (ctxt->comp == NULL))
10594 return;
10595
10596 if (ctxt->valueTab == NULL) {
10597 /* Allocate the value stack */
10598 ctxt->valueTab = (xmlXPathObjectPtr *)
10599 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10600 if (ctxt->valueTab == NULL) {
10601 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010602 }
10603 ctxt->valueNr = 0;
10604 ctxt->valueMax = 10;
10605 ctxt->value = NULL;
10606 }
10607 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010608 if(comp->last < 0) {
10609 xmlGenericError(xmlGenericErrorContext,
10610 "xmlXPathRunEval: last is less than zero\n");
10611 return;
10612 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010613 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10614}
10615
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010616/************************************************************************
10617 * *
10618 * Public interfaces *
10619 * *
10620 ************************************************************************/
10621
10622/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010623 * xmlXPathEvalPredicate:
10624 * @ctxt: the XPath context
10625 * @res: the Predicate Expression evaluation result
10626 *
10627 * Evaluate a predicate result for the current node.
10628 * A PredicateExpr is evaluated by evaluating the Expr and converting
10629 * the result to a boolean. If the result is a number, the result will
10630 * be converted to true if the number is equal to the position of the
10631 * context node in the context node list (as returned by the position
10632 * function) and will be converted to false otherwise; if the result
10633 * is not a number, then the result will be converted as if by a call
10634 * to the boolean function.
10635 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010636 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010637 */
10638int
10639xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10640 if (res == NULL) return(0);
10641 switch (res->type) {
10642 case XPATH_BOOLEAN:
10643 return(res->boolval);
10644 case XPATH_NUMBER:
10645 return(res->floatval == ctxt->proximityPosition);
10646 case XPATH_NODESET:
10647 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010648 if (res->nodesetval == NULL)
10649 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010650 return(res->nodesetval->nodeNr != 0);
10651 case XPATH_STRING:
10652 return((res->stringval != NULL) &&
10653 (xmlStrlen(res->stringval) != 0));
10654 default:
10655 STRANGE
10656 }
10657 return(0);
10658}
10659
10660/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010661 * xmlXPathEvaluatePredicateResult:
10662 * @ctxt: the XPath Parser context
10663 * @res: the Predicate Expression evaluation result
10664 *
10665 * Evaluate a predicate result for the current node.
10666 * A PredicateExpr is evaluated by evaluating the Expr and converting
10667 * the result to a boolean. If the result is a number, the result will
10668 * be converted to true if the number is equal to the position of the
10669 * context node in the context node list (as returned by the position
10670 * function) and will be converted to false otherwise; if the result
10671 * is not a number, then the result will be converted as if by a call
10672 * to the boolean function.
10673 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010674 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010675 */
10676int
10677xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10678 xmlXPathObjectPtr res) {
10679 if (res == NULL) return(0);
10680 switch (res->type) {
10681 case XPATH_BOOLEAN:
10682 return(res->boolval);
10683 case XPATH_NUMBER:
10684 return(res->floatval == ctxt->context->proximityPosition);
10685 case XPATH_NODESET:
10686 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010687 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010688 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010689 return(res->nodesetval->nodeNr != 0);
10690 case XPATH_STRING:
10691 return((res->stringval != NULL) &&
10692 (xmlStrlen(res->stringval) != 0));
10693 default:
10694 STRANGE
10695 }
10696 return(0);
10697}
10698
10699/**
10700 * xmlXPathCompile:
10701 * @str: the XPath expression
10702 *
10703 * Compile an XPath expression
10704 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010705 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010706 * the caller has to free the object.
10707 */
10708xmlXPathCompExprPtr
10709xmlXPathCompile(const xmlChar *str) {
10710 xmlXPathParserContextPtr ctxt;
10711 xmlXPathCompExprPtr comp;
10712
10713 xmlXPathInit();
10714
10715 ctxt = xmlXPathNewParserContext(str, NULL);
10716 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010717
Daniel Veillard40af6492001-04-22 08:50:55 +000010718 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010719 /*
10720 * aleksey: in some cases this line prints *second* error message
10721 * (see bug #78858) and probably this should be fixed.
10722 * However, we are not sure that all error messages are printed
10723 * out in other places. It's not critical so we leave it as-is for now
10724 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010725 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10726 comp = NULL;
10727 } else {
10728 comp = ctxt->comp;
10729 ctxt->comp = NULL;
10730 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010731 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010732 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010733 comp->expr = xmlStrdup(str);
10734#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010735 comp->string = xmlStrdup(str);
10736 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010737#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010738 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010739 return(comp);
10740}
10741
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010742/**
10743 * xmlXPathCompiledEval:
10744 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010745 * @ctx: the XPath context
10746 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010747 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010748 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010749 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010750 * the caller has to free the object.
10751 */
10752xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010753xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010754 xmlXPathParserContextPtr ctxt;
10755 xmlXPathObjectPtr res, tmp, init = NULL;
10756 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010757#ifndef LIBXML_THREAD_ENABLED
10758 static int reentance = 0;
10759#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010760
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010761 if ((comp == NULL) || (ctx == NULL))
10762 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010763 xmlXPathInit();
10764
10765 CHECK_CONTEXT(ctx)
10766
Daniel Veillard81463942001-10-16 12:34:39 +000010767#ifndef LIBXML_THREAD_ENABLED
10768 reentance++;
10769 if (reentance > 1)
10770 xmlXPathDisableOptimizer = 1;
10771#endif
10772
Daniel Veillardf06307e2001-07-03 10:35:50 +000010773#ifdef DEBUG_EVAL_COUNTS
10774 comp->nb++;
10775 if ((comp->string != NULL) && (comp->nb > 100)) {
10776 fprintf(stderr, "100 x %s\n", comp->string);
10777 comp->nb = 0;
10778 }
10779#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010780 ctxt = xmlXPathCompParserContext(comp, ctx);
10781 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010782
10783 if (ctxt->value == NULL) {
10784 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010785 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010786 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010787 } else {
10788 res = valuePop(ctxt);
10789 }
10790
Daniel Veillardf06307e2001-07-03 10:35:50 +000010791
Owen Taylor3473f882001-02-23 17:55:21 +000010792 do {
10793 tmp = valuePop(ctxt);
10794 if (tmp != NULL) {
10795 if (tmp != init)
10796 stack++;
10797 xmlXPathFreeObject(tmp);
10798 }
10799 } while (tmp != NULL);
10800 if ((stack != 0) && (res != NULL)) {
10801 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010802 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010803 stack);
10804 }
10805 if (ctxt->error != XPATH_EXPRESSION_OK) {
10806 xmlXPathFreeObject(res);
10807 res = NULL;
10808 }
10809
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010810
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010811 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010812 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010813#ifndef LIBXML_THREAD_ENABLED
10814 reentance--;
10815#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010816 return(res);
10817}
10818
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010819/**
10820 * xmlXPathEvalExpr:
10821 * @ctxt: the XPath Parser context
10822 *
10823 * Parse and evaluate an XPath expression in the given context,
10824 * then push the result on the context stack
10825 */
10826void
10827xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10828 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010829 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010830 xmlXPathRunEval(ctxt);
10831}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010832
10833/**
10834 * xmlXPathEval:
10835 * @str: the XPath expression
10836 * @ctx: the XPath context
10837 *
10838 * Evaluate the XPath Location Path in the given context.
10839 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010840 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010841 * the caller has to free the object.
10842 */
10843xmlXPathObjectPtr
10844xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10845 xmlXPathParserContextPtr ctxt;
10846 xmlXPathObjectPtr res, tmp, init = NULL;
10847 int stack = 0;
10848
10849 xmlXPathInit();
10850
10851 CHECK_CONTEXT(ctx)
10852
10853 ctxt = xmlXPathNewParserContext(str, ctx);
10854 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010855
10856 if (ctxt->value == NULL) {
10857 xmlGenericError(xmlGenericErrorContext,
10858 "xmlXPathEval: evaluation failed\n");
10859 res = NULL;
10860 } else if (*ctxt->cur != 0) {
10861 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10862 res = NULL;
10863 } else {
10864 res = valuePop(ctxt);
10865 }
10866
10867 do {
10868 tmp = valuePop(ctxt);
10869 if (tmp != NULL) {
10870 if (tmp != init)
10871 stack++;
10872 xmlXPathFreeObject(tmp);
10873 }
10874 } while (tmp != NULL);
10875 if ((stack != 0) && (res != NULL)) {
10876 xmlGenericError(xmlGenericErrorContext,
10877 "xmlXPathEval: %d object left on the stack\n",
10878 stack);
10879 }
10880 if (ctxt->error != XPATH_EXPRESSION_OK) {
10881 xmlXPathFreeObject(res);
10882 res = NULL;
10883 }
10884
Owen Taylor3473f882001-02-23 17:55:21 +000010885 xmlXPathFreeParserContext(ctxt);
10886 return(res);
10887}
10888
10889/**
10890 * xmlXPathEvalExpression:
10891 * @str: the XPath expression
10892 * @ctxt: the XPath context
10893 *
10894 * Evaluate the XPath expression in the given context.
10895 *
10896 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10897 * the caller has to free the object.
10898 */
10899xmlXPathObjectPtr
10900xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10901 xmlXPathParserContextPtr pctxt;
10902 xmlXPathObjectPtr res, tmp;
10903 int stack = 0;
10904
10905 xmlXPathInit();
10906
10907 CHECK_CONTEXT(ctxt)
10908
10909 pctxt = xmlXPathNewParserContext(str, ctxt);
10910 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010911
10912 if (*pctxt->cur != 0) {
10913 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10914 res = NULL;
10915 } else {
10916 res = valuePop(pctxt);
10917 }
10918 do {
10919 tmp = valuePop(pctxt);
10920 if (tmp != NULL) {
10921 xmlXPathFreeObject(tmp);
10922 stack++;
10923 }
10924 } while (tmp != NULL);
10925 if ((stack != 0) && (res != NULL)) {
10926 xmlGenericError(xmlGenericErrorContext,
10927 "xmlXPathEvalExpression: %d object left on the stack\n",
10928 stack);
10929 }
10930 xmlXPathFreeParserContext(pctxt);
10931 return(res);
10932}
10933
Daniel Veillard42766c02002-08-22 20:52:17 +000010934/************************************************************************
10935 * *
10936 * Extra functions not pertaining to the XPath spec *
10937 * *
10938 ************************************************************************/
10939/**
10940 * xmlXPathEscapeUriFunction:
10941 * @ctxt: the XPath Parser context
10942 * @nargs: the number of arguments
10943 *
10944 * Implement the escape-uri() XPath function
10945 * string escape-uri(string $str, bool $escape-reserved)
10946 *
10947 * This function applies the URI escaping rules defined in section 2 of [RFC
10948 * 2396] to the string supplied as $uri-part, which typically represents all
10949 * or part of a URI. The effect of the function is to replace any special
10950 * character in the string by an escape sequence of the form %xx%yy...,
10951 * where xxyy... is the hexadecimal representation of the octets used to
10952 * represent the character in UTF-8.
10953 *
10954 * The set of characters that are escaped depends on the setting of the
10955 * boolean argument $escape-reserved.
10956 *
10957 * If $escape-reserved is true, all characters are escaped other than lower
10958 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10959 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10960 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10961 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10962 * A-F).
10963 *
10964 * If $escape-reserved is false, the behavior differs in that characters
10965 * referred to in [RFC 2396] as reserved characters are not escaped. These
10966 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10967 *
10968 * [RFC 2396] does not define whether escaped URIs should use lower case or
10969 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10970 * compared using string comparison functions, this function must always use
10971 * the upper-case letters A-F.
10972 *
10973 * Generally, $escape-reserved should be set to true when escaping a string
10974 * that is to form a single part of a URI, and to false when escaping an
10975 * entire URI or URI reference.
10976 *
10977 * In the case of non-ascii characters, the string is encoded according to
10978 * utf-8 and then converted according to RFC 2396.
10979 *
10980 * Examples
10981 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10982 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10983 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10984 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10985 *
10986 */
Daniel Veillard118aed72002-09-24 14:13:13 +000010987static void
Daniel Veillard42766c02002-08-22 20:52:17 +000010988xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10989 xmlXPathObjectPtr str;
10990 int escape_reserved;
10991 xmlBufferPtr target;
10992 xmlChar *cptr;
10993 xmlChar escape[4];
10994
10995 CHECK_ARITY(2);
10996
10997 escape_reserved = xmlXPathPopBoolean(ctxt);
10998
10999 CAST_TO_STRING;
11000 str = valuePop(ctxt);
11001
11002 target = xmlBufferCreate();
11003
11004 escape[0] = '%';
11005 escape[3] = 0;
11006
11007 if (target) {
11008 for (cptr = str->stringval; *cptr; cptr++) {
11009 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11010 (*cptr >= 'a' && *cptr <= 'z') ||
11011 (*cptr >= '0' && *cptr <= '9') ||
11012 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11013 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11014 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11015 (*cptr == '%' &&
11016 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11017 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11018 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11019 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11020 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11021 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11022 (!escape_reserved &&
11023 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11024 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11025 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11026 *cptr == ','))) {
11027 xmlBufferAdd(target, cptr, 1);
11028 } else {
11029 if ((*cptr >> 4) < 10)
11030 escape[1] = '0' + (*cptr >> 4);
11031 else
11032 escape[1] = 'A' - 10 + (*cptr >> 4);
11033 if ((*cptr & 0xF) < 10)
11034 escape[2] = '0' + (*cptr & 0xF);
11035 else
11036 escape[2] = 'A' - 10 + (*cptr & 0xF);
11037
11038 xmlBufferAdd(target, &escape[0], 3);
11039 }
11040 }
11041 }
11042 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11043 xmlBufferFree(target);
11044 xmlXPathFreeObject(str);
11045}
11046
Owen Taylor3473f882001-02-23 17:55:21 +000011047/**
11048 * xmlXPathRegisterAllFunctions:
11049 * @ctxt: the XPath context
11050 *
11051 * Registers all default XPath functions in this context
11052 */
11053void
11054xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11055{
11056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11057 xmlXPathBooleanFunction);
11058 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11059 xmlXPathCeilingFunction);
11060 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11061 xmlXPathCountFunction);
11062 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11063 xmlXPathConcatFunction);
11064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11065 xmlXPathContainsFunction);
11066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11067 xmlXPathIdFunction);
11068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11069 xmlXPathFalseFunction);
11070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11071 xmlXPathFloorFunction);
11072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11073 xmlXPathLastFunction);
11074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11075 xmlXPathLangFunction);
11076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11077 xmlXPathLocalNameFunction);
11078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11079 xmlXPathNotFunction);
11080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11081 xmlXPathNameFunction);
11082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11083 xmlXPathNamespaceURIFunction);
11084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11085 xmlXPathNormalizeFunction);
11086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11087 xmlXPathNumberFunction);
11088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11089 xmlXPathPositionFunction);
11090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11091 xmlXPathRoundFunction);
11092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11093 xmlXPathStringFunction);
11094 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11095 xmlXPathStringLengthFunction);
11096 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11097 xmlXPathStartsWithFunction);
11098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11099 xmlXPathSubstringFunction);
11100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11101 xmlXPathSubstringBeforeFunction);
11102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11103 xmlXPathSubstringAfterFunction);
11104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11105 xmlXPathSumFunction);
11106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11107 xmlXPathTrueFunction);
11108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11109 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011110
11111 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11112 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11113 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011114}
11115
11116#endif /* LIBXML_XPATH_ENABLED */