blob: 1f575442b6468406178c0eec6f79cddfb4f02846 [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 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020#ifdef LIBXML_XPATH_ENABLED
21
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_MATH_H
28#include <math.h>
29#endif
30#ifdef HAVE_FLOAT_H
31#include <float.h>
32#endif
Owen Taylor3473f882001-02-23 17:55:21 +000033#ifdef HAVE_CTYPE_H
34#include <ctype.h>
35#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000036#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000037#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#endif
Owen Taylor3473f882001-02-23 17:55:21 +000039
40#include <libxml/xmlmemory.h>
41#include <libxml/tree.h>
42#include <libxml/valid.h>
43#include <libxml/xpath.h>
44#include <libxml/xpathInternals.h>
45#include <libxml/parserInternals.h>
46#include <libxml/hash.h>
47#ifdef LIBXML_XPTR_ENABLED
48#include <libxml/xpointer.h>
49#endif
50#ifdef LIBXML_DEBUG_ENABLED
51#include <libxml/debugXML.h>
52#endif
53#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000054#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000055#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000056
57/* #define DEBUG */
58/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000059/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000060/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000061/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000062
Daniel Veillard5792e162001-04-30 17:44:45 +000063double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000064
Daniel Veillard20ee8c02001-10-05 09:18:14 +000065static xmlNs xmlXPathXMLNamespaceStruct = {
66 NULL,
67 XML_NAMESPACE_DECL,
68 XML_XML_NAMESPACE,
69 BAD_CAST "xml"
70};
71static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillard81463942001-10-16 12:34:39 +000072#ifndef LIBXML_THREADS_ENABLED
73/*
74 * Optimizer is disabled only when threaded apps are detected while
75 * the library ain't compiled for thread safety.
76 */
77static int xmlXPathDisableOptimizer = 0;
78#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000079
Daniel Veillard9e7160d2001-03-18 23:17:47 +000080/************************************************************************
81 * *
82 * Floating point stuff *
83 * *
84 ************************************************************************/
85
Daniel Veillardc0631a62001-09-20 13:56:06 +000086#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000087#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000088#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000089#include "trionan.c"
90
Owen Taylor3473f882001-02-23 17:55:21 +000091/*
Owen Taylor3473f882001-02-23 17:55:21 +000092 * The lack of portability of this section of the libc is annoying !
93 */
94double xmlXPathNAN = 0;
95double xmlXPathPINF = 1;
96double xmlXPathNINF = -1;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000097static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000098
Owen Taylor3473f882001-02-23 17:55:21 +000099/**
100 * xmlXPathInit:
101 *
102 * Initialize the XPath environment
103 */
104void
105xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000106 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000107
Bjorn Reese45029602001-08-21 09:23:53 +0000108 xmlXPathPINF = trio_pinf();
109 xmlXPathNINF = trio_ninf();
110 xmlXPathNAN = trio_nan();
Owen Taylor3473f882001-02-23 17:55:21 +0000111
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000112 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000113}
114
Daniel Veillardcda96922001-08-21 10:56:31 +0000115/**
116 * xmlXPathIsNaN:
117 * @val: a double value
118 *
119 * Provides a portable isnan() function to detect whether a double
120 * is a NotaNumber. Based on trio code
121 * http://sourceforge.net/projects/ctrio/
122 *
123 * Returns 1 if the value is a NaN, 0 otherwise
124 */
125int
126xmlXPathIsNaN(double val) {
127 return(trio_isnan(val));
128}
129
130/**
131 * xmlXPathIsInf:
132 * @val: a double value
133 *
134 * Provides a portable isinf() function to detect whether a double
135 * is a +Infinite or -Infinite. Based on trio code
136 * http://sourceforge.net/projects/ctrio/
137 *
138 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
139 */
140int
141xmlXPathIsInf(double val) {
142 return(trio_isinf(val));
143}
144
Owen Taylor3473f882001-02-23 17:55:21 +0000145/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000146 * *
147 * Parser Types *
148 * *
149 ************************************************************************/
150
151/*
152 * Types are private:
153 */
154
155typedef enum {
156 XPATH_OP_END=0,
157 XPATH_OP_AND,
158 XPATH_OP_OR,
159 XPATH_OP_EQUAL,
160 XPATH_OP_CMP,
161 XPATH_OP_PLUS,
162 XPATH_OP_MULT,
163 XPATH_OP_UNION,
164 XPATH_OP_ROOT,
165 XPATH_OP_NODE,
166 XPATH_OP_RESET,
167 XPATH_OP_COLLECT,
168 XPATH_OP_VALUE,
169 XPATH_OP_VARIABLE,
170 XPATH_OP_FUNCTION,
171 XPATH_OP_ARG,
172 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000173 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000174 XPATH_OP_SORT
175#ifdef LIBXML_XPTR_ENABLED
176 ,XPATH_OP_RANGETO
177#endif
178} xmlXPathOp;
179
180typedef enum {
181 AXIS_ANCESTOR = 1,
182 AXIS_ANCESTOR_OR_SELF,
183 AXIS_ATTRIBUTE,
184 AXIS_CHILD,
185 AXIS_DESCENDANT,
186 AXIS_DESCENDANT_OR_SELF,
187 AXIS_FOLLOWING,
188 AXIS_FOLLOWING_SIBLING,
189 AXIS_NAMESPACE,
190 AXIS_PARENT,
191 AXIS_PRECEDING,
192 AXIS_PRECEDING_SIBLING,
193 AXIS_SELF
194} xmlXPathAxisVal;
195
196typedef enum {
197 NODE_TEST_NONE = 0,
198 NODE_TEST_TYPE = 1,
199 NODE_TEST_PI = 2,
200 NODE_TEST_ALL = 3,
201 NODE_TEST_NS = 4,
202 NODE_TEST_NAME = 5
203} xmlXPathTestVal;
204
205typedef enum {
206 NODE_TYPE_NODE = 0,
207 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
208 NODE_TYPE_TEXT = XML_TEXT_NODE,
209 NODE_TYPE_PI = XML_PI_NODE
210} xmlXPathTypeVal;
211
212
213typedef struct _xmlXPathStepOp xmlXPathStepOp;
214typedef xmlXPathStepOp *xmlXPathStepOpPtr;
215struct _xmlXPathStepOp {
216 xmlXPathOp op;
217 int ch1;
218 int ch2;
219 int value;
220 int value2;
221 int value3;
222 void *value4;
223 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000224 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000225 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000226};
227
228struct _xmlXPathCompExpr {
229 int nbStep;
230 int maxStep;
231 xmlXPathStepOp *steps; /* ops for computation */
232 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000233#ifdef DEBUG_EVAL_COUNTS
234 int nb;
235 xmlChar *string;
236#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000237};
238
239/************************************************************************
240 * *
241 * Parser Type functions *
242 * *
243 ************************************************************************/
244
245/**
246 * xmlXPathNewCompExpr:
247 *
248 * Create a new Xpath component
249 *
250 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
251 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000252static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000253xmlXPathNewCompExpr(void) {
254 xmlXPathCompExprPtr cur;
255
256 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
257 if (cur == NULL) {
258 xmlGenericError(xmlGenericErrorContext,
259 "xmlXPathNewCompExpr : malloc failed\n");
260 return(NULL);
261 }
262 memset(cur, 0, sizeof(xmlXPathCompExpr));
263 cur->maxStep = 10;
264 cur->nbStep = 0;
265 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
266 sizeof(xmlXPathStepOp));
267 if (cur->steps == NULL) {
268 xmlGenericError(xmlGenericErrorContext,
269 "xmlXPathNewCompExpr : malloc failed\n");
270 xmlFree(cur);
271 return(NULL);
272 }
273 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
274 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000275#ifdef DEBUG_EVAL_COUNTS
276 cur->nb = 0;
277#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000278 return(cur);
279}
280
281/**
282 * xmlXPathFreeCompExpr:
283 * @comp: an XPATH comp
284 *
285 * Free up the memory allocated by @comp
286 */
287void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000288xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
289{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000290 xmlXPathStepOpPtr op;
291 int i;
292
293 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000294 return;
295 for (i = 0; i < comp->nbStep; i++) {
296 op = &comp->steps[i];
297 if (op->value4 != NULL) {
298 if (op->op == XPATH_OP_VALUE)
299 xmlXPathFreeObject(op->value4);
300 else
301 xmlFree(op->value4);
302 }
303 if (op->value5 != NULL)
304 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000305 }
306 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000307 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000308 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000309#ifdef DEBUG_EVAL_COUNTS
310 if (comp->string != NULL) {
311 xmlFree(comp->string);
312 }
313#endif
314
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000315 xmlFree(comp);
316}
317
318/**
319 * xmlXPathCompExprAdd:
320 * @comp: the compiled expression
321 * @ch1: first child index
322 * @ch2: second child index
323 * @op: an op
324 * @value: the first int value
325 * @value2: the second int value
326 * @value3: the third int value
327 * @value4: the first string value
328 * @value5: the second string value
329 *
330 * Add an step to an XPath Compiled Expression
331 *
332 * Returns -1 in case of failure, the index otherwise
333 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000334static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000335xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
336 xmlXPathOp op, int value,
337 int value2, int value3, void *value4, void *value5) {
338 if (comp->nbStep >= comp->maxStep) {
339 xmlXPathStepOp *real;
340
341 comp->maxStep *= 2;
342 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
343 comp->maxStep * sizeof(xmlXPathStepOp));
344 if (real == NULL) {
345 comp->maxStep /= 2;
346 xmlGenericError(xmlGenericErrorContext,
347 "xmlXPathCompExprAdd : realloc failed\n");
348 return(-1);
349 }
350 comp->steps = real;
351 }
352 comp->last = comp->nbStep;
353 comp->steps[comp->nbStep].ch1 = ch1;
354 comp->steps[comp->nbStep].ch2 = ch2;
355 comp->steps[comp->nbStep].op = op;
356 comp->steps[comp->nbStep].value = value;
357 comp->steps[comp->nbStep].value2 = value2;
358 comp->steps[comp->nbStep].value3 = value3;
359 comp->steps[comp->nbStep].value4 = value4;
360 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000361 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000362 return(comp->nbStep++);
363}
364
Daniel Veillardf06307e2001-07-03 10:35:50 +0000365/**
366 * xmlXPathCompSwap:
367 * @comp: the compiled expression
368 * @op: operation index
369 *
370 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000371 */
372static void
373xmlXPathCompSwap(xmlXPathStepOpPtr op) {
374 int tmp;
375
Daniel Veillard81463942001-10-16 12:34:39 +0000376#ifdef LIBXML_THREADS_ENABLED
377 /*
378 * Since this manipulates possibly shared variables, this is
379 * disable if one detects that the library is used in a multithreaded
380 * application
381 */
382 if (xmlXPathDisableOptimizer)
383 return;
384#endif
385
Daniel Veillardf06307e2001-07-03 10:35:50 +0000386 tmp = op->ch1;
387 op->ch1 = op->ch2;
388 op->ch2 = tmp;
389}
390
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000391#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
392 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
393 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000394#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
395 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
396 (op), (val), (val2), (val3), (val4), (val5))
397
398#define PUSH_LEAVE_EXPR(op, val, val2) \
399xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
400
401#define PUSH_UNARY_EXPR(op, ch, val, val2) \
402xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
403
404#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
405xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
406
407/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000408 * *
409 * Debugging related functions *
410 * *
411 ************************************************************************/
412
413#define TODO \
414 xmlGenericError(xmlGenericErrorContext, \
415 "Unimplemented block at %s:%d\n", \
416 __FILE__, __LINE__);
417
418#define STRANGE \
419 xmlGenericError(xmlGenericErrorContext, \
420 "Internal error at %s:%d\n", \
421 __FILE__, __LINE__);
422
423#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000424static void
425xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000426 int i;
427 char shift[100];
428
429 for (i = 0;((i < depth) && (i < 25));i++)
430 shift[2 * i] = shift[2 * i + 1] = ' ';
431 shift[2 * i] = shift[2 * i + 1] = 0;
432 if (cur == NULL) {
433 fprintf(output, shift);
434 fprintf(output, "Node is NULL !\n");
435 return;
436
437 }
438
439 if ((cur->type == XML_DOCUMENT_NODE) ||
440 (cur->type == XML_HTML_DOCUMENT_NODE)) {
441 fprintf(output, shift);
442 fprintf(output, " /\n");
443 } else if (cur->type == XML_ATTRIBUTE_NODE)
444 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
445 else
446 xmlDebugDumpOneNode(output, cur, depth);
447}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000448static void
449xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000450 xmlNodePtr tmp;
451 int i;
452 char shift[100];
453
454 for (i = 0;((i < depth) && (i < 25));i++)
455 shift[2 * i] = shift[2 * i + 1] = ' ';
456 shift[2 * i] = shift[2 * i + 1] = 0;
457 if (cur == NULL) {
458 fprintf(output, shift);
459 fprintf(output, "Node is NULL !\n");
460 return;
461
462 }
463
464 while (cur != NULL) {
465 tmp = cur;
466 cur = cur->next;
467 xmlDebugDumpOneNode(output, tmp, depth);
468 }
469}
Owen Taylor3473f882001-02-23 17:55:21 +0000470
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000471static void
472xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000473 int i;
474 char shift[100];
475
476 for (i = 0;((i < depth) && (i < 25));i++)
477 shift[2 * i] = shift[2 * i + 1] = ' ';
478 shift[2 * i] = shift[2 * i + 1] = 0;
479
480 if (cur == NULL) {
481 fprintf(output, shift);
482 fprintf(output, "NodeSet is NULL !\n");
483 return;
484
485 }
486
Daniel Veillard911f49a2001-04-07 15:39:35 +0000487 if (cur != NULL) {
488 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
489 for (i = 0;i < cur->nodeNr;i++) {
490 fprintf(output, shift);
491 fprintf(output, "%d", i + 1);
492 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
493 }
Owen Taylor3473f882001-02-23 17:55:21 +0000494 }
495}
496
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000497static void
498xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000499 int i;
500 char shift[100];
501
502 for (i = 0;((i < depth) && (i < 25));i++)
503 shift[2 * i] = shift[2 * i + 1] = ' ';
504 shift[2 * i] = shift[2 * i + 1] = 0;
505
506 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
507 fprintf(output, shift);
508 fprintf(output, "Value Tree is NULL !\n");
509 return;
510
511 }
512
513 fprintf(output, shift);
514 fprintf(output, "%d", i + 1);
515 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
516}
Owen Taylor3473f882001-02-23 17:55:21 +0000517#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000518static void
519xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000520 int i;
521 char shift[100];
522
523 for (i = 0;((i < depth) && (i < 25));i++)
524 shift[2 * i] = shift[2 * i + 1] = ' ';
525 shift[2 * i] = shift[2 * i + 1] = 0;
526
527 if (cur == NULL) {
528 fprintf(output, shift);
529 fprintf(output, "LocationSet is NULL !\n");
530 return;
531
532 }
533
534 for (i = 0;i < cur->locNr;i++) {
535 fprintf(output, shift);
536 fprintf(output, "%d : ", i + 1);
537 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
538 }
539}
Daniel Veillard017b1082001-06-21 11:20:21 +0000540#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000541
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000542/**
543 * xmlXPathDebugDumpObject:
544 * @output: the FILE * to dump the output
545 * @cur: the object to inspect
546 * @depth: indentation level
547 *
548 * Dump the content of the object for debugging purposes
549 */
550void
551xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000552 int i;
553 char shift[100];
554
555 for (i = 0;((i < depth) && (i < 25));i++)
556 shift[2 * i] = shift[2 * i + 1] = ' ';
557 shift[2 * i] = shift[2 * i + 1] = 0;
558
559 fprintf(output, shift);
560
561 if (cur == NULL) {
562 fprintf(output, "Object is empty (NULL)\n");
563 return;
564 }
565 switch(cur->type) {
566 case XPATH_UNDEFINED:
567 fprintf(output, "Object is uninitialized\n");
568 break;
569 case XPATH_NODESET:
570 fprintf(output, "Object is a Node Set :\n");
571 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
572 break;
573 case XPATH_XSLT_TREE:
574 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000575 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000576 break;
577 case XPATH_BOOLEAN:
578 fprintf(output, "Object is a Boolean : ");
579 if (cur->boolval) fprintf(output, "true\n");
580 else fprintf(output, "false\n");
581 break;
582 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000583 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000584 case 1:
585 fprintf(output, "Object is a number : +Infinity\n");
586 break;
587 case -1:
588 fprintf(output, "Object is a number : -Infinity\n");
589 break;
590 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000591 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000592 fprintf(output, "Object is a number : NaN\n");
593 } else {
594 fprintf(output, "Object is a number : %0g\n", cur->floatval);
595 }
596 }
Owen Taylor3473f882001-02-23 17:55:21 +0000597 break;
598 case XPATH_STRING:
599 fprintf(output, "Object is a string : ");
600 xmlDebugDumpString(output, cur->stringval);
601 fprintf(output, "\n");
602 break;
603 case XPATH_POINT:
604 fprintf(output, "Object is a point : index %d in node", cur->index);
605 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
606 fprintf(output, "\n");
607 break;
608 case XPATH_RANGE:
609 if ((cur->user2 == NULL) ||
610 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
611 fprintf(output, "Object is a collapsed range :\n");
612 fprintf(output, shift);
613 if (cur->index >= 0)
614 fprintf(output, "index %d in ", cur->index);
615 fprintf(output, "node\n");
616 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
617 depth + 1);
618 } else {
619 fprintf(output, "Object is a range :\n");
620 fprintf(output, shift);
621 fprintf(output, "From ");
622 if (cur->index >= 0)
623 fprintf(output, "index %d in ", cur->index);
624 fprintf(output, "node\n");
625 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
626 depth + 1);
627 fprintf(output, shift);
628 fprintf(output, "To ");
629 if (cur->index2 >= 0)
630 fprintf(output, "index %d in ", cur->index2);
631 fprintf(output, "node\n");
632 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
633 depth + 1);
634 fprintf(output, "\n");
635 }
636 break;
637 case XPATH_LOCATIONSET:
638#if defined(LIBXML_XPTR_ENABLED)
639 fprintf(output, "Object is a Location Set:\n");
640 xmlXPathDebugDumpLocationSet(output,
641 (xmlLocationSetPtr) cur->user, depth);
642#endif
643 break;
644 case XPATH_USERS:
645 fprintf(output, "Object is user defined\n");
646 break;
647 }
648}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000649
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000650static void
651xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000652 xmlXPathStepOpPtr op, int depth) {
653 int i;
654 char shift[100];
655
656 for (i = 0;((i < depth) && (i < 25));i++)
657 shift[2 * i] = shift[2 * i + 1] = ' ';
658 shift[2 * i] = shift[2 * i + 1] = 0;
659
660 fprintf(output, shift);
661 if (op == NULL) {
662 fprintf(output, "Step is NULL\n");
663 return;
664 }
665 switch (op->op) {
666 case XPATH_OP_END:
667 fprintf(output, "END"); break;
668 case XPATH_OP_AND:
669 fprintf(output, "AND"); break;
670 case XPATH_OP_OR:
671 fprintf(output, "OR"); break;
672 case XPATH_OP_EQUAL:
673 if (op->value)
674 fprintf(output, "EQUAL =");
675 else
676 fprintf(output, "EQUAL !=");
677 break;
678 case XPATH_OP_CMP:
679 if (op->value)
680 fprintf(output, "CMP <");
681 else
682 fprintf(output, "CMP >");
683 if (!op->value2)
684 fprintf(output, "=");
685 break;
686 case XPATH_OP_PLUS:
687 if (op->value == 0)
688 fprintf(output, "PLUS -");
689 else if (op->value == 1)
690 fprintf(output, "PLUS +");
691 else if (op->value == 2)
692 fprintf(output, "PLUS unary -");
693 else if (op->value == 3)
694 fprintf(output, "PLUS unary - -");
695 break;
696 case XPATH_OP_MULT:
697 if (op->value == 0)
698 fprintf(output, "MULT *");
699 else if (op->value == 1)
700 fprintf(output, "MULT div");
701 else
702 fprintf(output, "MULT mod");
703 break;
704 case XPATH_OP_UNION:
705 fprintf(output, "UNION"); break;
706 case XPATH_OP_ROOT:
707 fprintf(output, "ROOT"); break;
708 case XPATH_OP_NODE:
709 fprintf(output, "NODE"); break;
710 case XPATH_OP_RESET:
711 fprintf(output, "RESET"); break;
712 case XPATH_OP_SORT:
713 fprintf(output, "SORT"); break;
714 case XPATH_OP_COLLECT: {
715 xmlXPathAxisVal axis = op->value;
716 xmlXPathTestVal test = op->value2;
717 xmlXPathTypeVal type = op->value3;
718 const xmlChar *prefix = op->value4;
719 const xmlChar *name = op->value5;
720
721 fprintf(output, "COLLECT ");
722 switch (axis) {
723 case AXIS_ANCESTOR:
724 fprintf(output, " 'ancestors' "); break;
725 case AXIS_ANCESTOR_OR_SELF:
726 fprintf(output, " 'ancestors-or-self' "); break;
727 case AXIS_ATTRIBUTE:
728 fprintf(output, " 'attributes' "); break;
729 case AXIS_CHILD:
730 fprintf(output, " 'child' "); break;
731 case AXIS_DESCENDANT:
732 fprintf(output, " 'descendant' "); break;
733 case AXIS_DESCENDANT_OR_SELF:
734 fprintf(output, " 'descendant-or-self' "); break;
735 case AXIS_FOLLOWING:
736 fprintf(output, " 'following' "); break;
737 case AXIS_FOLLOWING_SIBLING:
738 fprintf(output, " 'following-siblings' "); break;
739 case AXIS_NAMESPACE:
740 fprintf(output, " 'namespace' "); break;
741 case AXIS_PARENT:
742 fprintf(output, " 'parent' "); break;
743 case AXIS_PRECEDING:
744 fprintf(output, " 'preceding' "); break;
745 case AXIS_PRECEDING_SIBLING:
746 fprintf(output, " 'preceding-sibling' "); break;
747 case AXIS_SELF:
748 fprintf(output, " 'self' "); break;
749 }
750 switch (test) {
751 case NODE_TEST_NONE:
752 fprintf(output, "'none' "); break;
753 case NODE_TEST_TYPE:
754 fprintf(output, "'type' "); break;
755 case NODE_TEST_PI:
756 fprintf(output, "'PI' "); break;
757 case NODE_TEST_ALL:
758 fprintf(output, "'all' "); break;
759 case NODE_TEST_NS:
760 fprintf(output, "'namespace' "); break;
761 case NODE_TEST_NAME:
762 fprintf(output, "'name' "); break;
763 }
764 switch (type) {
765 case NODE_TYPE_NODE:
766 fprintf(output, "'node' "); break;
767 case NODE_TYPE_COMMENT:
768 fprintf(output, "'comment' "); break;
769 case NODE_TYPE_TEXT:
770 fprintf(output, "'text' "); break;
771 case NODE_TYPE_PI:
772 fprintf(output, "'PI' "); break;
773 }
774 if (prefix != NULL)
775 fprintf(output, "%s:", prefix);
776 if (name != NULL)
777 fprintf(output, "%s", name);
778 break;
779
780 }
781 case XPATH_OP_VALUE: {
782 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
783
784 fprintf(output, "ELEM ");
785 xmlXPathDebugDumpObject(output, object, 0);
786 goto finish;
787 }
788 case XPATH_OP_VARIABLE: {
789 const xmlChar *prefix = op->value5;
790 const xmlChar *name = op->value4;
791
792 if (prefix != NULL)
793 fprintf(output, "VARIABLE %s:%s", prefix, name);
794 else
795 fprintf(output, "VARIABLE %s", name);
796 break;
797 }
798 case XPATH_OP_FUNCTION: {
799 int nbargs = op->value;
800 const xmlChar *prefix = op->value5;
801 const xmlChar *name = op->value4;
802
803 if (prefix != NULL)
804 fprintf(output, "FUNCTION %s:%s(%d args)",
805 prefix, name, nbargs);
806 else
807 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
808 break;
809 }
810 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
811 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000812 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000813#ifdef LIBXML_XPTR_ENABLED
814 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
815#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000816 default:
817 fprintf(output, "UNKNOWN %d\n", op->op); return;
818 }
819 fprintf(output, "\n");
820finish:
821 if (op->ch1 >= 0)
822 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
823 if (op->ch2 >= 0)
824 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
825}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000826
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000827/**
828 * xmlXPathDebugDumpCompExpr:
829 * @output: the FILE * for the output
830 * @comp: the precompiled XPath expression
831 * @depth: the indentation level.
832 *
833 * Dumps the tree of the compiled XPath expression.
834 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000835void
836xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
837 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000838 int i;
839 char shift[100];
840
841 for (i = 0;((i < depth) && (i < 25));i++)
842 shift[2 * i] = shift[2 * i + 1] = ' ';
843 shift[2 * i] = shift[2 * i + 1] = 0;
844
845 fprintf(output, shift);
846
847 if (comp == NULL) {
848 fprintf(output, "Compiled Expression is NULL\n");
849 return;
850 }
851 fprintf(output, "Compiled Expression : %d elements\n",
852 comp->nbStep);
853 i = comp->last;
854 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
855}
Daniel Veillard017b1082001-06-21 11:20:21 +0000856#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000857
858/************************************************************************
859 * *
860 * Parser stacks related functions and macros *
861 * *
862 ************************************************************************/
863
864/*
865 * Generic function for accessing stacks in the Parser Context
866 */
867
868#define PUSH_AND_POP(type, name) \
869extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
870 if (ctxt->name##Nr >= ctxt->name##Max) { \
871 ctxt->name##Max *= 2; \
872 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
873 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
874 if (ctxt->name##Tab == NULL) { \
875 xmlGenericError(xmlGenericErrorContext, \
876 "realloc failed !\n"); \
877 return(0); \
878 } \
879 } \
880 ctxt->name##Tab[ctxt->name##Nr] = value; \
881 ctxt->name = value; \
882 return(ctxt->name##Nr++); \
883} \
884extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
885 type ret; \
886 if (ctxt->name##Nr <= 0) return(0); \
887 ctxt->name##Nr--; \
888 if (ctxt->name##Nr > 0) \
889 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
890 else \
891 ctxt->name = NULL; \
892 ret = ctxt->name##Tab[ctxt->name##Nr]; \
893 ctxt->name##Tab[ctxt->name##Nr] = 0; \
894 return(ret); \
895} \
896
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000897/**
898 * valuePop:
899 * @ctxt: an XPath evaluation context
900 *
901 * Pops the top XPath object from the value stack
902 *
903 * Returns the XPath object just removed
904 */
905/**
906 * valuePush:
907 * @ctxt: an XPath evaluation context
908 * @value: the XPath object
909 *
910 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000911 *
912 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000913 */
Owen Taylor3473f882001-02-23 17:55:21 +0000914PUSH_AND_POP(xmlXPathObjectPtr, value)
915
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000916/**
917 * xmlXPathPopBoolean:
918 * @ctxt: an XPath parser context
919 *
920 * Pops a boolean from the stack, handling conversion if needed.
921 * Check error with #xmlXPathCheckError.
922 *
923 * Returns the boolean
924 */
925int
926xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
927 xmlXPathObjectPtr obj;
928 int ret;
929
930 obj = valuePop(ctxt);
931 if (obj == NULL) {
932 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
933 return(0);
934 }
935 ret = xmlXPathCastToBoolean(obj);
936 xmlXPathFreeObject(obj);
937 return(ret);
938}
939
940/**
941 * xmlXPathPopNumber:
942 * @ctxt: an XPath parser context
943 *
944 * Pops a number from the stack, handling conversion if needed.
945 * Check error with #xmlXPathCheckError.
946 *
947 * Returns the number
948 */
949double
950xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
951 xmlXPathObjectPtr obj;
952 double ret;
953
954 obj = valuePop(ctxt);
955 if (obj == NULL) {
956 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
957 return(0);
958 }
959 ret = xmlXPathCastToNumber(obj);
960 xmlXPathFreeObject(obj);
961 return(ret);
962}
963
964/**
965 * xmlXPathPopString:
966 * @ctxt: an XPath parser context
967 *
968 * Pops a string from the stack, handling conversion if needed.
969 * Check error with #xmlXPathCheckError.
970 *
971 * Returns the string
972 */
973xmlChar *
974xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
975 xmlXPathObjectPtr obj;
976 xmlChar * ret;
977
978 obj = valuePop(ctxt);
979 if (obj == NULL) {
980 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
981 return(NULL);
982 }
983 ret = xmlXPathCastToString(obj);
984 /* TODO: needs refactoring somewhere else */
985 if (obj->stringval == ret)
986 obj->stringval = NULL;
987 xmlXPathFreeObject(obj);
988 return(ret);
989}
990
991/**
992 * xmlXPathPopNodeSet:
993 * @ctxt: an XPath parser context
994 *
995 * Pops a node-set from the stack, handling conversion if needed.
996 * Check error with #xmlXPathCheckError.
997 *
998 * Returns the node-set
999 */
1000xmlNodeSetPtr
1001xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1002 xmlXPathObjectPtr obj;
1003 xmlNodeSetPtr ret;
1004
1005 if (ctxt->value == NULL) {
1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1007 return(NULL);
1008 }
1009 if (!xmlXPathStackIsNodeSet(ctxt)) {
1010 xmlXPathSetTypeError(ctxt);
1011 return(NULL);
1012 }
1013 obj = valuePop(ctxt);
1014 ret = obj->nodesetval;
1015 xmlXPathFreeNodeSetList(obj);
1016 return(ret);
1017}
1018
1019/**
1020 * xmlXPathPopExternal:
1021 * @ctxt: an XPath parser context
1022 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001023 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001024 * Check error with #xmlXPathCheckError.
1025 *
1026 * Returns the object
1027 */
1028void *
1029xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1030 xmlXPathObjectPtr obj;
1031 void * ret;
1032
1033 if (ctxt->value == NULL) {
1034 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1035 return(NULL);
1036 }
1037 if (ctxt->value->type != XPATH_USERS) {
1038 xmlXPathSetTypeError(ctxt);
1039 return(NULL);
1040 }
1041 obj = valuePop(ctxt);
1042 ret = obj->user;
1043 xmlXPathFreeObject(obj);
1044 return(ret);
1045}
1046
Owen Taylor3473f882001-02-23 17:55:21 +00001047/*
1048 * Macros for accessing the content. Those should be used only by the parser,
1049 * and not exported.
1050 *
1051 * Dirty macros, i.e. one need to make assumption on the context to use them
1052 *
1053 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1054 * CUR returns the current xmlChar value, i.e. a 8 bit value
1055 * in ISO-Latin or UTF-8.
1056 * This should be used internally by the parser
1057 * only to compare to ASCII values otherwise it would break when
1058 * running with UTF-8 encoding.
1059 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1060 * to compare on ASCII based substring.
1061 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1062 * strings within the parser.
1063 * CURRENT Returns the current char value, with the full decoding of
1064 * UTF-8 if we are using this mode. It returns an int.
1065 * NEXT Skip to the next character, this does the proper decoding
1066 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1067 * It returns the pointer to the current xmlChar.
1068 */
1069
1070#define CUR (*ctxt->cur)
1071#define SKIP(val) ctxt->cur += (val)
1072#define NXT(val) ctxt->cur[(val)]
1073#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001074#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1075
1076#define COPY_BUF(l,b,i,v) \
1077 if (l == 1) b[i++] = (xmlChar) v; \
1078 else i += xmlCopyChar(l,&b[i],v)
1079
1080#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001081
1082#define SKIP_BLANKS \
1083 while (IS_BLANK(*(ctxt->cur))) NEXT
1084
1085#define CURRENT (*ctxt->cur)
1086#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1087
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001088
1089#ifndef DBL_DIG
1090#define DBL_DIG 16
1091#endif
1092#ifndef DBL_EPSILON
1093#define DBL_EPSILON 1E-9
1094#endif
1095
1096#define UPPER_DOUBLE 1E9
1097#define LOWER_DOUBLE 1E-5
1098
1099#define INTEGER_DIGITS DBL_DIG
1100#define FRACTION_DIGITS (DBL_DIG + 1)
1101#define EXPONENT_DIGITS (3 + 2)
1102
1103/**
1104 * xmlXPathFormatNumber:
1105 * @number: number to format
1106 * @buffer: output buffer
1107 * @buffersize: size of output buffer
1108 *
1109 * Convert the number into a string representation.
1110 */
1111static void
1112xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1113{
Daniel Veillardcda96922001-08-21 10:56:31 +00001114 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001115 case 1:
1116 if (buffersize > (int)sizeof("+Infinity"))
1117 sprintf(buffer, "+Infinity");
1118 break;
1119 case -1:
1120 if (buffersize > (int)sizeof("-Infinity"))
1121 sprintf(buffer, "-Infinity");
1122 break;
1123 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001124 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001125 if (buffersize > (int)sizeof("NaN"))
1126 sprintf(buffer, "NaN");
1127 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001128 /* 3 is sign, decimal point, and terminating zero */
1129 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1130 int integer_place, fraction_place;
1131 char *ptr;
1132 char *after_fraction;
1133 double absolute_value;
1134 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001135
Bjorn Reese70a9da52001-04-21 16:57:29 +00001136 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001137
Bjorn Reese70a9da52001-04-21 16:57:29 +00001138 /*
1139 * First choose format - scientific or regular floating point.
1140 * In either case, result is in work, and after_fraction points
1141 * just past the fractional part.
1142 */
1143 if ( ((absolute_value > UPPER_DOUBLE) ||
1144 (absolute_value < LOWER_DOUBLE)) &&
1145 (absolute_value != 0.0) ) {
1146 /* Use scientific notation */
1147 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1148 fraction_place = DBL_DIG - 1;
1149 snprintf(work, sizeof(work),"%*.*e",
1150 integer_place, fraction_place, number);
1151 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001152 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001153 else {
1154 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001155 if (absolute_value > 0.0)
1156 integer_place = 1 + (int)log10(absolute_value);
1157 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001158 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001159 fraction_place = (integer_place > 0)
1160 ? DBL_DIG - integer_place
1161 : DBL_DIG;
1162 size = snprintf(work, sizeof(work), "%0.*f",
1163 fraction_place, number);
1164 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001165 }
1166
Bjorn Reese70a9da52001-04-21 16:57:29 +00001167 /* Remove fractional trailing zeroes */
1168 ptr = after_fraction;
1169 while (*(--ptr) == '0')
1170 ;
1171 if (*ptr != '.')
1172 ptr++;
1173 strcpy(ptr, after_fraction);
1174
1175 /* Finally copy result back to caller */
1176 size = strlen(work) + 1;
1177 if (size > buffersize) {
1178 work[buffersize - 1] = 0;
1179 size = buffersize;
1180 }
1181 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001182 }
1183 break;
1184 }
1185}
1186
Owen Taylor3473f882001-02-23 17:55:21 +00001187/************************************************************************
1188 * *
1189 * Error handling routines *
1190 * *
1191 ************************************************************************/
1192
1193
Daniel Veillardb44025c2001-10-11 22:55:55 +00001194static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001195 "Ok",
1196 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001197 "Unfinished literal",
1198 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001199 "Expected $ for variable reference",
1200 "Undefined variable",
1201 "Invalid predicate",
1202 "Invalid expression",
1203 "Missing closing curly brace",
1204 "Unregistered function",
1205 "Invalid operand",
1206 "Invalid type",
1207 "Invalid number of arguments",
1208 "Invalid context size",
1209 "Invalid context position",
1210 "Memory allocation error",
1211 "Syntax error",
1212 "Resource error",
1213 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001214 "Undefined namespace prefix",
1215 "Encoding error",
1216 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001217};
1218
1219/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001220 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001221 * @ctxt: the XPath Parser context
1222 * @file: the file name
1223 * @line: the line number
1224 * @no: the error number
1225 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001226 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001227 */
1228void
1229xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1230 int line, int no) {
1231 int n;
1232 const xmlChar *cur;
1233 const xmlChar *base;
1234
1235 xmlGenericError(xmlGenericErrorContext,
1236 "Error %s:%d: %s\n", file, line,
1237 xmlXPathErrorMessages[no]);
1238
1239 cur = ctxt->cur;
1240 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001241 if ((cur == NULL) || (base == NULL))
1242 return;
1243
Owen Taylor3473f882001-02-23 17:55:21 +00001244 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1245 cur--;
1246 }
1247 n = 0;
1248 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1249 cur--;
1250 if ((*cur == '\n') || (*cur == '\r')) cur++;
1251 base = cur;
1252 n = 0;
1253 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1254 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1255 n++;
1256 }
1257 xmlGenericError(xmlGenericErrorContext, "\n");
1258 cur = ctxt->cur;
1259 while ((*cur == '\n') || (*cur == '\r'))
1260 cur--;
1261 n = 0;
1262 while ((cur != base) && (n++ < 80)) {
1263 xmlGenericError(xmlGenericErrorContext, " ");
1264 base++;
1265 }
1266 xmlGenericError(xmlGenericErrorContext,"^\n");
1267}
1268
1269
1270/************************************************************************
1271 * *
1272 * Routines to handle NodeSets *
1273 * *
1274 ************************************************************************/
1275
1276/**
1277 * xmlXPathCmpNodes:
1278 * @node1: the first node
1279 * @node2: the second node
1280 *
1281 * Compare two nodes w.r.t document order
1282 *
1283 * Returns -2 in case of error 1 if first point < second point, 0 if
1284 * that's the same node, -1 otherwise
1285 */
1286int
1287xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1288 int depth1, depth2;
1289 xmlNodePtr cur, root;
1290
1291 if ((node1 == NULL) || (node2 == NULL))
1292 return(-2);
1293 /*
1294 * a couple of optimizations which will avoid computations in most cases
1295 */
1296 if (node1 == node2)
1297 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001298 if ((node1->type == XML_NAMESPACE_DECL) ||
1299 (node2->type == XML_NAMESPACE_DECL))
1300 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001301 if (node1 == node2->prev)
1302 return(1);
1303 if (node1 == node2->next)
1304 return(-1);
1305
1306 /*
1307 * compute depth to root
1308 */
1309 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1310 if (cur == node1)
1311 return(1);
1312 depth2++;
1313 }
1314 root = cur;
1315 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1316 if (cur == node2)
1317 return(-1);
1318 depth1++;
1319 }
1320 /*
1321 * Distinct document (or distinct entities :-( ) case.
1322 */
1323 if (root != cur) {
1324 return(-2);
1325 }
1326 /*
1327 * get the nearest common ancestor.
1328 */
1329 while (depth1 > depth2) {
1330 depth1--;
1331 node1 = node1->parent;
1332 }
1333 while (depth2 > depth1) {
1334 depth2--;
1335 node2 = node2->parent;
1336 }
1337 while (node1->parent != node2->parent) {
1338 node1 = node1->parent;
1339 node2 = node2->parent;
1340 /* should not happen but just in case ... */
1341 if ((node1 == NULL) || (node2 == NULL))
1342 return(-2);
1343 }
1344 /*
1345 * Find who's first.
1346 */
1347 if (node1 == node2->next)
1348 return(-1);
1349 for (cur = node1->next;cur != NULL;cur = cur->next)
1350 if (cur == node2)
1351 return(1);
1352 return(-1); /* assume there is no sibling list corruption */
1353}
1354
1355/**
1356 * xmlXPathNodeSetSort:
1357 * @set: the node set
1358 *
1359 * Sort the node set in document order
1360 */
1361void
1362xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001363 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001364 xmlNodePtr tmp;
1365
1366 if (set == NULL)
1367 return;
1368
1369 /* Use Shell's sort to sort the node-set */
1370 len = set->nodeNr;
1371 for (incr = len / 2; incr > 0; incr /= 2) {
1372 for (i = incr; i < len; i++) {
1373 j = i - incr;
1374 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001375 if (xmlXPathCmpNodes(set->nodeTab[j],
1376 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001377 tmp = set->nodeTab[j];
1378 set->nodeTab[j] = set->nodeTab[j + incr];
1379 set->nodeTab[j + incr] = tmp;
1380 j -= incr;
1381 } else
1382 break;
1383 }
1384 }
1385 }
1386}
1387
1388#define XML_NODESET_DEFAULT 10
1389/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001390 * xmlXPathNodeSetDupNs:
1391 * @node: the parent node of the namespace XPath node
1392 * @ns: the libxml namespace declaration node.
1393 *
1394 * Namespace node in libxml don't match the XPath semantic. In a node set
1395 * the namespace nodes are duplicated and the next pointer is set to the
1396 * parent node in the XPath semantic.
1397 *
1398 * Returns the newly created object.
1399 */
1400static xmlNodePtr
1401xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1402 xmlNsPtr cur;
1403
1404 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1405 return(NULL);
1406 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1407 return((xmlNodePtr) ns);
1408
1409 /*
1410 * Allocate a new Namespace and fill the fields.
1411 */
1412 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1413 if (cur == NULL) {
1414 xmlGenericError(xmlGenericErrorContext,
1415 "xmlXPathNodeSetDupNs : malloc failed\n");
1416 return(NULL);
1417 }
1418 memset(cur, 0, sizeof(xmlNs));
1419 cur->type = XML_NAMESPACE_DECL;
1420 if (ns->href != NULL)
1421 cur->href = xmlStrdup(ns->href);
1422 if (ns->prefix != NULL)
1423 cur->prefix = xmlStrdup(ns->prefix);
1424 cur->next = (xmlNsPtr) node;
1425 return((xmlNodePtr) cur);
1426}
1427
1428/**
1429 * xmlXPathNodeSetFreeNs:
1430 * @ns: the XPath namespace node found in a nodeset.
1431 *
1432 * Namespace node in libxml don't match the XPath semantic. In a node set
1433 * the namespace nodes are duplicated and the next pointer is set to the
1434 * parent node in the XPath semantic. Check if such a node need to be freed
1435 */
1436static void
1437xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1438 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1439 return;
1440
1441 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1442 if (ns->href != NULL)
1443 xmlFree((xmlChar *)ns->href);
1444 if (ns->prefix != NULL)
1445 xmlFree((xmlChar *)ns->prefix);
1446 xmlFree(ns);
1447 }
1448}
1449
1450/**
Owen Taylor3473f882001-02-23 17:55:21 +00001451 * xmlXPathNodeSetCreate:
1452 * @val: an initial xmlNodePtr, or NULL
1453 *
1454 * Create a new xmlNodeSetPtr of type double and of value @val
1455 *
1456 * Returns the newly created object.
1457 */
1458xmlNodeSetPtr
1459xmlXPathNodeSetCreate(xmlNodePtr val) {
1460 xmlNodeSetPtr ret;
1461
1462 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1463 if (ret == NULL) {
1464 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001465 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001466 return(NULL);
1467 }
1468 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1469 if (val != NULL) {
1470 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1471 sizeof(xmlNodePtr));
1472 if (ret->nodeTab == NULL) {
1473 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001474 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001475 return(NULL);
1476 }
1477 memset(ret->nodeTab, 0 ,
1478 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1479 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001480 if (val->type == XML_NAMESPACE_DECL) {
1481 xmlNsPtr ns = (xmlNsPtr) val;
1482
1483 ret->nodeTab[ret->nodeNr++] =
1484 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1485 } else
1486 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001487 }
1488 return(ret);
1489}
1490
1491/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001492 * xmlXPathNodeSetContains:
1493 * @cur: the node-set
1494 * @val: the node
1495 *
1496 * checks whether @cur contains @val
1497 *
1498 * Returns true (1) if @cur contains @val, false (0) otherwise
1499 */
1500int
1501xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1502 int i;
1503
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001504 if (val->type == XML_NAMESPACE_DECL) {
1505 for (i = 0; i < cur->nodeNr; i++) {
1506 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1507 xmlNsPtr ns1, ns2;
1508
1509 ns1 = (xmlNsPtr) val;
1510 ns2 = (xmlNsPtr) cur->nodeTab[i];
1511 if (ns1 == ns2)
1512 return(1);
1513 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1514 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1515 return(1);
1516 }
1517 }
1518 } else {
1519 for (i = 0; i < cur->nodeNr; i++) {
1520 if (cur->nodeTab[i] == val)
1521 return(1);
1522 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001523 }
1524 return(0);
1525}
1526
1527/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001528 * xmlXPathNodeSetAddNs:
1529 * @cur: the initial node set
1530 * @node: the hosting node
1531 * @ns: a the namespace node
1532 *
1533 * add a new namespace node to an existing NodeSet
1534 */
1535static void
1536xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1537 int i;
1538
1539 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1540 (node->type != XML_ELEMENT_NODE))
1541 return;
1542
1543 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1544 /*
1545 * check against doublons
1546 */
1547 for (i = 0;i < cur->nodeNr;i++) {
1548 if ((cur->nodeTab[i] != NULL) &&
1549 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
1550 (cur->nodeTab[i]->next == node) &&
1551 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1552 return;
1553 }
1554
1555 /*
1556 * grow the nodeTab if needed
1557 */
1558 if (cur->nodeMax == 0) {
1559 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1560 sizeof(xmlNodePtr));
1561 if (cur->nodeTab == NULL) {
1562 xmlGenericError(xmlGenericErrorContext,
1563 "xmlXPathNodeSetAdd: out of memory\n");
1564 return;
1565 }
1566 memset(cur->nodeTab, 0 ,
1567 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1568 cur->nodeMax = XML_NODESET_DEFAULT;
1569 } else if (cur->nodeNr == cur->nodeMax) {
1570 xmlNodePtr *temp;
1571
1572 cur->nodeMax *= 2;
1573 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1574 sizeof(xmlNodePtr));
1575 if (temp == NULL) {
1576 xmlGenericError(xmlGenericErrorContext,
1577 "xmlXPathNodeSetAdd: out of memory\n");
1578 return;
1579 }
1580 cur->nodeTab = temp;
1581 }
1582 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1583}
1584
1585/**
Owen Taylor3473f882001-02-23 17:55:21 +00001586 * xmlXPathNodeSetAdd:
1587 * @cur: the initial node set
1588 * @val: a new xmlNodePtr
1589 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001590 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001591 */
1592void
1593xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1594 int i;
1595
1596 if (val == NULL) return;
1597
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001598 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001599 /*
1600 * check against doublons
1601 */
1602 for (i = 0;i < cur->nodeNr;i++)
1603 if (cur->nodeTab[i] == val) return;
1604
1605 /*
1606 * grow the nodeTab if needed
1607 */
1608 if (cur->nodeMax == 0) {
1609 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1610 sizeof(xmlNodePtr));
1611 if (cur->nodeTab == NULL) {
1612 xmlGenericError(xmlGenericErrorContext,
1613 "xmlXPathNodeSetAdd: out of memory\n");
1614 return;
1615 }
1616 memset(cur->nodeTab, 0 ,
1617 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1618 cur->nodeMax = XML_NODESET_DEFAULT;
1619 } else if (cur->nodeNr == cur->nodeMax) {
1620 xmlNodePtr *temp;
1621
1622 cur->nodeMax *= 2;
1623 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1624 sizeof(xmlNodePtr));
1625 if (temp == NULL) {
1626 xmlGenericError(xmlGenericErrorContext,
1627 "xmlXPathNodeSetAdd: out of memory\n");
1628 return;
1629 }
1630 cur->nodeTab = temp;
1631 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001632 if (val->type == XML_NAMESPACE_DECL) {
1633 xmlNsPtr ns = (xmlNsPtr) val;
1634
1635 cur->nodeTab[cur->nodeNr++] =
1636 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1637 } else
1638 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001639}
1640
1641/**
1642 * xmlXPathNodeSetAddUnique:
1643 * @cur: the initial node set
1644 * @val: a new xmlNodePtr
1645 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001646 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001647 * when we are sure the node is not already in the set.
1648 */
1649void
1650xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1651 if (val == NULL) return;
1652
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001653 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001654 /*
1655 * grow the nodeTab if needed
1656 */
1657 if (cur->nodeMax == 0) {
1658 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1659 sizeof(xmlNodePtr));
1660 if (cur->nodeTab == NULL) {
1661 xmlGenericError(xmlGenericErrorContext,
1662 "xmlXPathNodeSetAddUnique: out of memory\n");
1663 return;
1664 }
1665 memset(cur->nodeTab, 0 ,
1666 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1667 cur->nodeMax = XML_NODESET_DEFAULT;
1668 } else if (cur->nodeNr == cur->nodeMax) {
1669 xmlNodePtr *temp;
1670
1671 cur->nodeMax *= 2;
1672 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1673 sizeof(xmlNodePtr));
1674 if (temp == NULL) {
1675 xmlGenericError(xmlGenericErrorContext,
1676 "xmlXPathNodeSetAddUnique: out of memory\n");
1677 return;
1678 }
1679 cur->nodeTab = temp;
1680 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001681 if (val->type == XML_NAMESPACE_DECL) {
1682 xmlNsPtr ns = (xmlNsPtr) val;
1683
1684 cur->nodeTab[cur->nodeNr++] =
1685 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1686 } else
1687 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001688}
1689
1690/**
1691 * xmlXPathNodeSetMerge:
1692 * @val1: the first NodeSet or NULL
1693 * @val2: the second NodeSet
1694 *
1695 * Merges two nodesets, all nodes from @val2 are added to @val1
1696 * if @val1 is NULL, a new set is created and copied from @val2
1697 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001698 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001699 */
1700xmlNodeSetPtr
1701xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001702 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001703
1704 if (val2 == NULL) return(val1);
1705 if (val1 == NULL) {
1706 val1 = xmlXPathNodeSetCreate(NULL);
1707 }
1708
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001709 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001710 initNr = val1->nodeNr;
1711
1712 for (i = 0;i < val2->nodeNr;i++) {
1713 /*
1714 * check against doublons
1715 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001716 skip = 0;
1717 for (j = 0; j < initNr; j++) {
1718 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1719 skip = 1;
1720 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001721 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1722 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1723 xmlNsPtr ns1, ns2;
1724 ns1 = (xmlNsPtr) val1->nodeTab[j];
1725 ns2 = (xmlNsPtr) val2->nodeTab[i];
1726 if ((ns1->next == ns2->next) &&
1727 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1728 skip = 1;
1729 break;
1730 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001731 }
1732 }
1733 if (skip)
1734 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001735
1736 /*
1737 * grow the nodeTab if needed
1738 */
1739 if (val1->nodeMax == 0) {
1740 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1741 sizeof(xmlNodePtr));
1742 if (val1->nodeTab == NULL) {
1743 xmlGenericError(xmlGenericErrorContext,
1744 "xmlXPathNodeSetMerge: out of memory\n");
1745 return(NULL);
1746 }
1747 memset(val1->nodeTab, 0 ,
1748 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1749 val1->nodeMax = XML_NODESET_DEFAULT;
1750 } else if (val1->nodeNr == val1->nodeMax) {
1751 xmlNodePtr *temp;
1752
1753 val1->nodeMax *= 2;
1754 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1755 sizeof(xmlNodePtr));
1756 if (temp == NULL) {
1757 xmlGenericError(xmlGenericErrorContext,
1758 "xmlXPathNodeSetMerge: out of memory\n");
1759 return(NULL);
1760 }
1761 val1->nodeTab = temp;
1762 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001763 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1764 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1765
1766 val1->nodeTab[val1->nodeNr++] =
1767 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1768 } else
1769 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001770 }
1771
1772 return(val1);
1773}
1774
1775/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001776 * xmlXPathNodeSetMergeUnique:
1777 * @val1: the first NodeSet or NULL
1778 * @val2: the second NodeSet
1779 *
1780 * Merges two nodesets, all nodes from @val2 are added to @val1
1781 * if @val1 is NULL, a new set is created and copied from @val2
1782 *
1783 * Returns @val1 once extended or NULL in case of error.
1784 */
1785static xmlNodeSetPtr
1786xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1787 int i, initNr;
1788
1789 if (val2 == NULL) return(val1);
1790 if (val1 == NULL) {
1791 val1 = xmlXPathNodeSetCreate(NULL);
1792 }
1793
1794 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1795 initNr = val1->nodeNr;
1796
1797 for (i = 0;i < val2->nodeNr;i++) {
1798 /*
1799 * grow the nodeTab if needed
1800 */
1801 if (val1->nodeMax == 0) {
1802 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1803 sizeof(xmlNodePtr));
1804 if (val1->nodeTab == NULL) {
1805 xmlGenericError(xmlGenericErrorContext,
1806 "xmlXPathNodeSetMerge: out of memory\n");
1807 return(NULL);
1808 }
1809 memset(val1->nodeTab, 0 ,
1810 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1811 val1->nodeMax = XML_NODESET_DEFAULT;
1812 } else if (val1->nodeNr == val1->nodeMax) {
1813 xmlNodePtr *temp;
1814
1815 val1->nodeMax *= 2;
1816 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1817 sizeof(xmlNodePtr));
1818 if (temp == NULL) {
1819 xmlGenericError(xmlGenericErrorContext,
1820 "xmlXPathNodeSetMerge: out of memory\n");
1821 return(NULL);
1822 }
1823 val1->nodeTab = temp;
1824 }
1825 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1826 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1827
1828 val1->nodeTab[val1->nodeNr++] =
1829 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1830 } else
1831 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1832 }
1833
1834 return(val1);
1835}
1836
1837/**
Owen Taylor3473f882001-02-23 17:55:21 +00001838 * xmlXPathNodeSetDel:
1839 * @cur: the initial node set
1840 * @val: an xmlNodePtr
1841 *
1842 * Removes an xmlNodePtr from an existing NodeSet
1843 */
1844void
1845xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1846 int i;
1847
1848 if (cur == NULL) return;
1849 if (val == NULL) return;
1850
1851 /*
1852 * check against doublons
1853 */
1854 for (i = 0;i < cur->nodeNr;i++)
1855 if (cur->nodeTab[i] == val) break;
1856
1857 if (i >= cur->nodeNr) {
1858#ifdef DEBUG
1859 xmlGenericError(xmlGenericErrorContext,
1860 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1861 val->name);
1862#endif
1863 return;
1864 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001865 if ((cur->nodeTab[i] != NULL) &&
1866 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1867 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001868 cur->nodeNr--;
1869 for (;i < cur->nodeNr;i++)
1870 cur->nodeTab[i] = cur->nodeTab[i + 1];
1871 cur->nodeTab[cur->nodeNr] = NULL;
1872}
1873
1874/**
1875 * xmlXPathNodeSetRemove:
1876 * @cur: the initial node set
1877 * @val: the index to remove
1878 *
1879 * Removes an entry from an existing NodeSet list.
1880 */
1881void
1882xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1883 if (cur == NULL) return;
1884 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001885 if ((cur->nodeTab[val] != NULL) &&
1886 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1887 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001888 cur->nodeNr--;
1889 for (;val < cur->nodeNr;val++)
1890 cur->nodeTab[val] = cur->nodeTab[val + 1];
1891 cur->nodeTab[cur->nodeNr] = NULL;
1892}
1893
1894/**
1895 * xmlXPathFreeNodeSet:
1896 * @obj: the xmlNodeSetPtr to free
1897 *
1898 * Free the NodeSet compound (not the actual nodes !).
1899 */
1900void
1901xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1902 if (obj == NULL) return;
1903 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001904 int i;
1905
1906 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1907 for (i = 0;i < obj->nodeNr;i++)
1908 if ((obj->nodeTab[i] != NULL) &&
1909 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1910 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001911 xmlFree(obj->nodeTab);
1912 }
Owen Taylor3473f882001-02-23 17:55:21 +00001913 xmlFree(obj);
1914}
1915
1916/**
1917 * xmlXPathFreeValueTree:
1918 * @obj: the xmlNodeSetPtr to free
1919 *
1920 * Free the NodeSet compound and the actual tree, this is different
1921 * from xmlXPathFreeNodeSet()
1922 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001923static void
Owen Taylor3473f882001-02-23 17:55:21 +00001924xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1925 int i;
1926
1927 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001928
1929 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001930 for (i = 0;i < obj->nodeNr;i++) {
1931 if (obj->nodeTab[i] != NULL) {
1932 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1933 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
1934 } else {
1935 xmlFreeNodeList(obj->nodeTab[i]);
1936 }
1937 }
1938 }
Owen Taylor3473f882001-02-23 17:55:21 +00001939 xmlFree(obj->nodeTab);
1940 }
Owen Taylor3473f882001-02-23 17:55:21 +00001941 xmlFree(obj);
1942}
1943
1944#if defined(DEBUG) || defined(DEBUG_STEP)
1945/**
1946 * xmlGenericErrorContextNodeSet:
1947 * @output: a FILE * for the output
1948 * @obj: the xmlNodeSetPtr to free
1949 *
1950 * Quick display of a NodeSet
1951 */
1952void
1953xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1954 int i;
1955
1956 if (output == NULL) output = xmlGenericErrorContext;
1957 if (obj == NULL) {
1958 fprintf(output, "NodeSet == NULL !\n");
1959 return;
1960 }
1961 if (obj->nodeNr == 0) {
1962 fprintf(output, "NodeSet is empty\n");
1963 return;
1964 }
1965 if (obj->nodeTab == NULL) {
1966 fprintf(output, " nodeTab == NULL !\n");
1967 return;
1968 }
1969 for (i = 0; i < obj->nodeNr; i++) {
1970 if (obj->nodeTab[i] == NULL) {
1971 fprintf(output, " NULL !\n");
1972 return;
1973 }
1974 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1975 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1976 fprintf(output, " /");
1977 else if (obj->nodeTab[i]->name == NULL)
1978 fprintf(output, " noname!");
1979 else fprintf(output, " %s", obj->nodeTab[i]->name);
1980 }
1981 fprintf(output, "\n");
1982}
1983#endif
1984
1985/**
1986 * xmlXPathNewNodeSet:
1987 * @val: the NodePtr value
1988 *
1989 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1990 * it with the single Node @val
1991 *
1992 * Returns the newly created object.
1993 */
1994xmlXPathObjectPtr
1995xmlXPathNewNodeSet(xmlNodePtr val) {
1996 xmlXPathObjectPtr ret;
1997
1998 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1999 if (ret == NULL) {
2000 xmlGenericError(xmlGenericErrorContext,
2001 "xmlXPathNewNodeSet: out of memory\n");
2002 return(NULL);
2003 }
2004 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2005 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002006 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002007 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002008 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002009 return(ret);
2010}
2011
2012/**
2013 * xmlXPathNewValueTree:
2014 * @val: the NodePtr value
2015 *
2016 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2017 * it with the tree root @val
2018 *
2019 * Returns the newly created object.
2020 */
2021xmlXPathObjectPtr
2022xmlXPathNewValueTree(xmlNodePtr val) {
2023 xmlXPathObjectPtr ret;
2024
2025 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2026 if (ret == NULL) {
2027 xmlGenericError(xmlGenericErrorContext,
2028 "xmlXPathNewNodeSet: out of memory\n");
2029 return(NULL);
2030 }
2031 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2032 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002033 ret->boolval = 1;
2034 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002035 ret->nodesetval = xmlXPathNodeSetCreate(val);
2036 return(ret);
2037}
2038
2039/**
2040 * xmlXPathNewNodeSetList:
2041 * @val: an existing NodeSet
2042 *
2043 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2044 * it with the Nodeset @val
2045 *
2046 * Returns the newly created object.
2047 */
2048xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002049xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2050{
Owen Taylor3473f882001-02-23 17:55:21 +00002051 xmlXPathObjectPtr ret;
2052 int i;
2053
2054 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002055 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002056 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002057 ret = xmlXPathNewNodeSet(NULL);
2058 else {
2059 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2060 for (i = 1; i < val->nodeNr; ++i)
2061 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2062 }
Owen Taylor3473f882001-02-23 17:55:21 +00002063
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002064 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002065}
2066
2067/**
2068 * xmlXPathWrapNodeSet:
2069 * @val: the NodePtr value
2070 *
2071 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2072 *
2073 * Returns the newly created object.
2074 */
2075xmlXPathObjectPtr
2076xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2077 xmlXPathObjectPtr ret;
2078
2079 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2080 if (ret == NULL) {
2081 xmlGenericError(xmlGenericErrorContext,
2082 "xmlXPathWrapNodeSet: out of memory\n");
2083 return(NULL);
2084 }
2085 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2086 ret->type = XPATH_NODESET;
2087 ret->nodesetval = val;
2088 return(ret);
2089}
2090
2091/**
2092 * xmlXPathFreeNodeSetList:
2093 * @obj: an existing NodeSetList object
2094 *
2095 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2096 * the list contrary to xmlXPathFreeObject().
2097 */
2098void
2099xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2100 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002101 xmlFree(obj);
2102}
2103
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002104/**
2105 * xmlXPathDifference:
2106 * @nodes1: a node-set
2107 * @nodes2: a node-set
2108 *
2109 * Implements the EXSLT - Sets difference() function:
2110 * node-set set:difference (node-set, node-set)
2111 *
2112 * Returns the difference between the two node sets, or nodes1 if
2113 * nodes2 is empty
2114 */
2115xmlNodeSetPtr
2116xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2117 xmlNodeSetPtr ret;
2118 int i, l1;
2119 xmlNodePtr cur;
2120
2121 if (xmlXPathNodeSetIsEmpty(nodes2))
2122 return(nodes1);
2123
2124 ret = xmlXPathNodeSetCreate(NULL);
2125 if (xmlXPathNodeSetIsEmpty(nodes1))
2126 return(ret);
2127
2128 l1 = xmlXPathNodeSetGetLength(nodes1);
2129
2130 for (i = 0; i < l1; i++) {
2131 cur = xmlXPathNodeSetItem(nodes1, i);
2132 if (!xmlXPathNodeSetContains(nodes2, cur))
2133 xmlXPathNodeSetAddUnique(ret, cur);
2134 }
2135 return(ret);
2136}
2137
2138/**
2139 * xmlXPathIntersection:
2140 * @nodes1: a node-set
2141 * @nodes2: a node-set
2142 *
2143 * Implements the EXSLT - Sets intersection() function:
2144 * node-set set:intersection (node-set, node-set)
2145 *
2146 * Returns a node set comprising the nodes that are within both the
2147 * node sets passed as arguments
2148 */
2149xmlNodeSetPtr
2150xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2151 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2152 int i, l1;
2153 xmlNodePtr cur;
2154
2155 if (xmlXPathNodeSetIsEmpty(nodes1))
2156 return(ret);
2157 if (xmlXPathNodeSetIsEmpty(nodes2))
2158 return(ret);
2159
2160 l1 = xmlXPathNodeSetGetLength(nodes1);
2161
2162 for (i = 0; i < l1; i++) {
2163 cur = xmlXPathNodeSetItem(nodes1, i);
2164 if (xmlXPathNodeSetContains(nodes2, cur))
2165 xmlXPathNodeSetAddUnique(ret, cur);
2166 }
2167 return(ret);
2168}
2169
2170/**
2171 * xmlXPathDistinctSorted:
2172 * @nodes: a node-set, sorted by document order
2173 *
2174 * Implements the EXSLT - Sets distinct() function:
2175 * node-set set:distinct (node-set)
2176 *
2177 * Returns a subset of the nodes contained in @nodes, or @nodes if
2178 * it is empty
2179 */
2180xmlNodeSetPtr
2181xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2182 xmlNodeSetPtr ret;
2183 xmlHashTablePtr hash;
2184 int i, l;
2185 xmlChar * strval;
2186 xmlNodePtr cur;
2187
2188 if (xmlXPathNodeSetIsEmpty(nodes))
2189 return(nodes);
2190
2191 ret = xmlXPathNodeSetCreate(NULL);
2192 l = xmlXPathNodeSetGetLength(nodes);
2193 hash = xmlHashCreate (l);
2194 for (i = 0; i < l; i++) {
2195 cur = xmlXPathNodeSetItem(nodes, i);
2196 strval = xmlXPathCastNodeToString(cur);
2197 if (xmlHashLookup(hash, strval) == NULL) {
2198 xmlHashAddEntry(hash, strval, strval);
2199 xmlXPathNodeSetAddUnique(ret, cur);
2200 } else {
2201 xmlFree(strval);
2202 }
2203 }
2204 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2205 return(ret);
2206}
2207
2208/**
2209 * xmlXPathDistinct:
2210 * @nodes: a node-set
2211 *
2212 * Implements the EXSLT - Sets distinct() function:
2213 * node-set set:distinct (node-set)
2214 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2215 * is called with the sorted node-set
2216 *
2217 * Returns a subset of the nodes contained in @nodes, or @nodes if
2218 * it is empty
2219 */
2220xmlNodeSetPtr
2221xmlXPathDistinct (xmlNodeSetPtr nodes) {
2222 if (xmlXPathNodeSetIsEmpty(nodes))
2223 return(nodes);
2224
2225 xmlXPathNodeSetSort(nodes);
2226 return(xmlXPathDistinctSorted(nodes));
2227}
2228
2229/**
2230 * xmlXPathHasSameNodes:
2231 * @nodes1: a node-set
2232 * @nodes2: a node-set
2233 *
2234 * Implements the EXSLT - Sets has-same-nodes function:
2235 * boolean set:has-same-node(node-set, node-set)
2236 *
2237 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2238 * otherwise
2239 */
2240int
2241xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2242 int i, l;
2243 xmlNodePtr cur;
2244
2245 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2246 xmlXPathNodeSetIsEmpty(nodes2))
2247 return(0);
2248
2249 l = xmlXPathNodeSetGetLength(nodes1);
2250 for (i = 0; i < l; i++) {
2251 cur = xmlXPathNodeSetItem(nodes1, i);
2252 if (xmlXPathNodeSetContains(nodes2, cur))
2253 return(1);
2254 }
2255 return(0);
2256}
2257
2258/**
2259 * xmlXPathNodeLeadingSorted:
2260 * @nodes: a node-set, sorted by document order
2261 * @node: a node
2262 *
2263 * Implements the EXSLT - Sets leading() function:
2264 * node-set set:leading (node-set, node-set)
2265 *
2266 * Returns the nodes in @nodes that precede @node in document order,
2267 * @nodes if @node is NULL or an empty node-set if @nodes
2268 * doesn't contain @node
2269 */
2270xmlNodeSetPtr
2271xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2272 int i, l;
2273 xmlNodePtr cur;
2274 xmlNodeSetPtr ret;
2275
2276 if (node == NULL)
2277 return(nodes);
2278
2279 ret = xmlXPathNodeSetCreate(NULL);
2280 if (xmlXPathNodeSetIsEmpty(nodes) ||
2281 (!xmlXPathNodeSetContains(nodes, node)))
2282 return(ret);
2283
2284 l = xmlXPathNodeSetGetLength(nodes);
2285 for (i = 0; i < l; i++) {
2286 cur = xmlXPathNodeSetItem(nodes, i);
2287 if (cur == node)
2288 break;
2289 xmlXPathNodeSetAddUnique(ret, cur);
2290 }
2291 return(ret);
2292}
2293
2294/**
2295 * xmlXPathNodeLeading:
2296 * @nodes: a node-set
2297 * @node: a node
2298 *
2299 * Implements the EXSLT - Sets leading() function:
2300 * node-set set:leading (node-set, node-set)
2301 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2302 * is called.
2303 *
2304 * Returns the nodes in @nodes that precede @node in document order,
2305 * @nodes if @node is NULL or an empty node-set if @nodes
2306 * doesn't contain @node
2307 */
2308xmlNodeSetPtr
2309xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2310 xmlXPathNodeSetSort(nodes);
2311 return(xmlXPathNodeLeadingSorted(nodes, node));
2312}
2313
2314/**
2315 * xmlXPathLeadingSorted:
2316 * @nodes1: a node-set, sorted by document order
2317 * @nodes2: a node-set, sorted by document order
2318 *
2319 * Implements the EXSLT - Sets leading() function:
2320 * node-set set:leading (node-set, node-set)
2321 *
2322 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2323 * in document order, @nodes1 if @nodes2 is NULL or empty or
2324 * an empty node-set if @nodes1 doesn't contain @nodes2
2325 */
2326xmlNodeSetPtr
2327xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2328 if (xmlXPathNodeSetIsEmpty(nodes2))
2329 return(nodes1);
2330 return(xmlXPathNodeLeadingSorted(nodes1,
2331 xmlXPathNodeSetItem(nodes2, 1)));
2332}
2333
2334/**
2335 * xmlXPathLeading:
2336 * @nodes1: a node-set
2337 * @nodes2: a node-set
2338 *
2339 * Implements the EXSLT - Sets leading() function:
2340 * node-set set:leading (node-set, node-set)
2341 * @nodes1 and @nodes2 are sorted by document order, then
2342 * #exslSetsLeadingSorted is called.
2343 *
2344 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2345 * in document order, @nodes1 if @nodes2 is NULL or empty or
2346 * an empty node-set if @nodes1 doesn't contain @nodes2
2347 */
2348xmlNodeSetPtr
2349xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2350 if (xmlXPathNodeSetIsEmpty(nodes2))
2351 return(nodes1);
2352 if (xmlXPathNodeSetIsEmpty(nodes1))
2353 return(xmlXPathNodeSetCreate(NULL));
2354 xmlXPathNodeSetSort(nodes1);
2355 xmlXPathNodeSetSort(nodes2);
2356 return(xmlXPathNodeLeadingSorted(nodes1,
2357 xmlXPathNodeSetItem(nodes2, 1)));
2358}
2359
2360/**
2361 * xmlXPathNodeTrailingSorted:
2362 * @nodes: a node-set, sorted by document order
2363 * @node: a node
2364 *
2365 * Implements the EXSLT - Sets trailing() function:
2366 * node-set set:trailing (node-set, node-set)
2367 *
2368 * Returns the nodes in @nodes that follow @node in document order,
2369 * @nodes if @node is NULL or an empty node-set if @nodes
2370 * doesn't contain @node
2371 */
2372xmlNodeSetPtr
2373xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2374 int i, l;
2375 xmlNodePtr cur;
2376 xmlNodeSetPtr ret;
2377
2378 if (node == NULL)
2379 return(nodes);
2380
2381 ret = xmlXPathNodeSetCreate(NULL);
2382 if (xmlXPathNodeSetIsEmpty(nodes) ||
2383 (!xmlXPathNodeSetContains(nodes, node)))
2384 return(ret);
2385
2386 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002387 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002388 cur = xmlXPathNodeSetItem(nodes, i);
2389 if (cur == node)
2390 break;
2391 xmlXPathNodeSetAddUnique(ret, cur);
2392 }
2393 return(ret);
2394}
2395
2396/**
2397 * xmlXPathNodeTrailing:
2398 * @nodes: a node-set
2399 * @node: a node
2400 *
2401 * Implements the EXSLT - Sets trailing() function:
2402 * node-set set:trailing (node-set, node-set)
2403 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2404 * is called.
2405 *
2406 * Returns the nodes in @nodes that follow @node in document order,
2407 * @nodes if @node is NULL or an empty node-set if @nodes
2408 * doesn't contain @node
2409 */
2410xmlNodeSetPtr
2411xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2412 xmlXPathNodeSetSort(nodes);
2413 return(xmlXPathNodeTrailingSorted(nodes, node));
2414}
2415
2416/**
2417 * xmlXPathTrailingSorted:
2418 * @nodes1: a node-set, sorted by document order
2419 * @nodes2: a node-set, sorted by document order
2420 *
2421 * Implements the EXSLT - Sets trailing() function:
2422 * node-set set:trailing (node-set, node-set)
2423 *
2424 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2425 * in document order, @nodes1 if @nodes2 is NULL or empty or
2426 * an empty node-set if @nodes1 doesn't contain @nodes2
2427 */
2428xmlNodeSetPtr
2429xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2430 if (xmlXPathNodeSetIsEmpty(nodes2))
2431 return(nodes1);
2432 return(xmlXPathNodeTrailingSorted(nodes1,
2433 xmlXPathNodeSetItem(nodes2, 0)));
2434}
2435
2436/**
2437 * xmlXPathTrailing:
2438 * @nodes1: a node-set
2439 * @nodes2: a node-set
2440 *
2441 * Implements the EXSLT - Sets trailing() function:
2442 * node-set set:trailing (node-set, node-set)
2443 * @nodes1 and @nodes2 are sorted by document order, then
2444 * #xmlXPathTrailingSorted is called.
2445 *
2446 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2447 * in document order, @nodes1 if @nodes2 is NULL or empty or
2448 * an empty node-set if @nodes1 doesn't contain @nodes2
2449 */
2450xmlNodeSetPtr
2451xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2452 if (xmlXPathNodeSetIsEmpty(nodes2))
2453 return(nodes1);
2454 if (xmlXPathNodeSetIsEmpty(nodes1))
2455 return(xmlXPathNodeSetCreate(NULL));
2456 xmlXPathNodeSetSort(nodes1);
2457 xmlXPathNodeSetSort(nodes2);
2458 return(xmlXPathNodeTrailingSorted(nodes1,
2459 xmlXPathNodeSetItem(nodes2, 0)));
2460}
2461
Owen Taylor3473f882001-02-23 17:55:21 +00002462/************************************************************************
2463 * *
2464 * Routines to handle extra functions *
2465 * *
2466 ************************************************************************/
2467
2468/**
2469 * xmlXPathRegisterFunc:
2470 * @ctxt: the XPath context
2471 * @name: the function name
2472 * @f: the function implementation or NULL
2473 *
2474 * Register a new function. If @f is NULL it unregisters the function
2475 *
2476 * Returns 0 in case of success, -1 in case of error
2477 */
2478int
2479xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2480 xmlXPathFunction f) {
2481 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2482}
2483
2484/**
2485 * xmlXPathRegisterFuncNS:
2486 * @ctxt: the XPath context
2487 * @name: the function name
2488 * @ns_uri: the function namespace URI
2489 * @f: the function implementation or NULL
2490 *
2491 * Register a new function. If @f is NULL it unregisters the function
2492 *
2493 * Returns 0 in case of success, -1 in case of error
2494 */
2495int
2496xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2497 const xmlChar *ns_uri, xmlXPathFunction f) {
2498 if (ctxt == NULL)
2499 return(-1);
2500 if (name == NULL)
2501 return(-1);
2502
2503 if (ctxt->funcHash == NULL)
2504 ctxt->funcHash = xmlHashCreate(0);
2505 if (ctxt->funcHash == NULL)
2506 return(-1);
2507 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2508}
2509
2510/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002511 * xmlXPathRegisterFuncLookup:
2512 * @ctxt: the XPath context
2513 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002514 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002515 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002516 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002517 */
2518void
2519xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2520 xmlXPathFuncLookupFunc f,
2521 void *funcCtxt) {
2522 if (ctxt == NULL)
2523 return;
2524 ctxt->funcLookupFunc = (void *) f;
2525 ctxt->funcLookupData = funcCtxt;
2526}
2527
2528/**
Owen Taylor3473f882001-02-23 17:55:21 +00002529 * xmlXPathFunctionLookup:
2530 * @ctxt: the XPath context
2531 * @name: the function name
2532 *
2533 * Search in the Function array of the context for the given
2534 * function.
2535 *
2536 * Returns the xmlXPathFunction or NULL if not found
2537 */
2538xmlXPathFunction
2539xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002540 if (ctxt == NULL)
2541 return (NULL);
2542
2543 if (ctxt->funcLookupFunc != NULL) {
2544 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002545 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002546
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002547 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002548 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002549 if (ret != NULL)
2550 return(ret);
2551 }
Owen Taylor3473f882001-02-23 17:55:21 +00002552 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2553}
2554
2555/**
2556 * xmlXPathFunctionLookupNS:
2557 * @ctxt: the XPath context
2558 * @name: the function name
2559 * @ns_uri: the function namespace URI
2560 *
2561 * Search in the Function array of the context for the given
2562 * function.
2563 *
2564 * Returns the xmlXPathFunction or NULL if not found
2565 */
2566xmlXPathFunction
2567xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2568 const xmlChar *ns_uri) {
2569 if (ctxt == NULL)
2570 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002571 if (name == NULL)
2572 return(NULL);
2573
Thomas Broyerba4ad322001-07-26 16:55:21 +00002574 if (ctxt->funcLookupFunc != NULL) {
2575 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002576 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002577
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002578 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002579 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002580 if (ret != NULL)
2581 return(ret);
2582 }
2583
2584 if (ctxt->funcHash == NULL)
2585 return(NULL);
2586
Owen Taylor3473f882001-02-23 17:55:21 +00002587 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2588}
2589
2590/**
2591 * xmlXPathRegisteredFuncsCleanup:
2592 * @ctxt: the XPath context
2593 *
2594 * Cleanup the XPath context data associated to registered functions
2595 */
2596void
2597xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2598 if (ctxt == NULL)
2599 return;
2600
2601 xmlHashFree(ctxt->funcHash, NULL);
2602 ctxt->funcHash = NULL;
2603}
2604
2605/************************************************************************
2606 * *
2607 * Routines to handle Variable *
2608 * *
2609 ************************************************************************/
2610
2611/**
2612 * xmlXPathRegisterVariable:
2613 * @ctxt: the XPath context
2614 * @name: the variable name
2615 * @value: the variable value or NULL
2616 *
2617 * Register a new variable value. If @value is NULL it unregisters
2618 * the variable
2619 *
2620 * Returns 0 in case of success, -1 in case of error
2621 */
2622int
2623xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2624 xmlXPathObjectPtr value) {
2625 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2626}
2627
2628/**
2629 * xmlXPathRegisterVariableNS:
2630 * @ctxt: the XPath context
2631 * @name: the variable name
2632 * @ns_uri: the variable namespace URI
2633 * @value: the variable value or NULL
2634 *
2635 * Register a new variable value. If @value is NULL it unregisters
2636 * the variable
2637 *
2638 * Returns 0 in case of success, -1 in case of error
2639 */
2640int
2641xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2642 const xmlChar *ns_uri,
2643 xmlXPathObjectPtr value) {
2644 if (ctxt == NULL)
2645 return(-1);
2646 if (name == NULL)
2647 return(-1);
2648
2649 if (ctxt->varHash == NULL)
2650 ctxt->varHash = xmlHashCreate(0);
2651 if (ctxt->varHash == NULL)
2652 return(-1);
2653 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2654 (void *) value,
2655 (xmlHashDeallocator)xmlXPathFreeObject));
2656}
2657
2658/**
2659 * xmlXPathRegisterVariableLookup:
2660 * @ctxt: the XPath context
2661 * @f: the lookup function
2662 * @data: the lookup data
2663 *
2664 * register an external mechanism to do variable lookup
2665 */
2666void
2667xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2668 xmlXPathVariableLookupFunc f, void *data) {
2669 if (ctxt == NULL)
2670 return;
2671 ctxt->varLookupFunc = (void *) f;
2672 ctxt->varLookupData = data;
2673}
2674
2675/**
2676 * xmlXPathVariableLookup:
2677 * @ctxt: the XPath context
2678 * @name: the variable name
2679 *
2680 * Search in the Variable array of the context for the given
2681 * variable value.
2682 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002683 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002684 */
2685xmlXPathObjectPtr
2686xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2687 if (ctxt == NULL)
2688 return(NULL);
2689
2690 if (ctxt->varLookupFunc != NULL) {
2691 xmlXPathObjectPtr ret;
2692
2693 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2694 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002695 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002696 }
2697 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2698}
2699
2700/**
2701 * xmlXPathVariableLookupNS:
2702 * @ctxt: the XPath context
2703 * @name: the variable name
2704 * @ns_uri: the variable namespace URI
2705 *
2706 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002707 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002708 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002709 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002710 */
2711xmlXPathObjectPtr
2712xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2713 const xmlChar *ns_uri) {
2714 if (ctxt == NULL)
2715 return(NULL);
2716
2717 if (ctxt->varLookupFunc != NULL) {
2718 xmlXPathObjectPtr ret;
2719
2720 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2721 (ctxt->varLookupData, name, ns_uri);
2722 if (ret != NULL) return(ret);
2723 }
2724
2725 if (ctxt->varHash == NULL)
2726 return(NULL);
2727 if (name == NULL)
2728 return(NULL);
2729
Daniel Veillard8c357d52001-07-03 23:43:33 +00002730 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2731 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002732}
2733
2734/**
2735 * xmlXPathRegisteredVariablesCleanup:
2736 * @ctxt: the XPath context
2737 *
2738 * Cleanup the XPath context data associated to registered variables
2739 */
2740void
2741xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2742 if (ctxt == NULL)
2743 return;
2744
Daniel Veillard76d66f42001-05-16 21:05:17 +00002745 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002746 ctxt->varHash = NULL;
2747}
2748
2749/**
2750 * xmlXPathRegisterNs:
2751 * @ctxt: the XPath context
2752 * @prefix: the namespace prefix
2753 * @ns_uri: the namespace name
2754 *
2755 * Register a new namespace. If @ns_uri is NULL it unregisters
2756 * the namespace
2757 *
2758 * Returns 0 in case of success, -1 in case of error
2759 */
2760int
2761xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2762 const xmlChar *ns_uri) {
2763 if (ctxt == NULL)
2764 return(-1);
2765 if (prefix == NULL)
2766 return(-1);
2767
2768 if (ctxt->nsHash == NULL)
2769 ctxt->nsHash = xmlHashCreate(10);
2770 if (ctxt->nsHash == NULL)
2771 return(-1);
2772 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2773 (xmlHashDeallocator)xmlFree));
2774}
2775
2776/**
2777 * xmlXPathNsLookup:
2778 * @ctxt: the XPath context
2779 * @prefix: the namespace prefix value
2780 *
2781 * Search in the namespace declaration array of the context for the given
2782 * namespace name associated to the given prefix
2783 *
2784 * Returns the value or NULL if not found
2785 */
2786const xmlChar *
2787xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2788 if (ctxt == NULL)
2789 return(NULL);
2790 if (prefix == NULL)
2791 return(NULL);
2792
2793#ifdef XML_XML_NAMESPACE
2794 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2795 return(XML_XML_NAMESPACE);
2796#endif
2797
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002798 if (ctxt->namespaces != NULL) {
2799 int i;
2800
2801 for (i = 0;i < ctxt->nsNr;i++) {
2802 if ((ctxt->namespaces[i] != NULL) &&
2803 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2804 return(ctxt->namespaces[i]->href);
2805 }
2806 }
Owen Taylor3473f882001-02-23 17:55:21 +00002807
2808 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2809}
2810
2811/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002812 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002813 * @ctxt: the XPath context
2814 *
2815 * Cleanup the XPath context data associated to registered variables
2816 */
2817void
2818xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2819 if (ctxt == NULL)
2820 return;
2821
2822 xmlHashFree(ctxt->nsHash, NULL);
2823 ctxt->nsHash = NULL;
2824}
2825
2826/************************************************************************
2827 * *
2828 * Routines to handle Values *
2829 * *
2830 ************************************************************************/
2831
2832/* Allocations are terrible, one need to optimize all this !!! */
2833
2834/**
2835 * xmlXPathNewFloat:
2836 * @val: the double value
2837 *
2838 * Create a new xmlXPathObjectPtr of type double and of value @val
2839 *
2840 * Returns the newly created object.
2841 */
2842xmlXPathObjectPtr
2843xmlXPathNewFloat(double val) {
2844 xmlXPathObjectPtr ret;
2845
2846 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2847 if (ret == NULL) {
2848 xmlGenericError(xmlGenericErrorContext,
2849 "xmlXPathNewFloat: out of memory\n");
2850 return(NULL);
2851 }
2852 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2853 ret->type = XPATH_NUMBER;
2854 ret->floatval = val;
2855 return(ret);
2856}
2857
2858/**
2859 * xmlXPathNewBoolean:
2860 * @val: the boolean value
2861 *
2862 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2863 *
2864 * Returns the newly created object.
2865 */
2866xmlXPathObjectPtr
2867xmlXPathNewBoolean(int val) {
2868 xmlXPathObjectPtr ret;
2869
2870 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2871 if (ret == NULL) {
2872 xmlGenericError(xmlGenericErrorContext,
2873 "xmlXPathNewBoolean: out of memory\n");
2874 return(NULL);
2875 }
2876 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2877 ret->type = XPATH_BOOLEAN;
2878 ret->boolval = (val != 0);
2879 return(ret);
2880}
2881
2882/**
2883 * xmlXPathNewString:
2884 * @val: the xmlChar * value
2885 *
2886 * Create a new xmlXPathObjectPtr of type string and of value @val
2887 *
2888 * Returns the newly created object.
2889 */
2890xmlXPathObjectPtr
2891xmlXPathNewString(const xmlChar *val) {
2892 xmlXPathObjectPtr ret;
2893
2894 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2895 if (ret == NULL) {
2896 xmlGenericError(xmlGenericErrorContext,
2897 "xmlXPathNewString: out of memory\n");
2898 return(NULL);
2899 }
2900 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2901 ret->type = XPATH_STRING;
2902 if (val != NULL)
2903 ret->stringval = xmlStrdup(val);
2904 else
2905 ret->stringval = xmlStrdup((const xmlChar *)"");
2906 return(ret);
2907}
2908
2909/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002910 * xmlXPathWrapString:
2911 * @val: the xmlChar * value
2912 *
2913 * Wraps the @val string into an XPath object.
2914 *
2915 * Returns the newly created object.
2916 */
2917xmlXPathObjectPtr
2918xmlXPathWrapString (xmlChar *val) {
2919 xmlXPathObjectPtr ret;
2920
2921 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2922 if (ret == NULL) {
2923 xmlGenericError(xmlGenericErrorContext,
2924 "xmlXPathWrapString: out of memory\n");
2925 return(NULL);
2926 }
2927 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2928 ret->type = XPATH_STRING;
2929 ret->stringval = val;
2930 return(ret);
2931}
2932
2933/**
Owen Taylor3473f882001-02-23 17:55:21 +00002934 * xmlXPathNewCString:
2935 * @val: the char * value
2936 *
2937 * Create a new xmlXPathObjectPtr of type string and of value @val
2938 *
2939 * Returns the newly created object.
2940 */
2941xmlXPathObjectPtr
2942xmlXPathNewCString(const char *val) {
2943 xmlXPathObjectPtr ret;
2944
2945 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2946 if (ret == NULL) {
2947 xmlGenericError(xmlGenericErrorContext,
2948 "xmlXPathNewCString: out of memory\n");
2949 return(NULL);
2950 }
2951 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2952 ret->type = XPATH_STRING;
2953 ret->stringval = xmlStrdup(BAD_CAST val);
2954 return(ret);
2955}
2956
2957/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002958 * xmlXPathWrapCString:
2959 * @val: the char * value
2960 *
2961 * Wraps a string into an XPath object.
2962 *
2963 * Returns the newly created object.
2964 */
2965xmlXPathObjectPtr
2966xmlXPathWrapCString (char * val) {
2967 return(xmlXPathWrapString((xmlChar *)(val)));
2968}
2969
2970/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002971 * xmlXPathWrapExternal:
2972 * @val: the user data
2973 *
2974 * Wraps the @val data into an XPath object.
2975 *
2976 * Returns the newly created object.
2977 */
2978xmlXPathObjectPtr
2979xmlXPathWrapExternal (void *val) {
2980 xmlXPathObjectPtr ret;
2981
2982 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2983 if (ret == NULL) {
2984 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002985 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002986 return(NULL);
2987 }
2988 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2989 ret->type = XPATH_USERS;
2990 ret->user = val;
2991 return(ret);
2992}
2993
2994/**
Owen Taylor3473f882001-02-23 17:55:21 +00002995 * xmlXPathObjectCopy:
2996 * @val: the original object
2997 *
2998 * allocate a new copy of a given object
2999 *
3000 * Returns the newly created object.
3001 */
3002xmlXPathObjectPtr
3003xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3004 xmlXPathObjectPtr ret;
3005
3006 if (val == NULL)
3007 return(NULL);
3008
3009 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3010 if (ret == NULL) {
3011 xmlGenericError(xmlGenericErrorContext,
3012 "xmlXPathObjectCopy: out of memory\n");
3013 return(NULL);
3014 }
3015 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3016 switch (val->type) {
3017 case XPATH_BOOLEAN:
3018 case XPATH_NUMBER:
3019 case XPATH_POINT:
3020 case XPATH_RANGE:
3021 break;
3022 case XPATH_STRING:
3023 ret->stringval = xmlStrdup(val->stringval);
3024 break;
3025 case XPATH_XSLT_TREE:
3026 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003027 (val->nodesetval->nodeTab != NULL)) {
3028 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003029 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3030 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003031 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003032 (xmlNodePtr) ret->user);
3033 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003034 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003035 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003036 break;
3037 case XPATH_NODESET:
3038 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003039 /* Do not deallocate the copied tree value */
3040 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003041 break;
3042 case XPATH_LOCATIONSET:
3043#ifdef LIBXML_XPTR_ENABLED
3044 {
3045 xmlLocationSetPtr loc = val->user;
3046 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3047 break;
3048 }
3049#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003050 case XPATH_USERS:
3051 ret->user = val->user;
3052 break;
3053 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003054 xmlGenericError(xmlGenericErrorContext,
3055 "xmlXPathObjectCopy: unsupported type %d\n",
3056 val->type);
3057 break;
3058 }
3059 return(ret);
3060}
3061
3062/**
3063 * xmlXPathFreeObject:
3064 * @obj: the object to free
3065 *
3066 * Free up an xmlXPathObjectPtr object.
3067 */
3068void
3069xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3070 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003071 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003072 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003073 if (obj->user != NULL) {
3074 xmlFreeNodeList((xmlNodePtr) obj->user);
3075 xmlXPathFreeNodeSet(obj->nodesetval);
3076 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003077 xmlXPathFreeValueTree(obj->nodesetval);
3078 } else {
3079 if (obj->nodesetval != NULL)
3080 xmlXPathFreeNodeSet(obj->nodesetval);
3081 }
Owen Taylor3473f882001-02-23 17:55:21 +00003082#ifdef LIBXML_XPTR_ENABLED
3083 } else if (obj->type == XPATH_LOCATIONSET) {
3084 if (obj->user != NULL)
3085 xmlXPtrFreeLocationSet(obj->user);
3086#endif
3087 } else if (obj->type == XPATH_STRING) {
3088 if (obj->stringval != NULL)
3089 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003090 }
3091
Owen Taylor3473f882001-02-23 17:55:21 +00003092 xmlFree(obj);
3093}
3094
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003095
3096/************************************************************************
3097 * *
3098 * Type Casting Routines *
3099 * *
3100 ************************************************************************/
3101
3102/**
3103 * xmlXPathCastBooleanToString:
3104 * @val: a boolean
3105 *
3106 * Converts a boolean to its string value.
3107 *
3108 * Returns a newly allocated string.
3109 */
3110xmlChar *
3111xmlXPathCastBooleanToString (int val) {
3112 xmlChar *ret;
3113 if (val)
3114 ret = xmlStrdup((const xmlChar *) "true");
3115 else
3116 ret = xmlStrdup((const xmlChar *) "false");
3117 return(ret);
3118}
3119
3120/**
3121 * xmlXPathCastNumberToString:
3122 * @val: a number
3123 *
3124 * Converts a number to its string value.
3125 *
3126 * Returns a newly allocated string.
3127 */
3128xmlChar *
3129xmlXPathCastNumberToString (double val) {
3130 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003131 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003132 case 1:
3133 ret = xmlStrdup((const xmlChar *) "+Infinity");
3134 break;
3135 case -1:
3136 ret = xmlStrdup((const xmlChar *) "-Infinity");
3137 break;
3138 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003139 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003140 ret = xmlStrdup((const xmlChar *) "NaN");
3141 } else {
3142 /* could be improved */
3143 char buf[100];
3144 xmlXPathFormatNumber(val, buf, 100);
3145 ret = xmlStrdup((const xmlChar *) buf);
3146 }
3147 }
3148 return(ret);
3149}
3150
3151/**
3152 * xmlXPathCastNodeToString:
3153 * @node: a node
3154 *
3155 * Converts a node to its string value.
3156 *
3157 * Returns a newly allocated string.
3158 */
3159xmlChar *
3160xmlXPathCastNodeToString (xmlNodePtr node) {
3161 return(xmlNodeGetContent(node));
3162}
3163
3164/**
3165 * xmlXPathCastNodeSetToString:
3166 * @ns: a node-set
3167 *
3168 * Converts a node-set to its string value.
3169 *
3170 * Returns a newly allocated string.
3171 */
3172xmlChar *
3173xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3174 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3175 return(xmlStrdup((const xmlChar *) ""));
3176
3177 xmlXPathNodeSetSort(ns);
3178 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3179}
3180
3181/**
3182 * xmlXPathCastToString:
3183 * @val: an XPath object
3184 *
3185 * Converts an existing object to its string() equivalent
3186 *
3187 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003188 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003189 * string object).
3190 */
3191xmlChar *
3192xmlXPathCastToString(xmlXPathObjectPtr val) {
3193 xmlChar *ret = NULL;
3194
3195 if (val == NULL)
3196 return(xmlStrdup((const xmlChar *) ""));
3197 switch (val->type) {
3198 case XPATH_UNDEFINED:
3199#ifdef DEBUG_EXPR
3200 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3201#endif
3202 ret = xmlStrdup((const xmlChar *) "");
3203 break;
3204 case XPATH_XSLT_TREE:
3205 case XPATH_NODESET:
3206 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3207 break;
3208 case XPATH_STRING:
3209 return(val->stringval);
3210 case XPATH_BOOLEAN:
3211 ret = xmlXPathCastBooleanToString(val->boolval);
3212 break;
3213 case XPATH_NUMBER: {
3214 ret = xmlXPathCastNumberToString(val->floatval);
3215 break;
3216 }
3217 case XPATH_USERS:
3218 case XPATH_POINT:
3219 case XPATH_RANGE:
3220 case XPATH_LOCATIONSET:
3221 TODO
3222 ret = xmlStrdup((const xmlChar *) "");
3223 break;
3224 }
3225 return(ret);
3226}
3227
3228/**
3229 * xmlXPathConvertString:
3230 * @val: an XPath object
3231 *
3232 * Converts an existing object to its string() equivalent
3233 *
3234 * Returns the new object, the old one is freed (or the operation
3235 * is done directly on @val)
3236 */
3237xmlXPathObjectPtr
3238xmlXPathConvertString(xmlXPathObjectPtr val) {
3239 xmlChar *res = NULL;
3240
3241 if (val == NULL)
3242 return(xmlXPathNewCString(""));
3243
3244 switch (val->type) {
3245 case XPATH_UNDEFINED:
3246#ifdef DEBUG_EXPR
3247 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3248#endif
3249 break;
3250 case XPATH_XSLT_TREE:
3251 case XPATH_NODESET:
3252 res = xmlXPathCastNodeSetToString(val->nodesetval);
3253 break;
3254 case XPATH_STRING:
3255 return(val);
3256 case XPATH_BOOLEAN:
3257 res = xmlXPathCastBooleanToString(val->boolval);
3258 break;
3259 case XPATH_NUMBER:
3260 res = xmlXPathCastNumberToString(val->floatval);
3261 break;
3262 case XPATH_USERS:
3263 case XPATH_POINT:
3264 case XPATH_RANGE:
3265 case XPATH_LOCATIONSET:
3266 TODO;
3267 break;
3268 }
3269 xmlXPathFreeObject(val);
3270 if (res == NULL)
3271 return(xmlXPathNewCString(""));
3272 return(xmlXPathWrapString(res));
3273}
3274
3275/**
3276 * xmlXPathCastBooleanToNumber:
3277 * @val: a boolean
3278 *
3279 * Converts a boolean to its number value
3280 *
3281 * Returns the number value
3282 */
3283double
3284xmlXPathCastBooleanToNumber(int val) {
3285 if (val)
3286 return(1.0);
3287 return(0.0);
3288}
3289
3290/**
3291 * xmlXPathCastStringToNumber:
3292 * @val: a string
3293 *
3294 * Converts a string to its number value
3295 *
3296 * Returns the number value
3297 */
3298double
3299xmlXPathCastStringToNumber(const xmlChar * val) {
3300 return(xmlXPathStringEvalNumber(val));
3301}
3302
3303/**
3304 * xmlXPathCastNodeToNumber:
3305 * @node: a node
3306 *
3307 * Converts a node to its number value
3308 *
3309 * Returns the number value
3310 */
3311double
3312xmlXPathCastNodeToNumber (xmlNodePtr node) {
3313 xmlChar *strval;
3314 double ret;
3315
3316 if (node == NULL)
3317 return(xmlXPathNAN);
3318 strval = xmlXPathCastNodeToString(node);
3319 if (strval == NULL)
3320 return(xmlXPathNAN);
3321 ret = xmlXPathCastStringToNumber(strval);
3322 xmlFree(strval);
3323
3324 return(ret);
3325}
3326
3327/**
3328 * xmlXPathCastNodeSetToNumber:
3329 * @ns: a node-set
3330 *
3331 * Converts a node-set to its number value
3332 *
3333 * Returns the number value
3334 */
3335double
3336xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3337 xmlChar *str;
3338 double ret;
3339
3340 if (ns == NULL)
3341 return(xmlXPathNAN);
3342 str = xmlXPathCastNodeSetToString(ns);
3343 ret = xmlXPathCastStringToNumber(str);
3344 xmlFree(str);
3345 return(ret);
3346}
3347
3348/**
3349 * xmlXPathCastToNumber:
3350 * @val: an XPath object
3351 *
3352 * Converts an XPath object to its number value
3353 *
3354 * Returns the number value
3355 */
3356double
3357xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3358 double ret = 0.0;
3359
3360 if (val == NULL)
3361 return(xmlXPathNAN);
3362 switch (val->type) {
3363 case XPATH_UNDEFINED:
3364#ifdef DEGUB_EXPR
3365 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3366#endif
3367 ret = xmlXPathNAN;
3368 break;
3369 case XPATH_XSLT_TREE:
3370 case XPATH_NODESET:
3371 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3372 break;
3373 case XPATH_STRING:
3374 ret = xmlXPathCastStringToNumber(val->stringval);
3375 break;
3376 case XPATH_NUMBER:
3377 ret = val->floatval;
3378 break;
3379 case XPATH_BOOLEAN:
3380 ret = xmlXPathCastBooleanToNumber(val->boolval);
3381 break;
3382 case XPATH_USERS:
3383 case XPATH_POINT:
3384 case XPATH_RANGE:
3385 case XPATH_LOCATIONSET:
3386 TODO;
3387 ret = xmlXPathNAN;
3388 break;
3389 }
3390 return(ret);
3391}
3392
3393/**
3394 * xmlXPathConvertNumber:
3395 * @val: an XPath object
3396 *
3397 * Converts an existing object to its number() equivalent
3398 *
3399 * Returns the new object, the old one is freed (or the operation
3400 * is done directly on @val)
3401 */
3402xmlXPathObjectPtr
3403xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3404 xmlXPathObjectPtr ret;
3405
3406 if (val == NULL)
3407 return(xmlXPathNewFloat(0.0));
3408 if (val->type == XPATH_NUMBER)
3409 return(val);
3410 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3411 xmlXPathFreeObject(val);
3412 return(ret);
3413}
3414
3415/**
3416 * xmlXPathCastNumberToBoolean:
3417 * @val: a number
3418 *
3419 * Converts a number to its boolean value
3420 *
3421 * Returns the boolean value
3422 */
3423int
3424xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003425 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003426 return(0);
3427 return(1);
3428}
3429
3430/**
3431 * xmlXPathCastStringToBoolean:
3432 * @val: a string
3433 *
3434 * Converts a string to its boolean value
3435 *
3436 * Returns the boolean value
3437 */
3438int
3439xmlXPathCastStringToBoolean (const xmlChar *val) {
3440 if ((val == NULL) || (xmlStrlen(val) == 0))
3441 return(0);
3442 return(1);
3443}
3444
3445/**
3446 * xmlXPathCastNodeSetToBoolean:
3447 * @ns: a node-set
3448 *
3449 * Converts a node-set to its boolean value
3450 *
3451 * Returns the boolean value
3452 */
3453int
3454xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3455 if ((ns == NULL) || (ns->nodeNr == 0))
3456 return(0);
3457 return(1);
3458}
3459
3460/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003461 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003462 * @val: an XPath object
3463 *
3464 * Converts an XPath object to its boolean value
3465 *
3466 * Returns the boolean value
3467 */
3468int
3469xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3470 int ret = 0;
3471
3472 if (val == NULL)
3473 return(0);
3474 switch (val->type) {
3475 case XPATH_UNDEFINED:
3476#ifdef DEBUG_EXPR
3477 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3478#endif
3479 ret = 0;
3480 break;
3481 case XPATH_XSLT_TREE:
3482 case XPATH_NODESET:
3483 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3484 break;
3485 case XPATH_STRING:
3486 ret = xmlXPathCastStringToBoolean(val->stringval);
3487 break;
3488 case XPATH_NUMBER:
3489 ret = xmlXPathCastNumberToBoolean(val->floatval);
3490 break;
3491 case XPATH_BOOLEAN:
3492 ret = val->boolval;
3493 break;
3494 case XPATH_USERS:
3495 case XPATH_POINT:
3496 case XPATH_RANGE:
3497 case XPATH_LOCATIONSET:
3498 TODO;
3499 ret = 0;
3500 break;
3501 }
3502 return(ret);
3503}
3504
3505
3506/**
3507 * xmlXPathConvertBoolean:
3508 * @val: an XPath object
3509 *
3510 * Converts an existing object to its boolean() equivalent
3511 *
3512 * Returns the new object, the old one is freed (or the operation
3513 * is done directly on @val)
3514 */
3515xmlXPathObjectPtr
3516xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3517 xmlXPathObjectPtr ret;
3518
3519 if (val == NULL)
3520 return(xmlXPathNewBoolean(0));
3521 if (val->type == XPATH_BOOLEAN)
3522 return(val);
3523 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3524 xmlXPathFreeObject(val);
3525 return(ret);
3526}
3527
Owen Taylor3473f882001-02-23 17:55:21 +00003528/************************************************************************
3529 * *
3530 * Routines to handle XPath contexts *
3531 * *
3532 ************************************************************************/
3533
3534/**
3535 * xmlXPathNewContext:
3536 * @doc: the XML document
3537 *
3538 * Create a new xmlXPathContext
3539 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003540 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003541 */
3542xmlXPathContextPtr
3543xmlXPathNewContext(xmlDocPtr doc) {
3544 xmlXPathContextPtr ret;
3545
3546 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3547 if (ret == NULL) {
3548 xmlGenericError(xmlGenericErrorContext,
3549 "xmlXPathNewContext: out of memory\n");
3550 return(NULL);
3551 }
3552 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3553 ret->doc = doc;
3554 ret->node = NULL;
3555
3556 ret->varHash = NULL;
3557
3558 ret->nb_types = 0;
3559 ret->max_types = 0;
3560 ret->types = NULL;
3561
3562 ret->funcHash = xmlHashCreate(0);
3563
3564 ret->nb_axis = 0;
3565 ret->max_axis = 0;
3566 ret->axis = NULL;
3567
3568 ret->nsHash = NULL;
3569 ret->user = NULL;
3570
3571 ret->contextSize = -1;
3572 ret->proximityPosition = -1;
3573
3574 xmlXPathRegisterAllFunctions(ret);
3575
3576 return(ret);
3577}
3578
3579/**
3580 * xmlXPathFreeContext:
3581 * @ctxt: the context to free
3582 *
3583 * Free up an xmlXPathContext
3584 */
3585void
3586xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3587 xmlXPathRegisteredNsCleanup(ctxt);
3588 xmlXPathRegisteredFuncsCleanup(ctxt);
3589 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003590 xmlFree(ctxt);
3591}
3592
3593/************************************************************************
3594 * *
3595 * Routines to handle XPath parser contexts *
3596 * *
3597 ************************************************************************/
3598
3599#define CHECK_CTXT(ctxt) \
3600 if (ctxt == NULL) { \
3601 xmlGenericError(xmlGenericErrorContext, \
3602 "%s:%d Internal error: ctxt == NULL\n", \
3603 __FILE__, __LINE__); \
3604 } \
3605
3606
3607#define CHECK_CONTEXT(ctxt) \
3608 if (ctxt == NULL) { \
3609 xmlGenericError(xmlGenericErrorContext, \
3610 "%s:%d Internal error: no context\n", \
3611 __FILE__, __LINE__); \
3612 } \
3613 else if (ctxt->doc == NULL) { \
3614 xmlGenericError(xmlGenericErrorContext, \
3615 "%s:%d Internal error: no document\n", \
3616 __FILE__, __LINE__); \
3617 } \
3618 else if (ctxt->doc->children == NULL) { \
3619 xmlGenericError(xmlGenericErrorContext, \
3620 "%s:%d Internal error: document without root\n", \
3621 __FILE__, __LINE__); \
3622 } \
3623
3624
3625/**
3626 * xmlXPathNewParserContext:
3627 * @str: the XPath expression
3628 * @ctxt: the XPath context
3629 *
3630 * Create a new xmlXPathParserContext
3631 *
3632 * Returns the xmlXPathParserContext just allocated.
3633 */
3634xmlXPathParserContextPtr
3635xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3636 xmlXPathParserContextPtr ret;
3637
3638 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3639 if (ret == NULL) {
3640 xmlGenericError(xmlGenericErrorContext,
3641 "xmlXPathNewParserContext: out of memory\n");
3642 return(NULL);
3643 }
3644 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3645 ret->cur = ret->base = str;
3646 ret->context = ctxt;
3647
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003648 ret->comp = xmlXPathNewCompExpr();
3649 if (ret->comp == NULL) {
3650 xmlFree(ret->valueTab);
3651 xmlFree(ret);
3652 return(NULL);
3653 }
3654
3655 return(ret);
3656}
3657
3658/**
3659 * xmlXPathCompParserContext:
3660 * @comp: the XPath compiled expression
3661 * @ctxt: the XPath context
3662 *
3663 * Create a new xmlXPathParserContext when processing a compiled expression
3664 *
3665 * Returns the xmlXPathParserContext just allocated.
3666 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003667static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003668xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3669 xmlXPathParserContextPtr ret;
3670
3671 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3672 if (ret == NULL) {
3673 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003674 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003675 return(NULL);
3676 }
3677 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3678
Owen Taylor3473f882001-02-23 17:55:21 +00003679 /* Allocate the value stack */
3680 ret->valueTab = (xmlXPathObjectPtr *)
3681 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003682 if (ret->valueTab == NULL) {
3683 xmlFree(ret);
3684 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003685 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003686 return(NULL);
3687 }
Owen Taylor3473f882001-02-23 17:55:21 +00003688 ret->valueNr = 0;
3689 ret->valueMax = 10;
3690 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003691
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003692 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003693 ret->comp = comp;
3694
Owen Taylor3473f882001-02-23 17:55:21 +00003695 return(ret);
3696}
3697
3698/**
3699 * xmlXPathFreeParserContext:
3700 * @ctxt: the context to free
3701 *
3702 * Free up an xmlXPathParserContext
3703 */
3704void
3705xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3706 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003707 xmlFree(ctxt->valueTab);
3708 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003709 if (ctxt->comp)
3710 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003711 xmlFree(ctxt);
3712}
3713
3714/************************************************************************
3715 * *
3716 * The implicit core function library *
3717 * *
3718 ************************************************************************/
3719
Owen Taylor3473f882001-02-23 17:55:21 +00003720/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003721 * xmlXPathNodeStringHash:
3722 * @node: a node pointer
3723 *
3724 * Function computing the beginning of the string value of the node,
3725 * used to speed up comparisons
3726 *
3727 * Returns an int usable as a hash
3728 */
3729static unsigned int
3730xmlXPathNodeValHash(xmlNodePtr node) {
3731 int len = 2;
3732 const xmlChar * string = NULL;
3733 xmlNodePtr tmp = NULL;
3734 unsigned int ret = 0;
3735
3736 if (node == NULL)
3737 return(0);
3738
3739
3740 switch (node->type) {
3741 case XML_COMMENT_NODE:
3742 case XML_PI_NODE:
3743 case XML_CDATA_SECTION_NODE:
3744 case XML_TEXT_NODE:
3745 string = node->content;
3746 if (string == NULL)
3747 return(0);
3748 if (string[0] == 0)
3749 return(0);
3750 return(((unsigned int) string[0]) +
3751 (((unsigned int) string[1]) << 8));
3752 case XML_NAMESPACE_DECL:
3753 string = ((xmlNsPtr)node)->href;
3754 if (string == NULL)
3755 return(0);
3756 if (string[0] == 0)
3757 return(0);
3758 return(((unsigned int) string[0]) +
3759 (((unsigned int) string[1]) << 8));
3760 case XML_ATTRIBUTE_NODE:
3761 tmp = ((xmlAttrPtr) node)->children;
3762 break;
3763 case XML_ELEMENT_NODE:
3764 tmp = node->children;
3765 break;
3766 default:
3767 return(0);
3768 }
3769 while (tmp != NULL) {
3770 switch (tmp->type) {
3771 case XML_COMMENT_NODE:
3772 case XML_PI_NODE:
3773 case XML_CDATA_SECTION_NODE:
3774 case XML_TEXT_NODE:
3775 string = tmp->content;
3776 break;
3777 case XML_NAMESPACE_DECL:
3778 string = ((xmlNsPtr)tmp)->href;
3779 break;
3780 default:
3781 break;
3782 }
3783 if ((string != NULL) && (string[0] != 0)) {
3784 if (string[0] == 0)
3785 return(0);
3786 if (len == 1) {
3787 return(ret + (((unsigned int) string[0]) << 8));
3788 }
3789 if (string[1] == 0) {
3790 len = 1;
3791 ret = (unsigned int) string[0];
3792 } else {
3793 return(((unsigned int) string[0]) +
3794 (((unsigned int) string[1]) << 8));
3795 }
3796 }
3797 /*
3798 * Skip to next node
3799 */
3800 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3801 if (tmp->children->type != XML_ENTITY_DECL) {
3802 tmp = tmp->children;
3803 continue;
3804 }
3805 }
3806 if (tmp == node)
3807 break;
3808
3809 if (tmp->next != NULL) {
3810 tmp = tmp->next;
3811 continue;
3812 }
3813
3814 do {
3815 tmp = tmp->parent;
3816 if (tmp == NULL)
3817 break;
3818 if (tmp == node) {
3819 tmp = NULL;
3820 break;
3821 }
3822 if (tmp->next != NULL) {
3823 tmp = tmp->next;
3824 break;
3825 }
3826 } while (tmp != NULL);
3827 }
3828 return(ret);
3829}
3830
3831/**
3832 * xmlXPathStringHash:
3833 * @string: a string
3834 *
3835 * Function computing the beginning of the string value of the node,
3836 * used to speed up comparisons
3837 *
3838 * Returns an int usable as a hash
3839 */
3840static unsigned int
3841xmlXPathStringHash(const xmlChar * string) {
3842 if (string == NULL)
3843 return((unsigned int) 0);
3844 if (string[0] == 0)
3845 return(0);
3846 return(((unsigned int) string[0]) +
3847 (((unsigned int) string[1]) << 8));
3848}
3849
3850/**
Owen Taylor3473f882001-02-23 17:55:21 +00003851 * xmlXPathCompareNodeSetFloat:
3852 * @ctxt: the XPath Parser context
3853 * @inf: less than (1) or greater than (0)
3854 * @strict: is the comparison strict
3855 * @arg: the node set
3856 * @f: the value
3857 *
3858 * Implement the compare operation between a nodeset and a number
3859 * @ns < @val (1, 1, ...
3860 * @ns <= @val (1, 0, ...
3861 * @ns > @val (0, 1, ...
3862 * @ns >= @val (0, 0, ...
3863 *
3864 * If one object to be compared is a node-set and the other is a number,
3865 * then the comparison will be true if and only if there is a node in the
3866 * node-set such that the result of performing the comparison on the number
3867 * to be compared and on the result of converting the string-value of that
3868 * node to a number using the number function is true.
3869 *
3870 * Returns 0 or 1 depending on the results of the test.
3871 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003872static int
Owen Taylor3473f882001-02-23 17:55:21 +00003873xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3874 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3875 int i, ret = 0;
3876 xmlNodeSetPtr ns;
3877 xmlChar *str2;
3878
3879 if ((f == NULL) || (arg == NULL) ||
3880 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3881 xmlXPathFreeObject(arg);
3882 xmlXPathFreeObject(f);
3883 return(0);
3884 }
3885 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003886 if (ns != NULL) {
3887 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003888 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003889 if (str2 != NULL) {
3890 valuePush(ctxt,
3891 xmlXPathNewString(str2));
3892 xmlFree(str2);
3893 xmlXPathNumberFunction(ctxt, 1);
3894 valuePush(ctxt, xmlXPathObjectCopy(f));
3895 ret = xmlXPathCompareValues(ctxt, inf, strict);
3896 if (ret)
3897 break;
3898 }
3899 }
Owen Taylor3473f882001-02-23 17:55:21 +00003900 }
3901 xmlXPathFreeObject(arg);
3902 xmlXPathFreeObject(f);
3903 return(ret);
3904}
3905
3906/**
3907 * xmlXPathCompareNodeSetString:
3908 * @ctxt: the XPath Parser context
3909 * @inf: less than (1) or greater than (0)
3910 * @strict: is the comparison strict
3911 * @arg: the node set
3912 * @s: the value
3913 *
3914 * Implement the compare operation between a nodeset and a string
3915 * @ns < @val (1, 1, ...
3916 * @ns <= @val (1, 0, ...
3917 * @ns > @val (0, 1, ...
3918 * @ns >= @val (0, 0, ...
3919 *
3920 * If one object to be compared is a node-set and the other is a string,
3921 * then the comparison will be true if and only if there is a node in
3922 * the node-set such that the result of performing the comparison on the
3923 * string-value of the node and the other string is true.
3924 *
3925 * Returns 0 or 1 depending on the results of the test.
3926 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003927static int
Owen Taylor3473f882001-02-23 17:55:21 +00003928xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3929 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3930 int i, ret = 0;
3931 xmlNodeSetPtr ns;
3932 xmlChar *str2;
3933
3934 if ((s == NULL) || (arg == NULL) ||
3935 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3936 xmlXPathFreeObject(arg);
3937 xmlXPathFreeObject(s);
3938 return(0);
3939 }
3940 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003941 if (ns != NULL) {
3942 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003943 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003944 if (str2 != NULL) {
3945 valuePush(ctxt,
3946 xmlXPathNewString(str2));
3947 xmlFree(str2);
3948 valuePush(ctxt, xmlXPathObjectCopy(s));
3949 ret = xmlXPathCompareValues(ctxt, inf, strict);
3950 if (ret)
3951 break;
3952 }
3953 }
Owen Taylor3473f882001-02-23 17:55:21 +00003954 }
3955 xmlXPathFreeObject(arg);
3956 xmlXPathFreeObject(s);
3957 return(ret);
3958}
3959
3960/**
3961 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003962 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003963 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003964 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00003965 * @arg2: the second node set object
3966 *
3967 * Implement the compare operation on nodesets:
3968 *
3969 * If both objects to be compared are node-sets, then the comparison
3970 * will be true if and only if there is a node in the first node-set
3971 * and a node in the second node-set such that the result of performing
3972 * the comparison on the string-values of the two nodes is true.
3973 * ....
3974 * When neither object to be compared is a node-set and the operator
3975 * is <=, <, >= or >, then the objects are compared by converting both
3976 * objects to numbers and comparing the numbers according to IEEE 754.
3977 * ....
3978 * The number function converts its argument to a number as follows:
3979 * - a string that consists of optional whitespace followed by an
3980 * optional minus sign followed by a Number followed by whitespace
3981 * is converted to the IEEE 754 number that is nearest (according
3982 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3983 * represented by the string; any other string is converted to NaN
3984 *
3985 * Conclusion all nodes need to be converted first to their string value
3986 * and then the comparison must be done when possible
3987 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003988static int
3989xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003990 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3991 int i, j, init = 0;
3992 double val1;
3993 double *values2;
3994 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003995 xmlNodeSetPtr ns1;
3996 xmlNodeSetPtr ns2;
3997
3998 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003999 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4000 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004001 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004002 }
Owen Taylor3473f882001-02-23 17:55:21 +00004003 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004004 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4005 xmlXPathFreeObject(arg1);
4006 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004007 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004008 }
Owen Taylor3473f882001-02-23 17:55:21 +00004009
4010 ns1 = arg1->nodesetval;
4011 ns2 = arg2->nodesetval;
4012
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004013 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004014 xmlXPathFreeObject(arg1);
4015 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004016 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004017 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004018 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004019 xmlXPathFreeObject(arg1);
4020 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004021 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004022 }
Owen Taylor3473f882001-02-23 17:55:21 +00004023
4024 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4025 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004026 xmlXPathFreeObject(arg1);
4027 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004028 return(0);
4029 }
4030 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004031 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004032 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004033 continue;
4034 for (j = 0;j < ns2->nodeNr;j++) {
4035 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004036 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004037 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004038 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004039 continue;
4040 if (inf && strict)
4041 ret = (val1 < values2[j]);
4042 else if (inf && !strict)
4043 ret = (val1 <= values2[j]);
4044 else if (!inf && strict)
4045 ret = (val1 > values2[j]);
4046 else if (!inf && !strict)
4047 ret = (val1 >= values2[j]);
4048 if (ret)
4049 break;
4050 }
4051 if (ret)
4052 break;
4053 init = 1;
4054 }
4055 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004056 xmlXPathFreeObject(arg1);
4057 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004058 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004059}
4060
4061/**
4062 * xmlXPathCompareNodeSetValue:
4063 * @ctxt: the XPath Parser context
4064 * @inf: less than (1) or greater than (0)
4065 * @strict: is the comparison strict
4066 * @arg: the node set
4067 * @val: the value
4068 *
4069 * Implement the compare operation between a nodeset and a value
4070 * @ns < @val (1, 1, ...
4071 * @ns <= @val (1, 0, ...
4072 * @ns > @val (0, 1, ...
4073 * @ns >= @val (0, 0, ...
4074 *
4075 * If one object to be compared is a node-set and the other is a boolean,
4076 * then the comparison will be true if and only if the result of performing
4077 * the comparison on the boolean and on the result of converting
4078 * the node-set to a boolean using the boolean function is true.
4079 *
4080 * Returns 0 or 1 depending on the results of the test.
4081 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004082static int
Owen Taylor3473f882001-02-23 17:55:21 +00004083xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4084 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4085 if ((val == NULL) || (arg == NULL) ||
4086 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4087 return(0);
4088
4089 switch(val->type) {
4090 case XPATH_NUMBER:
4091 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4092 case XPATH_NODESET:
4093 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004094 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004095 case XPATH_STRING:
4096 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4097 case XPATH_BOOLEAN:
4098 valuePush(ctxt, arg);
4099 xmlXPathBooleanFunction(ctxt, 1);
4100 valuePush(ctxt, val);
4101 return(xmlXPathCompareValues(ctxt, inf, strict));
4102 default:
4103 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004104 }
4105 return(0);
4106}
4107
4108/**
4109 * xmlXPathEqualNodeSetString
4110 * @arg: the nodeset object argument
4111 * @str: the string to compare to.
4112 *
4113 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4114 * If one object to be compared is a node-set and the other is a string,
4115 * then the comparison will be true if and only if there is a node in
4116 * the node-set such that the result of performing the comparison on the
4117 * string-value of the node and the other string is true.
4118 *
4119 * Returns 0 or 1 depending on the results of the test.
4120 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004121static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00004122xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
4123{
Owen Taylor3473f882001-02-23 17:55:21 +00004124 int i;
4125 xmlNodeSetPtr ns;
4126 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004127 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004128
4129 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004130 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4131 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004132 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004133 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004134 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004135 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004136 if (ns->nodeNr <= 0) {
4137 if (hash == 0)
4138 return(1);
4139 return(0);
4140 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004141 for (i = 0; i < ns->nodeNr; i++) {
4142 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4143 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4144 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4145 xmlFree(str2);
4146 return (1);
4147 }
4148 if (str2 != NULL)
4149 xmlFree(str2);
4150 }
Owen Taylor3473f882001-02-23 17:55:21 +00004151 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004152 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004153}
4154
4155/**
4156 * xmlXPathEqualNodeSetFloat
4157 * @arg: the nodeset object argument
4158 * @f: the float to compare to
4159 *
4160 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4161 * If one object to be compared is a node-set and the other is a number,
4162 * then the comparison will be true if and only if there is a node in
4163 * the node-set such that the result of performing the comparison on the
4164 * number to be compared and on the result of converting the string-value
4165 * of that node to a number using the number function is true.
4166 *
4167 * Returns 0 or 1 depending on the results of the test.
4168 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004169static int
Owen Taylor3473f882001-02-23 17:55:21 +00004170xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
4171 char buf[100] = "";
4172
4173 if ((arg == NULL) ||
4174 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4175 return(0);
4176
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004177 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00004178 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
4179}
4180
4181
4182/**
4183 * xmlXPathEqualNodeSets
4184 * @arg1: first nodeset object argument
4185 * @arg2: second nodeset object argument
4186 *
4187 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
4188 * If both objects to be compared are node-sets, then the comparison
4189 * will be true if and only if there is a node in the first node-set and
4190 * a node in the second node-set such that the result of performing the
4191 * comparison on the string-values of the two nodes is true.
4192 *
4193 * (needless to say, this is a costly operation)
4194 *
4195 * Returns 0 or 1 depending on the results of the test.
4196 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004197static int
Owen Taylor3473f882001-02-23 17:55:21 +00004198xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4199 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004200 unsigned int *hashs1;
4201 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004202 xmlChar **values1;
4203 xmlChar **values2;
4204 int ret = 0;
4205 xmlNodeSetPtr ns1;
4206 xmlNodeSetPtr ns2;
4207
4208 if ((arg1 == NULL) ||
4209 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4210 return(0);
4211 if ((arg2 == NULL) ||
4212 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4213 return(0);
4214
4215 ns1 = arg1->nodesetval;
4216 ns2 = arg2->nodesetval;
4217
Daniel Veillard911f49a2001-04-07 15:39:35 +00004218 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004219 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004220 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004221 return(0);
4222
4223 /*
4224 * check if there is a node pertaining to both sets
4225 */
4226 for (i = 0;i < ns1->nodeNr;i++)
4227 for (j = 0;j < ns2->nodeNr;j++)
4228 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4229 return(1);
4230
4231 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4232 if (values1 == NULL)
4233 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004234 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4235 if (hashs1 == NULL) {
4236 xmlFree(values1);
4237 return(0);
4238 }
Owen Taylor3473f882001-02-23 17:55:21 +00004239 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4240 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4241 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004242 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004243 xmlFree(values1);
4244 return(0);
4245 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004246 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4247 if (hashs2 == NULL) {
4248 xmlFree(hashs1);
4249 xmlFree(values1);
4250 xmlFree(values2);
4251 return(0);
4252 }
Owen Taylor3473f882001-02-23 17:55:21 +00004253 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4254 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004255 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004256 for (j = 0;j < ns2->nodeNr;j++) {
4257 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004258 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4259 if (hashs1[i] == hashs2[j]) {
4260 if (values1[i] == NULL)
4261 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4262 if (values2[j] == NULL)
4263 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4264 ret = xmlStrEqual(values1[i], values2[j]);
4265 if (ret)
4266 break;
4267 }
Owen Taylor3473f882001-02-23 17:55:21 +00004268 }
4269 if (ret)
4270 break;
4271 }
4272 for (i = 0;i < ns1->nodeNr;i++)
4273 if (values1[i] != NULL)
4274 xmlFree(values1[i]);
4275 for (j = 0;j < ns2->nodeNr;j++)
4276 if (values2[j] != NULL)
4277 xmlFree(values2[j]);
4278 xmlFree(values1);
4279 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004280 xmlFree(hashs1);
4281 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004282 return(ret);
4283}
4284
4285/**
4286 * xmlXPathEqualValues:
4287 * @ctxt: the XPath Parser context
4288 *
4289 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4290 *
4291 * Returns 0 or 1 depending on the results of the test.
4292 */
4293int
4294xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4295 xmlXPathObjectPtr arg1, arg2;
4296 int ret = 0;
4297
4298 arg1 = valuePop(ctxt);
4299 if (arg1 == NULL)
4300 XP_ERROR0(XPATH_INVALID_OPERAND);
4301
4302 arg2 = valuePop(ctxt);
4303 if (arg2 == NULL) {
4304 xmlXPathFreeObject(arg1);
4305 XP_ERROR0(XPATH_INVALID_OPERAND);
4306 }
4307
4308 if (arg1 == arg2) {
4309#ifdef DEBUG_EXPR
4310 xmlGenericError(xmlGenericErrorContext,
4311 "Equal: by pointer\n");
4312#endif
4313 return(1);
4314 }
4315
4316 switch (arg1->type) {
4317 case XPATH_UNDEFINED:
4318#ifdef DEBUG_EXPR
4319 xmlGenericError(xmlGenericErrorContext,
4320 "Equal: undefined\n");
4321#endif
4322 break;
4323 case XPATH_XSLT_TREE:
4324 case XPATH_NODESET:
4325 switch (arg2->type) {
4326 case XPATH_UNDEFINED:
4327#ifdef DEBUG_EXPR
4328 xmlGenericError(xmlGenericErrorContext,
4329 "Equal: undefined\n");
4330#endif
4331 break;
4332 case XPATH_XSLT_TREE:
4333 case XPATH_NODESET:
4334 ret = xmlXPathEqualNodeSets(arg1, arg2);
4335 break;
4336 case XPATH_BOOLEAN:
4337 if ((arg1->nodesetval == NULL) ||
4338 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4339 else
4340 ret = 1;
4341 ret = (ret == arg2->boolval);
4342 break;
4343 case XPATH_NUMBER:
4344 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4345 break;
4346 case XPATH_STRING:
4347 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4348 break;
4349 case XPATH_USERS:
4350 case XPATH_POINT:
4351 case XPATH_RANGE:
4352 case XPATH_LOCATIONSET:
4353 TODO
4354 break;
4355 }
4356 break;
4357 case XPATH_BOOLEAN:
4358 switch (arg2->type) {
4359 case XPATH_UNDEFINED:
4360#ifdef DEBUG_EXPR
4361 xmlGenericError(xmlGenericErrorContext,
4362 "Equal: undefined\n");
4363#endif
4364 break;
4365 case XPATH_NODESET:
4366 case XPATH_XSLT_TREE:
4367 if ((arg2->nodesetval == NULL) ||
4368 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4369 else
4370 ret = 1;
4371 break;
4372 case XPATH_BOOLEAN:
4373#ifdef DEBUG_EXPR
4374 xmlGenericError(xmlGenericErrorContext,
4375 "Equal: %d boolean %d \n",
4376 arg1->boolval, arg2->boolval);
4377#endif
4378 ret = (arg1->boolval == arg2->boolval);
4379 break;
4380 case XPATH_NUMBER:
4381 if (arg2->floatval) ret = 1;
4382 else ret = 0;
4383 ret = (arg1->boolval == ret);
4384 break;
4385 case XPATH_STRING:
4386 if ((arg2->stringval == NULL) ||
4387 (arg2->stringval[0] == 0)) ret = 0;
4388 else
4389 ret = 1;
4390 ret = (arg1->boolval == ret);
4391 break;
4392 case XPATH_USERS:
4393 case XPATH_POINT:
4394 case XPATH_RANGE:
4395 case XPATH_LOCATIONSET:
4396 TODO
4397 break;
4398 }
4399 break;
4400 case XPATH_NUMBER:
4401 switch (arg2->type) {
4402 case XPATH_UNDEFINED:
4403#ifdef DEBUG_EXPR
4404 xmlGenericError(xmlGenericErrorContext,
4405 "Equal: undefined\n");
4406#endif
4407 break;
4408 case XPATH_NODESET:
4409 case XPATH_XSLT_TREE:
4410 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4411 break;
4412 case XPATH_BOOLEAN:
4413 if (arg1->floatval) ret = 1;
4414 else ret = 0;
4415 ret = (arg2->boolval == ret);
4416 break;
4417 case XPATH_STRING:
4418 valuePush(ctxt, arg2);
4419 xmlXPathNumberFunction(ctxt, 1);
4420 arg2 = valuePop(ctxt);
4421 /* no break on purpose */
4422 case XPATH_NUMBER:
4423 ret = (arg1->floatval == arg2->floatval);
4424 break;
4425 case XPATH_USERS:
4426 case XPATH_POINT:
4427 case XPATH_RANGE:
4428 case XPATH_LOCATIONSET:
4429 TODO
4430 break;
4431 }
4432 break;
4433 case XPATH_STRING:
4434 switch (arg2->type) {
4435 case XPATH_UNDEFINED:
4436#ifdef DEBUG_EXPR
4437 xmlGenericError(xmlGenericErrorContext,
4438 "Equal: undefined\n");
4439#endif
4440 break;
4441 case XPATH_NODESET:
4442 case XPATH_XSLT_TREE:
4443 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4444 break;
4445 case XPATH_BOOLEAN:
4446 if ((arg1->stringval == NULL) ||
4447 (arg1->stringval[0] == 0)) ret = 0;
4448 else
4449 ret = 1;
4450 ret = (arg2->boolval == ret);
4451 break;
4452 case XPATH_STRING:
4453 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4454 break;
4455 case XPATH_NUMBER:
4456 valuePush(ctxt, arg1);
4457 xmlXPathNumberFunction(ctxt, 1);
4458 arg1 = valuePop(ctxt);
4459 ret = (arg1->floatval == arg2->floatval);
4460 break;
4461 case XPATH_USERS:
4462 case XPATH_POINT:
4463 case XPATH_RANGE:
4464 case XPATH_LOCATIONSET:
4465 TODO
4466 break;
4467 }
4468 break;
4469 case XPATH_USERS:
4470 case XPATH_POINT:
4471 case XPATH_RANGE:
4472 case XPATH_LOCATIONSET:
4473 TODO
4474 break;
4475 }
4476 xmlXPathFreeObject(arg1);
4477 xmlXPathFreeObject(arg2);
4478 return(ret);
4479}
4480
4481
4482/**
4483 * xmlXPathCompareValues:
4484 * @ctxt: the XPath Parser context
4485 * @inf: less than (1) or greater than (0)
4486 * @strict: is the comparison strict
4487 *
4488 * Implement the compare operation on XPath objects:
4489 * @arg1 < @arg2 (1, 1, ...
4490 * @arg1 <= @arg2 (1, 0, ...
4491 * @arg1 > @arg2 (0, 1, ...
4492 * @arg1 >= @arg2 (0, 0, ...
4493 *
4494 * When neither object to be compared is a node-set and the operator is
4495 * <=, <, >=, >, then the objects are compared by converted both objects
4496 * to numbers and comparing the numbers according to IEEE 754. The <
4497 * comparison will be true if and only if the first number is less than the
4498 * second number. The <= comparison will be true if and only if the first
4499 * number is less than or equal to the second number. The > comparison
4500 * will be true if and only if the first number is greater than the second
4501 * number. The >= comparison will be true if and only if the first number
4502 * is greater than or equal to the second number.
4503 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004504 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004505 */
4506int
4507xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4508 int ret = 0;
4509 xmlXPathObjectPtr arg1, arg2;
4510
4511 arg2 = valuePop(ctxt);
4512 if (arg2 == NULL) {
4513 XP_ERROR0(XPATH_INVALID_OPERAND);
4514 }
4515
4516 arg1 = valuePop(ctxt);
4517 if (arg1 == NULL) {
4518 xmlXPathFreeObject(arg2);
4519 XP_ERROR0(XPATH_INVALID_OPERAND);
4520 }
4521
4522 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4523 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004524 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004525 } else {
4526 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004527 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4528 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004529 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004530 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4531 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004532 }
4533 }
4534 return(ret);
4535 }
4536
4537 if (arg1->type != XPATH_NUMBER) {
4538 valuePush(ctxt, arg1);
4539 xmlXPathNumberFunction(ctxt, 1);
4540 arg1 = valuePop(ctxt);
4541 }
4542 if (arg1->type != XPATH_NUMBER) {
4543 xmlXPathFreeObject(arg1);
4544 xmlXPathFreeObject(arg2);
4545 XP_ERROR0(XPATH_INVALID_OPERAND);
4546 }
4547 if (arg2->type != XPATH_NUMBER) {
4548 valuePush(ctxt, arg2);
4549 xmlXPathNumberFunction(ctxt, 1);
4550 arg2 = valuePop(ctxt);
4551 }
4552 if (arg2->type != XPATH_NUMBER) {
4553 xmlXPathFreeObject(arg1);
4554 xmlXPathFreeObject(arg2);
4555 XP_ERROR0(XPATH_INVALID_OPERAND);
4556 }
4557 /*
4558 * Add tests for infinity and nan
4559 * => feedback on 3.4 for Inf and NaN
4560 */
4561 if (inf && strict)
4562 ret = (arg1->floatval < arg2->floatval);
4563 else if (inf && !strict)
4564 ret = (arg1->floatval <= arg2->floatval);
4565 else if (!inf && strict)
4566 ret = (arg1->floatval > arg2->floatval);
4567 else if (!inf && !strict)
4568 ret = (arg1->floatval >= arg2->floatval);
4569 xmlXPathFreeObject(arg1);
4570 xmlXPathFreeObject(arg2);
4571 return(ret);
4572}
4573
4574/**
4575 * xmlXPathValueFlipSign:
4576 * @ctxt: the XPath Parser context
4577 *
4578 * Implement the unary - operation on an XPath object
4579 * The numeric operators convert their operands to numbers as if
4580 * by calling the number function.
4581 */
4582void
4583xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004584 CAST_TO_NUMBER;
4585 CHECK_TYPE(XPATH_NUMBER);
4586 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004587}
4588
4589/**
4590 * xmlXPathAddValues:
4591 * @ctxt: the XPath Parser context
4592 *
4593 * Implement the add operation on XPath objects:
4594 * The numeric operators convert their operands to numbers as if
4595 * by calling the number function.
4596 */
4597void
4598xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4599 xmlXPathObjectPtr arg;
4600 double val;
4601
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004602 arg = valuePop(ctxt);
4603 if (arg == NULL)
4604 XP_ERROR(XPATH_INVALID_OPERAND);
4605 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004606 xmlXPathFreeObject(arg);
4607
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004608 CAST_TO_NUMBER;
4609 CHECK_TYPE(XPATH_NUMBER);
4610 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004611}
4612
4613/**
4614 * xmlXPathSubValues:
4615 * @ctxt: the XPath Parser context
4616 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004617 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004618 * The numeric operators convert their operands to numbers as if
4619 * by calling the number function.
4620 */
4621void
4622xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4623 xmlXPathObjectPtr arg;
4624 double val;
4625
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004626 arg = valuePop(ctxt);
4627 if (arg == NULL)
4628 XP_ERROR(XPATH_INVALID_OPERAND);
4629 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004630 xmlXPathFreeObject(arg);
4631
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004632 CAST_TO_NUMBER;
4633 CHECK_TYPE(XPATH_NUMBER);
4634 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004635}
4636
4637/**
4638 * xmlXPathMultValues:
4639 * @ctxt: the XPath Parser context
4640 *
4641 * Implement the multiply operation on XPath objects:
4642 * The numeric operators convert their operands to numbers as if
4643 * by calling the number function.
4644 */
4645void
4646xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4647 xmlXPathObjectPtr arg;
4648 double val;
4649
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004650 arg = valuePop(ctxt);
4651 if (arg == NULL)
4652 XP_ERROR(XPATH_INVALID_OPERAND);
4653 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004654 xmlXPathFreeObject(arg);
4655
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004656 CAST_TO_NUMBER;
4657 CHECK_TYPE(XPATH_NUMBER);
4658 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004659}
4660
4661/**
4662 * xmlXPathDivValues:
4663 * @ctxt: the XPath Parser context
4664 *
4665 * Implement the div operation on XPath objects @arg1 / @arg2:
4666 * The numeric operators convert their operands to numbers as if
4667 * by calling the number function.
4668 */
4669void
4670xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4671 xmlXPathObjectPtr arg;
4672 double val;
4673
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004674 arg = valuePop(ctxt);
4675 if (arg == NULL)
4676 XP_ERROR(XPATH_INVALID_OPERAND);
4677 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004678 xmlXPathFreeObject(arg);
4679
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004680 CAST_TO_NUMBER;
4681 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004682 if (val == 0) {
4683 if (ctxt->value->floatval == 0)
4684 ctxt->value->floatval = xmlXPathNAN;
4685 else if (ctxt->value->floatval > 0)
4686 ctxt->value->floatval = xmlXPathPINF;
4687 else if (ctxt->value->floatval < 0)
4688 ctxt->value->floatval = xmlXPathNINF;
4689 } else
4690 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004691}
4692
4693/**
4694 * xmlXPathModValues:
4695 * @ctxt: the XPath Parser context
4696 *
4697 * Implement the mod operation on XPath objects: @arg1 / @arg2
4698 * The numeric operators convert their operands to numbers as if
4699 * by calling the number function.
4700 */
4701void
4702xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4703 xmlXPathObjectPtr arg;
4704 int arg1, arg2;
4705
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004706 arg = valuePop(ctxt);
4707 if (arg == NULL)
4708 XP_ERROR(XPATH_INVALID_OPERAND);
4709 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004710 xmlXPathFreeObject(arg);
4711
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004712 CAST_TO_NUMBER;
4713 CHECK_TYPE(XPATH_NUMBER);
4714 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004715 if (arg2 == 0)
4716 ctxt->value->floatval = xmlXPathNAN;
4717 else
4718 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004719}
4720
4721/************************************************************************
4722 * *
4723 * The traversal functions *
4724 * *
4725 ************************************************************************/
4726
Owen Taylor3473f882001-02-23 17:55:21 +00004727/*
4728 * A traversal function enumerates nodes along an axis.
4729 * Initially it must be called with NULL, and it indicates
4730 * termination on the axis by returning NULL.
4731 */
4732typedef xmlNodePtr (*xmlXPathTraversalFunction)
4733 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4734
4735/**
4736 * xmlXPathNextSelf:
4737 * @ctxt: the XPath Parser context
4738 * @cur: the current node in the traversal
4739 *
4740 * Traversal function for the "self" direction
4741 * The self axis contains just the context node itself
4742 *
4743 * Returns the next element following that axis
4744 */
4745xmlNodePtr
4746xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4747 if (cur == NULL)
4748 return(ctxt->context->node);
4749 return(NULL);
4750}
4751
4752/**
4753 * xmlXPathNextChild:
4754 * @ctxt: the XPath Parser context
4755 * @cur: the current node in the traversal
4756 *
4757 * Traversal function for the "child" direction
4758 * The child axis contains the children of the context node in document order.
4759 *
4760 * Returns the next element following that axis
4761 */
4762xmlNodePtr
4763xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4764 if (cur == NULL) {
4765 if (ctxt->context->node == NULL) return(NULL);
4766 switch (ctxt->context->node->type) {
4767 case XML_ELEMENT_NODE:
4768 case XML_TEXT_NODE:
4769 case XML_CDATA_SECTION_NODE:
4770 case XML_ENTITY_REF_NODE:
4771 case XML_ENTITY_NODE:
4772 case XML_PI_NODE:
4773 case XML_COMMENT_NODE:
4774 case XML_NOTATION_NODE:
4775 case XML_DTD_NODE:
4776 return(ctxt->context->node->children);
4777 case XML_DOCUMENT_NODE:
4778 case XML_DOCUMENT_TYPE_NODE:
4779 case XML_DOCUMENT_FRAG_NODE:
4780 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004781#ifdef LIBXML_DOCB_ENABLED
4782 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004783#endif
4784 return(((xmlDocPtr) ctxt->context->node)->children);
4785 case XML_ELEMENT_DECL:
4786 case XML_ATTRIBUTE_DECL:
4787 case XML_ENTITY_DECL:
4788 case XML_ATTRIBUTE_NODE:
4789 case XML_NAMESPACE_DECL:
4790 case XML_XINCLUDE_START:
4791 case XML_XINCLUDE_END:
4792 return(NULL);
4793 }
4794 return(NULL);
4795 }
4796 if ((cur->type == XML_DOCUMENT_NODE) ||
4797 (cur->type == XML_HTML_DOCUMENT_NODE))
4798 return(NULL);
4799 return(cur->next);
4800}
4801
4802/**
4803 * xmlXPathNextDescendant:
4804 * @ctxt: the XPath Parser context
4805 * @cur: the current node in the traversal
4806 *
4807 * Traversal function for the "descendant" direction
4808 * the descendant axis contains the descendants of the context node in document
4809 * order; a descendant is a child or a child of a child and so on.
4810 *
4811 * Returns the next element following that axis
4812 */
4813xmlNodePtr
4814xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4815 if (cur == NULL) {
4816 if (ctxt->context->node == NULL)
4817 return(NULL);
4818 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4819 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4820 return(NULL);
4821
4822 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4823 return(ctxt->context->doc->children);
4824 return(ctxt->context->node->children);
4825 }
4826
Daniel Veillard567e1b42001-08-01 15:53:47 +00004827 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004828 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004829 return(cur->children);
4830 }
4831
4832 if (cur == ctxt->context->node) return(NULL);
4833
Owen Taylor3473f882001-02-23 17:55:21 +00004834 if (cur->next != NULL) return(cur->next);
4835
4836 do {
4837 cur = cur->parent;
4838 if (cur == NULL) return(NULL);
4839 if (cur == ctxt->context->node) return(NULL);
4840 if (cur->next != NULL) {
4841 cur = cur->next;
4842 return(cur);
4843 }
4844 } while (cur != NULL);
4845 return(cur);
4846}
4847
4848/**
4849 * xmlXPathNextDescendantOrSelf:
4850 * @ctxt: the XPath Parser context
4851 * @cur: the current node in the traversal
4852 *
4853 * Traversal function for the "descendant-or-self" direction
4854 * the descendant-or-self axis contains the context node and the descendants
4855 * of the context node in document order; thus the context node is the first
4856 * node on the axis, and the first child of the context node is the second node
4857 * on the axis
4858 *
4859 * Returns the next element following that axis
4860 */
4861xmlNodePtr
4862xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4863 if (cur == NULL) {
4864 if (ctxt->context->node == NULL)
4865 return(NULL);
4866 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4867 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4868 return(NULL);
4869 return(ctxt->context->node);
4870 }
4871
4872 return(xmlXPathNextDescendant(ctxt, cur));
4873}
4874
4875/**
4876 * xmlXPathNextParent:
4877 * @ctxt: the XPath Parser context
4878 * @cur: the current node in the traversal
4879 *
4880 * Traversal function for the "parent" direction
4881 * The parent axis contains the parent of the context node, if there is one.
4882 *
4883 * Returns the next element following that axis
4884 */
4885xmlNodePtr
4886xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4887 /*
4888 * the parent of an attribute or namespace node is the element
4889 * to which the attribute or namespace node is attached
4890 * Namespace handling !!!
4891 */
4892 if (cur == NULL) {
4893 if (ctxt->context->node == NULL) return(NULL);
4894 switch (ctxt->context->node->type) {
4895 case XML_ELEMENT_NODE:
4896 case XML_TEXT_NODE:
4897 case XML_CDATA_SECTION_NODE:
4898 case XML_ENTITY_REF_NODE:
4899 case XML_ENTITY_NODE:
4900 case XML_PI_NODE:
4901 case XML_COMMENT_NODE:
4902 case XML_NOTATION_NODE:
4903 case XML_DTD_NODE:
4904 case XML_ELEMENT_DECL:
4905 case XML_ATTRIBUTE_DECL:
4906 case XML_XINCLUDE_START:
4907 case XML_XINCLUDE_END:
4908 case XML_ENTITY_DECL:
4909 if (ctxt->context->node->parent == NULL)
4910 return((xmlNodePtr) ctxt->context->doc);
4911 return(ctxt->context->node->parent);
4912 case XML_ATTRIBUTE_NODE: {
4913 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4914
4915 return(att->parent);
4916 }
4917 case XML_DOCUMENT_NODE:
4918 case XML_DOCUMENT_TYPE_NODE:
4919 case XML_DOCUMENT_FRAG_NODE:
4920 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004921#ifdef LIBXML_DOCB_ENABLED
4922 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004923#endif
4924 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004925 case XML_NAMESPACE_DECL: {
4926 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
4927
4928 if ((ns->next != NULL) &&
4929 (ns->next->type != XML_NAMESPACE_DECL))
4930 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00004931 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004932 }
Owen Taylor3473f882001-02-23 17:55:21 +00004933 }
4934 }
4935 return(NULL);
4936}
4937
4938/**
4939 * xmlXPathNextAncestor:
4940 * @ctxt: the XPath Parser context
4941 * @cur: the current node in the traversal
4942 *
4943 * Traversal function for the "ancestor" direction
4944 * the ancestor axis contains the ancestors of the context node; the ancestors
4945 * of the context node consist of the parent of context node and the parent's
4946 * parent and so on; the nodes are ordered in reverse document order; thus the
4947 * parent is the first node on the axis, and the parent's parent is the second
4948 * node on the axis
4949 *
4950 * Returns the next element following that axis
4951 */
4952xmlNodePtr
4953xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4954 /*
4955 * the parent of an attribute or namespace node is the element
4956 * to which the attribute or namespace node is attached
4957 * !!!!!!!!!!!!!
4958 */
4959 if (cur == NULL) {
4960 if (ctxt->context->node == NULL) return(NULL);
4961 switch (ctxt->context->node->type) {
4962 case XML_ELEMENT_NODE:
4963 case XML_TEXT_NODE:
4964 case XML_CDATA_SECTION_NODE:
4965 case XML_ENTITY_REF_NODE:
4966 case XML_ENTITY_NODE:
4967 case XML_PI_NODE:
4968 case XML_COMMENT_NODE:
4969 case XML_DTD_NODE:
4970 case XML_ELEMENT_DECL:
4971 case XML_ATTRIBUTE_DECL:
4972 case XML_ENTITY_DECL:
4973 case XML_NOTATION_NODE:
4974 case XML_XINCLUDE_START:
4975 case XML_XINCLUDE_END:
4976 if (ctxt->context->node->parent == NULL)
4977 return((xmlNodePtr) ctxt->context->doc);
4978 return(ctxt->context->node->parent);
4979 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004980 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004981
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004982 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004983 }
4984 case XML_DOCUMENT_NODE:
4985 case XML_DOCUMENT_TYPE_NODE:
4986 case XML_DOCUMENT_FRAG_NODE:
4987 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004988#ifdef LIBXML_DOCB_ENABLED
4989 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004990#endif
4991 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004992 case XML_NAMESPACE_DECL: {
4993 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
4994
4995 if ((ns->next != NULL) &&
4996 (ns->next->type != XML_NAMESPACE_DECL))
4997 return((xmlNodePtr) ns->next);
4998 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00004999 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005000 }
Owen Taylor3473f882001-02-23 17:55:21 +00005001 }
5002 return(NULL);
5003 }
5004 if (cur == ctxt->context->doc->children)
5005 return((xmlNodePtr) ctxt->context->doc);
5006 if (cur == (xmlNodePtr) ctxt->context->doc)
5007 return(NULL);
5008 switch (cur->type) {
5009 case XML_ELEMENT_NODE:
5010 case XML_TEXT_NODE:
5011 case XML_CDATA_SECTION_NODE:
5012 case XML_ENTITY_REF_NODE:
5013 case XML_ENTITY_NODE:
5014 case XML_PI_NODE:
5015 case XML_COMMENT_NODE:
5016 case XML_NOTATION_NODE:
5017 case XML_DTD_NODE:
5018 case XML_ELEMENT_DECL:
5019 case XML_ATTRIBUTE_DECL:
5020 case XML_ENTITY_DECL:
5021 case XML_XINCLUDE_START:
5022 case XML_XINCLUDE_END:
5023 return(cur->parent);
5024 case XML_ATTRIBUTE_NODE: {
5025 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5026
5027 return(att->parent);
5028 }
5029 case XML_DOCUMENT_NODE:
5030 case XML_DOCUMENT_TYPE_NODE:
5031 case XML_DOCUMENT_FRAG_NODE:
5032 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005033#ifdef LIBXML_DOCB_ENABLED
5034 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005035#endif
5036 return(NULL);
5037 case XML_NAMESPACE_DECL:
5038 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005039 * this should not hapen a namespace can't be
5040 * the ancestor of another node
Owen Taylor3473f882001-02-23 17:55:21 +00005041 */
5042 return(NULL);
5043 }
5044 return(NULL);
5045}
5046
5047/**
5048 * xmlXPathNextAncestorOrSelf:
5049 * @ctxt: the XPath Parser context
5050 * @cur: the current node in the traversal
5051 *
5052 * Traversal function for the "ancestor-or-self" direction
5053 * he ancestor-or-self axis contains the context node and ancestors of
5054 * the context node in reverse document order; thus the context node is
5055 * the first node on the axis, and the context node's parent the second;
5056 * parent here is defined the same as with the parent axis.
5057 *
5058 * Returns the next element following that axis
5059 */
5060xmlNodePtr
5061xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5062 if (cur == NULL)
5063 return(ctxt->context->node);
5064 return(xmlXPathNextAncestor(ctxt, cur));
5065}
5066
5067/**
5068 * xmlXPathNextFollowingSibling:
5069 * @ctxt: the XPath Parser context
5070 * @cur: the current node in the traversal
5071 *
5072 * Traversal function for the "following-sibling" direction
5073 * The following-sibling axis contains the following siblings of the context
5074 * node in document order.
5075 *
5076 * Returns the next element following that axis
5077 */
5078xmlNodePtr
5079xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5080 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5081 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5082 return(NULL);
5083 if (cur == (xmlNodePtr) ctxt->context->doc)
5084 return(NULL);
5085 if (cur == NULL)
5086 return(ctxt->context->node->next);
5087 return(cur->next);
5088}
5089
5090/**
5091 * xmlXPathNextPrecedingSibling:
5092 * @ctxt: the XPath Parser context
5093 * @cur: the current node in the traversal
5094 *
5095 * Traversal function for the "preceding-sibling" direction
5096 * The preceding-sibling axis contains the preceding siblings of the context
5097 * node in reverse document order; the first preceding sibling is first on the
5098 * axis; the sibling preceding that node is the second on the axis and so on.
5099 *
5100 * Returns the next element following that axis
5101 */
5102xmlNodePtr
5103xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5104 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5105 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5106 return(NULL);
5107 if (cur == (xmlNodePtr) ctxt->context->doc)
5108 return(NULL);
5109 if (cur == NULL)
5110 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005111 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5112 cur = cur->prev;
5113 if (cur == NULL)
5114 return(ctxt->context->node->prev);
5115 }
Owen Taylor3473f882001-02-23 17:55:21 +00005116 return(cur->prev);
5117}
5118
5119/**
5120 * xmlXPathNextFollowing:
5121 * @ctxt: the XPath Parser context
5122 * @cur: the current node in the traversal
5123 *
5124 * Traversal function for the "following" direction
5125 * The following axis contains all nodes in the same document as the context
5126 * node that are after the context node in document order, excluding any
5127 * descendants and excluding attribute nodes and namespace nodes; the nodes
5128 * are ordered in document order
5129 *
5130 * Returns the next element following that axis
5131 */
5132xmlNodePtr
5133xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5134 if (cur != NULL && cur->children != NULL)
5135 return cur->children ;
5136 if (cur == NULL) cur = ctxt->context->node;
5137 if (cur == NULL) return(NULL) ; /* ERROR */
5138 if (cur->next != NULL) return(cur->next) ;
5139 do {
5140 cur = cur->parent;
5141 if (cur == NULL) return(NULL);
5142 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5143 if (cur->next != NULL) return(cur->next);
5144 } while (cur != NULL);
5145 return(cur);
5146}
5147
5148/*
5149 * xmlXPathIsAncestor:
5150 * @ancestor: the ancestor node
5151 * @node: the current node
5152 *
5153 * Check that @ancestor is a @node's ancestor
5154 *
5155 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5156 */
5157static int
5158xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5159 if ((ancestor == NULL) || (node == NULL)) return(0);
5160 /* nodes need to be in the same document */
5161 if (ancestor->doc != node->doc) return(0);
5162 /* avoid searching if ancestor or node is the root node */
5163 if (ancestor == (xmlNodePtr) node->doc) return(1);
5164 if (node == (xmlNodePtr) ancestor->doc) return(0);
5165 while (node->parent != NULL) {
5166 if (node->parent == ancestor)
5167 return(1);
5168 node = node->parent;
5169 }
5170 return(0);
5171}
5172
5173/**
5174 * xmlXPathNextPreceding:
5175 * @ctxt: the XPath Parser context
5176 * @cur: the current node in the traversal
5177 *
5178 * Traversal function for the "preceding" direction
5179 * the preceding axis contains all nodes in the same document as the context
5180 * node that are before the context node in document order, excluding any
5181 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5182 * ordered in reverse document order
5183 *
5184 * Returns the next element following that axis
5185 */
5186xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005187xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5188{
Owen Taylor3473f882001-02-23 17:55:21 +00005189 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005190 cur = ctxt->context->node;
5191 if (cur == NULL)
5192 return (NULL);
5193 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5194 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005195 do {
5196 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005197 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5198 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005199 }
5200
5201 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005202 if (cur == NULL)
5203 return (NULL);
5204 if (cur == ctxt->context->doc->children)
5205 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005206 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005207 return (cur);
5208}
5209
5210/**
5211 * xmlXPathNextPrecedingInternal:
5212 * @ctxt: the XPath Parser context
5213 * @cur: the current node in the traversal
5214 *
5215 * Traversal function for the "preceding" direction
5216 * the preceding axis contains all nodes in the same document as the context
5217 * node that are before the context node in document order, excluding any
5218 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5219 * ordered in reverse document order
5220 * This is a faster implementation but internal only since it requires a
5221 * state kept in the parser context: ctxt->ancestor.
5222 *
5223 * Returns the next element following that axis
5224 */
5225static xmlNodePtr
5226xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5227 xmlNodePtr cur)
5228{
5229 if (cur == NULL) {
5230 cur = ctxt->context->node;
5231 if (cur == NULL)
5232 return (NULL);
5233 ctxt->ancestor = cur->parent;
5234 }
5235 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5236 cur = cur->prev;
5237 while (cur->prev == NULL) {
5238 cur = cur->parent;
5239 if (cur == NULL)
5240 return (NULL);
5241 if (cur == ctxt->context->doc->children)
5242 return (NULL);
5243 if (cur != ctxt->ancestor)
5244 return (cur);
5245 ctxt->ancestor = cur->parent;
5246 }
5247 cur = cur->prev;
5248 while (cur->last != NULL)
5249 cur = cur->last;
5250 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005251}
5252
5253/**
5254 * xmlXPathNextNamespace:
5255 * @ctxt: the XPath Parser context
5256 * @cur: the current attribute in the traversal
5257 *
5258 * Traversal function for the "namespace" direction
5259 * the namespace axis contains the namespace nodes of the context node;
5260 * the order of nodes on this axis is implementation-defined; the axis will
5261 * be empty unless the context node is an element
5262 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005263 * We keep the XML namespace node at the end of the list.
5264 *
Owen Taylor3473f882001-02-23 17:55:21 +00005265 * Returns the next element following that axis
5266 */
5267xmlNodePtr
5268xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005269 xmlNodePtr ret;
5270
Owen Taylor3473f882001-02-23 17:55:21 +00005271 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005272 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5273 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005274 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5275 if (ctxt->context->tmpNsList != NULL)
5276 xmlFree(ctxt->context->tmpNsList);
5277 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005278 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005279 if (ctxt->context->tmpNsList == NULL) return(NULL);
5280 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005281 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005282 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5283 if (ret == NULL) {
5284 xmlFree(ctxt->context->tmpNsList);
5285 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005286 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005287 }
5288 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005289}
5290
5291/**
5292 * xmlXPathNextAttribute:
5293 * @ctxt: the XPath Parser context
5294 * @cur: the current attribute in the traversal
5295 *
5296 * Traversal function for the "attribute" direction
5297 * TODO: support DTD inherited default attributes
5298 *
5299 * Returns the next element following that axis
5300 */
5301xmlNodePtr
5302xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005303 if (ctxt->context->node == NULL)
5304 return(NULL);
5305 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5306 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005307 if (cur == NULL) {
5308 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5309 return(NULL);
5310 return((xmlNodePtr)ctxt->context->node->properties);
5311 }
5312 return((xmlNodePtr)cur->next);
5313}
5314
5315/************************************************************************
5316 * *
5317 * NodeTest Functions *
5318 * *
5319 ************************************************************************/
5320
Owen Taylor3473f882001-02-23 17:55:21 +00005321#define IS_FUNCTION 200
5322
Owen Taylor3473f882001-02-23 17:55:21 +00005323
5324/************************************************************************
5325 * *
5326 * Implicit tree core function library *
5327 * *
5328 ************************************************************************/
5329
5330/**
5331 * xmlXPathRoot:
5332 * @ctxt: the XPath Parser context
5333 *
5334 * Initialize the context to the root of the document
5335 */
5336void
5337xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5338 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5339 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5340}
5341
5342/************************************************************************
5343 * *
5344 * The explicit core function library *
5345 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5346 * *
5347 ************************************************************************/
5348
5349
5350/**
5351 * xmlXPathLastFunction:
5352 * @ctxt: the XPath Parser context
5353 * @nargs: the number of arguments
5354 *
5355 * Implement the last() XPath function
5356 * number last()
5357 * The last function returns the number of nodes in the context node list.
5358 */
5359void
5360xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5361 CHECK_ARITY(0);
5362 if (ctxt->context->contextSize >= 0) {
5363 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5364#ifdef DEBUG_EXPR
5365 xmlGenericError(xmlGenericErrorContext,
5366 "last() : %d\n", ctxt->context->contextSize);
5367#endif
5368 } else {
5369 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5370 }
5371}
5372
5373/**
5374 * xmlXPathPositionFunction:
5375 * @ctxt: the XPath Parser context
5376 * @nargs: the number of arguments
5377 *
5378 * Implement the position() XPath function
5379 * number position()
5380 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005381 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005382 * will be equal to last().
5383 */
5384void
5385xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5386 CHECK_ARITY(0);
5387 if (ctxt->context->proximityPosition >= 0) {
5388 valuePush(ctxt,
5389 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5390#ifdef DEBUG_EXPR
5391 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5392 ctxt->context->proximityPosition);
5393#endif
5394 } else {
5395 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5396 }
5397}
5398
5399/**
5400 * xmlXPathCountFunction:
5401 * @ctxt: the XPath Parser context
5402 * @nargs: the number of arguments
5403 *
5404 * Implement the count() XPath function
5405 * number count(node-set)
5406 */
5407void
5408xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5409 xmlXPathObjectPtr cur;
5410
5411 CHECK_ARITY(1);
5412 if ((ctxt->value == NULL) ||
5413 ((ctxt->value->type != XPATH_NODESET) &&
5414 (ctxt->value->type != XPATH_XSLT_TREE)))
5415 XP_ERROR(XPATH_INVALID_TYPE);
5416 cur = valuePop(ctxt);
5417
Daniel Veillard911f49a2001-04-07 15:39:35 +00005418 if ((cur == NULL) || (cur->nodesetval == NULL))
5419 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005420 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005421 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005422 } else {
5423 if ((cur->nodesetval->nodeNr != 1) ||
5424 (cur->nodesetval->nodeTab == NULL)) {
5425 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5426 } else {
5427 xmlNodePtr tmp;
5428 int i = 0;
5429
5430 tmp = cur->nodesetval->nodeTab[0];
5431 if (tmp != NULL) {
5432 tmp = tmp->children;
5433 while (tmp != NULL) {
5434 tmp = tmp->next;
5435 i++;
5436 }
5437 }
5438 valuePush(ctxt, xmlXPathNewFloat((double) i));
5439 }
5440 }
Owen Taylor3473f882001-02-23 17:55:21 +00005441 xmlXPathFreeObject(cur);
5442}
5443
5444/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005445 * xmlXPathGetElementsByIds:
5446 * @doc: the document
5447 * @ids: a whitespace separated list of IDs
5448 *
5449 * Selects elements by their unique ID.
5450 *
5451 * Returns a node-set of selected elements.
5452 */
5453static xmlNodeSetPtr
5454xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5455 xmlNodeSetPtr ret;
5456 const xmlChar *cur = ids;
5457 xmlChar *ID;
5458 xmlAttrPtr attr;
5459 xmlNodePtr elem = NULL;
5460
5461 ret = xmlXPathNodeSetCreate(NULL);
5462
5463 while (IS_BLANK(*cur)) cur++;
5464 while (*cur != 0) {
5465 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5466 (*cur == '.') || (*cur == '-') ||
5467 (*cur == '_') || (*cur == ':') ||
5468 (IS_COMBINING(*cur)) ||
5469 (IS_EXTENDER(*cur)))
5470 cur++;
5471
5472 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5473
5474 ID = xmlStrndup(ids, cur - ids);
5475 attr = xmlGetID(doc, ID);
5476 if (attr != NULL) {
5477 elem = attr->parent;
5478 xmlXPathNodeSetAdd(ret, elem);
5479 }
5480 if (ID != NULL)
5481 xmlFree(ID);
5482
5483 while (IS_BLANK(*cur)) cur++;
5484 ids = cur;
5485 }
5486 return(ret);
5487}
5488
5489/**
Owen Taylor3473f882001-02-23 17:55:21 +00005490 * xmlXPathIdFunction:
5491 * @ctxt: the XPath Parser context
5492 * @nargs: the number of arguments
5493 *
5494 * Implement the id() XPath function
5495 * node-set id(object)
5496 * The id function selects elements by their unique ID
5497 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5498 * then the result is the union of the result of applying id to the
5499 * string value of each of the nodes in the argument node-set. When the
5500 * argument to id is of any other type, the argument is converted to a
5501 * string as if by a call to the string function; the string is split
5502 * into a whitespace-separated list of tokens (whitespace is any sequence
5503 * of characters matching the production S); the result is a node-set
5504 * containing the elements in the same document as the context node that
5505 * have a unique ID equal to any of the tokens in the list.
5506 */
5507void
5508xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005509 xmlChar *tokens;
5510 xmlNodeSetPtr ret;
5511 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005512
5513 CHECK_ARITY(1);
5514 obj = valuePop(ctxt);
5515 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5516 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005517 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005518 int i;
5519
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005520 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005521
Daniel Veillard911f49a2001-04-07 15:39:35 +00005522 if (obj->nodesetval != NULL) {
5523 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005524 tokens =
5525 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5526 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5527 ret = xmlXPathNodeSetMerge(ret, ns);
5528 xmlXPathFreeNodeSet(ns);
5529 if (tokens != NULL)
5530 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005531 }
Owen Taylor3473f882001-02-23 17:55:21 +00005532 }
5533
5534 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005535 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005536 return;
5537 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005538 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005539
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005540 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5541 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005542
Owen Taylor3473f882001-02-23 17:55:21 +00005543 xmlXPathFreeObject(obj);
5544 return;
5545}
5546
5547/**
5548 * xmlXPathLocalNameFunction:
5549 * @ctxt: the XPath Parser context
5550 * @nargs: the number of arguments
5551 *
5552 * Implement the local-name() XPath function
5553 * string local-name(node-set?)
5554 * The local-name function returns a string containing the local part
5555 * of the name of the node in the argument node-set that is first in
5556 * document order. If the node-set is empty or the first node has no
5557 * name, an empty string is returned. If the argument is omitted it
5558 * defaults to the context node.
5559 */
5560void
5561xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5562 xmlXPathObjectPtr cur;
5563
5564 if (nargs == 0) {
5565 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5566 nargs = 1;
5567 }
5568
5569 CHECK_ARITY(1);
5570 if ((ctxt->value == NULL) ||
5571 ((ctxt->value->type != XPATH_NODESET) &&
5572 (ctxt->value->type != XPATH_XSLT_TREE)))
5573 XP_ERROR(XPATH_INVALID_TYPE);
5574 cur = valuePop(ctxt);
5575
Daniel Veillard911f49a2001-04-07 15:39:35 +00005576 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005577 valuePush(ctxt, xmlXPathNewCString(""));
5578 } else {
5579 int i = 0; /* Should be first in document order !!!!! */
5580 switch (cur->nodesetval->nodeTab[i]->type) {
5581 case XML_ELEMENT_NODE:
5582 case XML_ATTRIBUTE_NODE:
5583 case XML_PI_NODE:
5584 valuePush(ctxt,
5585 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5586 break;
5587 case XML_NAMESPACE_DECL:
5588 valuePush(ctxt, xmlXPathNewString(
5589 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5590 break;
5591 default:
5592 valuePush(ctxt, xmlXPathNewCString(""));
5593 }
5594 }
5595 xmlXPathFreeObject(cur);
5596}
5597
5598/**
5599 * xmlXPathNamespaceURIFunction:
5600 * @ctxt: the XPath Parser context
5601 * @nargs: the number of arguments
5602 *
5603 * Implement the namespace-uri() XPath function
5604 * string namespace-uri(node-set?)
5605 * The namespace-uri function returns a string containing the
5606 * namespace URI of the expanded name of the node in the argument
5607 * node-set that is first in document order. If the node-set is empty,
5608 * the first node has no name, or the expanded name has no namespace
5609 * URI, an empty string is returned. If the argument is omitted it
5610 * defaults to the context node.
5611 */
5612void
5613xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5614 xmlXPathObjectPtr cur;
5615
5616 if (nargs == 0) {
5617 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5618 nargs = 1;
5619 }
5620 CHECK_ARITY(1);
5621 if ((ctxt->value == NULL) ||
5622 ((ctxt->value->type != XPATH_NODESET) &&
5623 (ctxt->value->type != XPATH_XSLT_TREE)))
5624 XP_ERROR(XPATH_INVALID_TYPE);
5625 cur = valuePop(ctxt);
5626
Daniel Veillard911f49a2001-04-07 15:39:35 +00005627 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005628 valuePush(ctxt, xmlXPathNewCString(""));
5629 } else {
5630 int i = 0; /* Should be first in document order !!!!! */
5631 switch (cur->nodesetval->nodeTab[i]->type) {
5632 case XML_ELEMENT_NODE:
5633 case XML_ATTRIBUTE_NODE:
5634 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5635 valuePush(ctxt, xmlXPathNewCString(""));
5636 else
5637 valuePush(ctxt, xmlXPathNewString(
5638 cur->nodesetval->nodeTab[i]->ns->href));
5639 break;
5640 default:
5641 valuePush(ctxt, xmlXPathNewCString(""));
5642 }
5643 }
5644 xmlXPathFreeObject(cur);
5645}
5646
5647/**
5648 * xmlXPathNameFunction:
5649 * @ctxt: the XPath Parser context
5650 * @nargs: the number of arguments
5651 *
5652 * Implement the name() XPath function
5653 * string name(node-set?)
5654 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005655 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005656 * order. The QName must represent the name with respect to the namespace
5657 * declarations in effect on the node whose name is being represented.
5658 * Typically, this will be the form in which the name occurred in the XML
5659 * source. This need not be the case if there are namespace declarations
5660 * in effect on the node that associate multiple prefixes with the same
5661 * namespace. However, an implementation may include information about
5662 * the original prefix in its representation of nodes; in this case, an
5663 * implementation can ensure that the returned string is always the same
5664 * as the QName used in the XML source. If the argument it omitted it
5665 * defaults to the context node.
5666 * Libxml keep the original prefix so the "real qualified name" used is
5667 * returned.
5668 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005669static void
Daniel Veillard04383752001-07-08 14:27:15 +00005670xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5671{
Owen Taylor3473f882001-02-23 17:55:21 +00005672 xmlXPathObjectPtr cur;
5673
5674 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005675 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5676 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005677 }
5678
5679 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005680 if ((ctxt->value == NULL) ||
5681 ((ctxt->value->type != XPATH_NODESET) &&
5682 (ctxt->value->type != XPATH_XSLT_TREE)))
5683 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005684 cur = valuePop(ctxt);
5685
Daniel Veillard911f49a2001-04-07 15:39:35 +00005686 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005687 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005688 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005689 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005690
Daniel Veillard04383752001-07-08 14:27:15 +00005691 switch (cur->nodesetval->nodeTab[i]->type) {
5692 case XML_ELEMENT_NODE:
5693 case XML_ATTRIBUTE_NODE:
5694 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5695 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5696 valuePush(ctxt,
5697 xmlXPathNewString(cur->nodesetval->
5698 nodeTab[i]->name));
5699
5700 else {
5701 char name[2000];
5702
5703 snprintf(name, sizeof(name), "%s:%s",
5704 (char *) cur->nodesetval->nodeTab[i]->ns->
5705 prefix,
5706 (char *) cur->nodesetval->nodeTab[i]->name);
5707 name[sizeof(name) - 1] = 0;
5708 valuePush(ctxt, xmlXPathNewCString(name));
5709 }
5710 break;
5711 default:
5712 valuePush(ctxt,
5713 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5714 xmlXPathLocalNameFunction(ctxt, 1);
5715 }
Owen Taylor3473f882001-02-23 17:55:21 +00005716 }
5717 xmlXPathFreeObject(cur);
5718}
5719
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005720
5721/**
Owen Taylor3473f882001-02-23 17:55:21 +00005722 * xmlXPathStringFunction:
5723 * @ctxt: the XPath Parser context
5724 * @nargs: the number of arguments
5725 *
5726 * Implement the string() XPath function
5727 * string string(object?)
5728 * he string function converts an object to a string as follows:
5729 * - A node-set is converted to a string by returning the value of
5730 * the node in the node-set that is first in document order.
5731 * If the node-set is empty, an empty string is returned.
5732 * - A number is converted to a string as follows
5733 * + NaN is converted to the string NaN
5734 * + positive zero is converted to the string 0
5735 * + negative zero is converted to the string 0
5736 * + positive infinity is converted to the string Infinity
5737 * + negative infinity is converted to the string -Infinity
5738 * + if the number is an integer, the number is represented in
5739 * decimal form as a Number with no decimal point and no leading
5740 * zeros, preceded by a minus sign (-) if the number is negative
5741 * + otherwise, the number is represented in decimal form as a
5742 * Number including a decimal point with at least one digit
5743 * before the decimal point and at least one digit after the
5744 * decimal point, preceded by a minus sign (-) if the number
5745 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005746 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005747 * before the decimal point; beyond the one required digit
5748 * after the decimal point there must be as many, but only as
5749 * many, more digits as are needed to uniquely distinguish the
5750 * number from all other IEEE 754 numeric values.
5751 * - The boolean false value is converted to the string false.
5752 * The boolean true value is converted to the string true.
5753 *
5754 * If the argument is omitted, it defaults to a node-set with the
5755 * context node as its only member.
5756 */
5757void
5758xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5759 xmlXPathObjectPtr cur;
5760
5761 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005762 valuePush(ctxt,
5763 xmlXPathWrapString(
5764 xmlXPathCastNodeToString(ctxt->context->node)));
5765 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005766 }
5767
5768 CHECK_ARITY(1);
5769 cur = valuePop(ctxt);
5770 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005771 cur = xmlXPathConvertString(cur);
5772 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005773}
5774
5775/**
5776 * xmlXPathStringLengthFunction:
5777 * @ctxt: the XPath Parser context
5778 * @nargs: the number of arguments
5779 *
5780 * Implement the string-length() XPath function
5781 * number string-length(string?)
5782 * The string-length returns the number of characters in the string
5783 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5784 * the context node converted to a string, in other words the value
5785 * of the context node.
5786 */
5787void
5788xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5789 xmlXPathObjectPtr cur;
5790
5791 if (nargs == 0) {
5792 if (ctxt->context->node == NULL) {
5793 valuePush(ctxt, xmlXPathNewFloat(0));
5794 } else {
5795 xmlChar *content;
5796
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005797 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005798 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005799 xmlFree(content);
5800 }
5801 return;
5802 }
5803 CHECK_ARITY(1);
5804 CAST_TO_STRING;
5805 CHECK_TYPE(XPATH_STRING);
5806 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005807 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005808 xmlXPathFreeObject(cur);
5809}
5810
5811/**
5812 * xmlXPathConcatFunction:
5813 * @ctxt: the XPath Parser context
5814 * @nargs: the number of arguments
5815 *
5816 * Implement the concat() XPath function
5817 * string concat(string, string, string*)
5818 * The concat function returns the concatenation of its arguments.
5819 */
5820void
5821xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5822 xmlXPathObjectPtr cur, newobj;
5823 xmlChar *tmp;
5824
5825 if (nargs < 2) {
5826 CHECK_ARITY(2);
5827 }
5828
5829 CAST_TO_STRING;
5830 cur = valuePop(ctxt);
5831 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5832 xmlXPathFreeObject(cur);
5833 return;
5834 }
5835 nargs--;
5836
5837 while (nargs > 0) {
5838 CAST_TO_STRING;
5839 newobj = valuePop(ctxt);
5840 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5841 xmlXPathFreeObject(newobj);
5842 xmlXPathFreeObject(cur);
5843 XP_ERROR(XPATH_INVALID_TYPE);
5844 }
5845 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5846 newobj->stringval = cur->stringval;
5847 cur->stringval = tmp;
5848
5849 xmlXPathFreeObject(newobj);
5850 nargs--;
5851 }
5852 valuePush(ctxt, cur);
5853}
5854
5855/**
5856 * xmlXPathContainsFunction:
5857 * @ctxt: the XPath Parser context
5858 * @nargs: the number of arguments
5859 *
5860 * Implement the contains() XPath function
5861 * boolean contains(string, string)
5862 * The contains function returns true if the first argument string
5863 * contains the second argument string, and otherwise returns false.
5864 */
5865void
5866xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5867 xmlXPathObjectPtr hay, needle;
5868
5869 CHECK_ARITY(2);
5870 CAST_TO_STRING;
5871 CHECK_TYPE(XPATH_STRING);
5872 needle = valuePop(ctxt);
5873 CAST_TO_STRING;
5874 hay = valuePop(ctxt);
5875 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5876 xmlXPathFreeObject(hay);
5877 xmlXPathFreeObject(needle);
5878 XP_ERROR(XPATH_INVALID_TYPE);
5879 }
5880 if (xmlStrstr(hay->stringval, needle->stringval))
5881 valuePush(ctxt, xmlXPathNewBoolean(1));
5882 else
5883 valuePush(ctxt, xmlXPathNewBoolean(0));
5884 xmlXPathFreeObject(hay);
5885 xmlXPathFreeObject(needle);
5886}
5887
5888/**
5889 * xmlXPathStartsWithFunction:
5890 * @ctxt: the XPath Parser context
5891 * @nargs: the number of arguments
5892 *
5893 * Implement the starts-with() XPath function
5894 * boolean starts-with(string, string)
5895 * The starts-with function returns true if the first argument string
5896 * starts with the second argument string, and otherwise returns false.
5897 */
5898void
5899xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5900 xmlXPathObjectPtr hay, needle;
5901 int n;
5902
5903 CHECK_ARITY(2);
5904 CAST_TO_STRING;
5905 CHECK_TYPE(XPATH_STRING);
5906 needle = valuePop(ctxt);
5907 CAST_TO_STRING;
5908 hay = valuePop(ctxt);
5909 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5910 xmlXPathFreeObject(hay);
5911 xmlXPathFreeObject(needle);
5912 XP_ERROR(XPATH_INVALID_TYPE);
5913 }
5914 n = xmlStrlen(needle->stringval);
5915 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5916 valuePush(ctxt, xmlXPathNewBoolean(0));
5917 else
5918 valuePush(ctxt, xmlXPathNewBoolean(1));
5919 xmlXPathFreeObject(hay);
5920 xmlXPathFreeObject(needle);
5921}
5922
5923/**
5924 * xmlXPathSubstringFunction:
5925 * @ctxt: the XPath Parser context
5926 * @nargs: the number of arguments
5927 *
5928 * Implement the substring() XPath function
5929 * string substring(string, number, number?)
5930 * The substring function returns the substring of the first argument
5931 * starting at the position specified in the second argument with
5932 * length specified in the third argument. For example,
5933 * substring("12345",2,3) returns "234". If the third argument is not
5934 * specified, it returns the substring starting at the position specified
5935 * in the second argument and continuing to the end of the string. For
5936 * example, substring("12345",2) returns "2345". More precisely, each
5937 * character in the string (see [3.6 Strings]) is considered to have a
5938 * numeric position: the position of the first character is 1, the position
5939 * of the second character is 2 and so on. The returned substring contains
5940 * those characters for which the position of the character is greater than
5941 * or equal to the second argument and, if the third argument is specified,
5942 * less than the sum of the second and third arguments; the comparisons
5943 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5944 * - substring("12345", 1.5, 2.6) returns "234"
5945 * - substring("12345", 0, 3) returns "12"
5946 * - substring("12345", 0 div 0, 3) returns ""
5947 * - substring("12345", 1, 0 div 0) returns ""
5948 * - substring("12345", -42, 1 div 0) returns "12345"
5949 * - substring("12345", -1 div 0, 1 div 0) returns ""
5950 */
5951void
5952xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5953 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005954 double le=0, in;
5955 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005956 xmlChar *ret;
5957
Owen Taylor3473f882001-02-23 17:55:21 +00005958 if (nargs < 2) {
5959 CHECK_ARITY(2);
5960 }
5961 if (nargs > 3) {
5962 CHECK_ARITY(3);
5963 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005964 /*
5965 * take care of possible last (position) argument
5966 */
Owen Taylor3473f882001-02-23 17:55:21 +00005967 if (nargs == 3) {
5968 CAST_TO_NUMBER;
5969 CHECK_TYPE(XPATH_NUMBER);
5970 len = valuePop(ctxt);
5971 le = len->floatval;
5972 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005973 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005974
Owen Taylor3473f882001-02-23 17:55:21 +00005975 CAST_TO_NUMBER;
5976 CHECK_TYPE(XPATH_NUMBER);
5977 start = valuePop(ctxt);
5978 in = start->floatval;
5979 xmlXPathFreeObject(start);
5980 CAST_TO_STRING;
5981 CHECK_TYPE(XPATH_STRING);
5982 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005983 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005984
Daniel Veillard97ac1312001-05-30 19:14:17 +00005985 /*
5986 * If last pos not present, calculate last position
5987 */
5988 if (nargs != 3)
5989 le = m;
5990
5991 /*
5992 * To meet our requirements, initial index calculations
5993 * must be done before we convert to integer format
5994 *
5995 * First we normalize indices
5996 */
5997 in -= 1.0;
5998 le += in;
5999 if (in < 0.0)
6000 in = 0.0;
6001 if (le > (double)m)
6002 le = (double)m;
6003
6004 /*
6005 * Now we go to integer form, rounding up
6006 */
Owen Taylor3473f882001-02-23 17:55:21 +00006007 i = (int) in;
6008 if (((double)i) != in) i++;
6009
Owen Taylor3473f882001-02-23 17:55:21 +00006010 l = (int) le;
6011 if (((double)l) != le) l++;
6012
Daniel Veillard97ac1312001-05-30 19:14:17 +00006013 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00006014
6015 /* number of chars to copy */
6016 l -= i;
6017
Daniel Veillard97ac1312001-05-30 19:14:17 +00006018 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00006019 if (ret == NULL)
6020 valuePush(ctxt, xmlXPathNewCString(""));
6021 else {
6022 valuePush(ctxt, xmlXPathNewString(ret));
6023 xmlFree(ret);
6024 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006025
Owen Taylor3473f882001-02-23 17:55:21 +00006026 xmlXPathFreeObject(str);
6027}
6028
6029/**
6030 * xmlXPathSubstringBeforeFunction:
6031 * @ctxt: the XPath Parser context
6032 * @nargs: the number of arguments
6033 *
6034 * Implement the substring-before() XPath function
6035 * string substring-before(string, string)
6036 * The substring-before function returns the substring of the first
6037 * argument string that precedes the first occurrence of the second
6038 * argument string in the first argument string, or the empty string
6039 * if the first argument string does not contain the second argument
6040 * string. For example, substring-before("1999/04/01","/") returns 1999.
6041 */
6042void
6043xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6044 xmlXPathObjectPtr str;
6045 xmlXPathObjectPtr find;
6046 xmlBufferPtr target;
6047 const xmlChar *point;
6048 int offset;
6049
6050 CHECK_ARITY(2);
6051 CAST_TO_STRING;
6052 find = valuePop(ctxt);
6053 CAST_TO_STRING;
6054 str = valuePop(ctxt);
6055
6056 target = xmlBufferCreate();
6057 if (target) {
6058 point = xmlStrstr(str->stringval, find->stringval);
6059 if (point) {
6060 offset = (int)(point - str->stringval);
6061 xmlBufferAdd(target, str->stringval, offset);
6062 }
6063 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6064 xmlBufferFree(target);
6065 }
6066
6067 xmlXPathFreeObject(str);
6068 xmlXPathFreeObject(find);
6069}
6070
6071/**
6072 * xmlXPathSubstringAfterFunction:
6073 * @ctxt: the XPath Parser context
6074 * @nargs: the number of arguments
6075 *
6076 * Implement the substring-after() XPath function
6077 * string substring-after(string, string)
6078 * The substring-after function returns the substring of the first
6079 * argument string that follows the first occurrence of the second
6080 * argument string in the first argument string, or the empty stringi
6081 * if the first argument string does not contain the second argument
6082 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6083 * and substring-after("1999/04/01","19") returns 99/04/01.
6084 */
6085void
6086xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6087 xmlXPathObjectPtr str;
6088 xmlXPathObjectPtr find;
6089 xmlBufferPtr target;
6090 const xmlChar *point;
6091 int offset;
6092
6093 CHECK_ARITY(2);
6094 CAST_TO_STRING;
6095 find = valuePop(ctxt);
6096 CAST_TO_STRING;
6097 str = valuePop(ctxt);
6098
6099 target = xmlBufferCreate();
6100 if (target) {
6101 point = xmlStrstr(str->stringval, find->stringval);
6102 if (point) {
6103 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6104 xmlBufferAdd(target, &str->stringval[offset],
6105 xmlStrlen(str->stringval) - offset);
6106 }
6107 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6108 xmlBufferFree(target);
6109 }
6110
6111 xmlXPathFreeObject(str);
6112 xmlXPathFreeObject(find);
6113}
6114
6115/**
6116 * xmlXPathNormalizeFunction:
6117 * @ctxt: the XPath Parser context
6118 * @nargs: the number of arguments
6119 *
6120 * Implement the normalize-space() XPath function
6121 * string normalize-space(string?)
6122 * The normalize-space function returns the argument string with white
6123 * space normalized by stripping leading and trailing whitespace
6124 * and replacing sequences of whitespace characters by a single
6125 * space. Whitespace characters are the same allowed by the S production
6126 * in XML. If the argument is omitted, it defaults to the context
6127 * node converted to a string, in other words the value of the context node.
6128 */
6129void
6130xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6131 xmlXPathObjectPtr obj = NULL;
6132 xmlChar *source = NULL;
6133 xmlBufferPtr target;
6134 xmlChar blank;
6135
6136 if (nargs == 0) {
6137 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006138 valuePush(ctxt,
6139 xmlXPathWrapString(
6140 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006141 nargs = 1;
6142 }
6143
6144 CHECK_ARITY(1);
6145 CAST_TO_STRING;
6146 CHECK_TYPE(XPATH_STRING);
6147 obj = valuePop(ctxt);
6148 source = obj->stringval;
6149
6150 target = xmlBufferCreate();
6151 if (target && source) {
6152
6153 /* Skip leading whitespaces */
6154 while (IS_BLANK(*source))
6155 source++;
6156
6157 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6158 blank = 0;
6159 while (*source) {
6160 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006161 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006162 } else {
6163 if (blank) {
6164 xmlBufferAdd(target, &blank, 1);
6165 blank = 0;
6166 }
6167 xmlBufferAdd(target, source, 1);
6168 }
6169 source++;
6170 }
6171
6172 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6173 xmlBufferFree(target);
6174 }
6175 xmlXPathFreeObject(obj);
6176}
6177
6178/**
6179 * xmlXPathTranslateFunction:
6180 * @ctxt: the XPath Parser context
6181 * @nargs: the number of arguments
6182 *
6183 * Implement the translate() XPath function
6184 * string translate(string, string, string)
6185 * The translate function returns the first argument string with
6186 * occurrences of characters in the second argument string replaced
6187 * by the character at the corresponding position in the third argument
6188 * string. For example, translate("bar","abc","ABC") returns the string
6189 * BAr. If there is a character in the second argument string with no
6190 * character at a corresponding position in the third argument string
6191 * (because the second argument string is longer than the third argument
6192 * string), then occurrences of that character in the first argument
6193 * string are removed. For example, translate("--aaa--","abc-","ABC")
6194 * returns "AAA". If a character occurs more than once in second
6195 * argument string, then the first occurrence determines the replacement
6196 * character. If the third argument string is longer than the second
6197 * argument string, then excess characters are ignored.
6198 */
6199void
6200xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006201 xmlXPathObjectPtr str;
6202 xmlXPathObjectPtr from;
6203 xmlXPathObjectPtr to;
6204 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006205 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006206 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006207 xmlChar *point;
6208 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006209
Daniel Veillarde043ee12001-04-16 14:08:07 +00006210 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006211
Daniel Veillarde043ee12001-04-16 14:08:07 +00006212 CAST_TO_STRING;
6213 to = valuePop(ctxt);
6214 CAST_TO_STRING;
6215 from = valuePop(ctxt);
6216 CAST_TO_STRING;
6217 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006218
Daniel Veillarde043ee12001-04-16 14:08:07 +00006219 target = xmlBufferCreate();
6220 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006221 max = xmlUTF8Strlen(to->stringval);
6222 for (cptr = str->stringval; (ch=*cptr); ) {
6223 offset = xmlUTF8Strloc(from->stringval, cptr);
6224 if (offset >= 0) {
6225 if (offset < max) {
6226 point = xmlUTF8Strpos(to->stringval, offset);
6227 if (point)
6228 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6229 }
6230 } else
6231 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6232
6233 /* Step to next character in input */
6234 cptr++;
6235 if ( ch & 0x80 ) {
6236 /* if not simple ascii, verify proper format */
6237 if ( (ch & 0xc0) != 0xc0 ) {
6238 xmlGenericError(xmlGenericErrorContext,
6239 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6240 break;
6241 }
6242 /* then skip over remaining bytes for this char */
6243 while ( (ch <<= 1) & 0x80 )
6244 if ( (*cptr++ & 0xc0) != 0x80 ) {
6245 xmlGenericError(xmlGenericErrorContext,
6246 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6247 break;
6248 }
6249 if (ch & 0x80) /* must have had error encountered */
6250 break;
6251 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006252 }
Owen Taylor3473f882001-02-23 17:55:21 +00006253 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006254 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6255 xmlBufferFree(target);
6256 xmlXPathFreeObject(str);
6257 xmlXPathFreeObject(from);
6258 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006259}
6260
6261/**
6262 * xmlXPathBooleanFunction:
6263 * @ctxt: the XPath Parser context
6264 * @nargs: the number of arguments
6265 *
6266 * Implement the boolean() XPath function
6267 * boolean boolean(object)
6268 * he boolean function converts its argument to a boolean as follows:
6269 * - a number is true if and only if it is neither positive or
6270 * negative zero nor NaN
6271 * - a node-set is true if and only if it is non-empty
6272 * - a string is true if and only if its length is non-zero
6273 */
6274void
6275xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6276 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006277
6278 CHECK_ARITY(1);
6279 cur = valuePop(ctxt);
6280 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006281 cur = xmlXPathConvertBoolean(cur);
6282 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006283}
6284
6285/**
6286 * xmlXPathNotFunction:
6287 * @ctxt: the XPath Parser context
6288 * @nargs: the number of arguments
6289 *
6290 * Implement the not() XPath function
6291 * boolean not(boolean)
6292 * The not function returns true if its argument is false,
6293 * and false otherwise.
6294 */
6295void
6296xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6297 CHECK_ARITY(1);
6298 CAST_TO_BOOLEAN;
6299 CHECK_TYPE(XPATH_BOOLEAN);
6300 ctxt->value->boolval = ! ctxt->value->boolval;
6301}
6302
6303/**
6304 * xmlXPathTrueFunction:
6305 * @ctxt: the XPath Parser context
6306 * @nargs: the number of arguments
6307 *
6308 * Implement the true() XPath function
6309 * boolean true()
6310 */
6311void
6312xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6313 CHECK_ARITY(0);
6314 valuePush(ctxt, xmlXPathNewBoolean(1));
6315}
6316
6317/**
6318 * xmlXPathFalseFunction:
6319 * @ctxt: the XPath Parser context
6320 * @nargs: the number of arguments
6321 *
6322 * Implement the false() XPath function
6323 * boolean false()
6324 */
6325void
6326xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6327 CHECK_ARITY(0);
6328 valuePush(ctxt, xmlXPathNewBoolean(0));
6329}
6330
6331/**
6332 * xmlXPathLangFunction:
6333 * @ctxt: the XPath Parser context
6334 * @nargs: the number of arguments
6335 *
6336 * Implement the lang() XPath function
6337 * boolean lang(string)
6338 * The lang function returns true or false depending on whether the
6339 * language of the context node as specified by xml:lang attributes
6340 * is the same as or is a sublanguage of the language specified by
6341 * the argument string. The language of the context node is determined
6342 * by the value of the xml:lang attribute on the context node, or, if
6343 * the context node has no xml:lang attribute, by the value of the
6344 * xml:lang attribute on the nearest ancestor of the context node that
6345 * has an xml:lang attribute. If there is no such attribute, then lang
6346 * returns false. If there is such an attribute, then lang returns
6347 * true if the attribute value is equal to the argument ignoring case,
6348 * or if there is some suffix starting with - such that the attribute
6349 * value is equal to the argument ignoring that suffix of the attribute
6350 * value and ignoring case.
6351 */
6352void
6353xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6354 xmlXPathObjectPtr val;
6355 const xmlChar *theLang;
6356 const xmlChar *lang;
6357 int ret = 0;
6358 int i;
6359
6360 CHECK_ARITY(1);
6361 CAST_TO_STRING;
6362 CHECK_TYPE(XPATH_STRING);
6363 val = valuePop(ctxt);
6364 lang = val->stringval;
6365 theLang = xmlNodeGetLang(ctxt->context->node);
6366 if ((theLang != NULL) && (lang != NULL)) {
6367 for (i = 0;lang[i] != 0;i++)
6368 if (toupper(lang[i]) != toupper(theLang[i]))
6369 goto not_equal;
6370 ret = 1;
6371 }
6372not_equal:
6373 xmlXPathFreeObject(val);
6374 valuePush(ctxt, xmlXPathNewBoolean(ret));
6375}
6376
6377/**
6378 * xmlXPathNumberFunction:
6379 * @ctxt: the XPath Parser context
6380 * @nargs: the number of arguments
6381 *
6382 * Implement the number() XPath function
6383 * number number(object?)
6384 */
6385void
6386xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6387 xmlXPathObjectPtr cur;
6388 double res;
6389
6390 if (nargs == 0) {
6391 if (ctxt->context->node == NULL) {
6392 valuePush(ctxt, xmlXPathNewFloat(0.0));
6393 } else {
6394 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6395
6396 res = xmlXPathStringEvalNumber(content);
6397 valuePush(ctxt, xmlXPathNewFloat(res));
6398 xmlFree(content);
6399 }
6400 return;
6401 }
6402
6403 CHECK_ARITY(1);
6404 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006405 cur = xmlXPathConvertNumber(cur);
6406 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006407}
6408
6409/**
6410 * xmlXPathSumFunction:
6411 * @ctxt: the XPath Parser context
6412 * @nargs: the number of arguments
6413 *
6414 * Implement the sum() XPath function
6415 * number sum(node-set)
6416 * The sum function returns the sum of the values of the nodes in
6417 * the argument node-set.
6418 */
6419void
6420xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6421 xmlXPathObjectPtr cur;
6422 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006423 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006424
6425 CHECK_ARITY(1);
6426 if ((ctxt->value == NULL) ||
6427 ((ctxt->value->type != XPATH_NODESET) &&
6428 (ctxt->value->type != XPATH_XSLT_TREE)))
6429 XP_ERROR(XPATH_INVALID_TYPE);
6430 cur = valuePop(ctxt);
6431
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006432 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006433 valuePush(ctxt, xmlXPathNewFloat(0.0));
6434 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006435 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6436 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006437 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006438 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006439 }
6440 xmlXPathFreeObject(cur);
6441}
6442
6443/**
6444 * xmlXPathFloorFunction:
6445 * @ctxt: the XPath Parser context
6446 * @nargs: the number of arguments
6447 *
6448 * Implement the floor() XPath function
6449 * number floor(number)
6450 * The floor function returns the largest (closest to positive infinity)
6451 * number that is not greater than the argument and that is an integer.
6452 */
6453void
6454xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6455 CHECK_ARITY(1);
6456 CAST_TO_NUMBER;
6457 CHECK_TYPE(XPATH_NUMBER);
6458#if 0
6459 ctxt->value->floatval = floor(ctxt->value->floatval);
6460#else
6461 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6462 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6463#endif
6464}
6465
6466/**
6467 * xmlXPathCeilingFunction:
6468 * @ctxt: the XPath Parser context
6469 * @nargs: the number of arguments
6470 *
6471 * Implement the ceiling() XPath function
6472 * number ceiling(number)
6473 * The ceiling function returns the smallest (closest to negative infinity)
6474 * number that is not less than the argument and that is an integer.
6475 */
6476void
6477xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6478 double f;
6479
6480 CHECK_ARITY(1);
6481 CAST_TO_NUMBER;
6482 CHECK_TYPE(XPATH_NUMBER);
6483
6484#if 0
6485 ctxt->value->floatval = ceil(ctxt->value->floatval);
6486#else
6487 f = (double)((int) ctxt->value->floatval);
6488 if (f != ctxt->value->floatval)
6489 ctxt->value->floatval = f + 1;
6490#endif
6491}
6492
6493/**
6494 * xmlXPathRoundFunction:
6495 * @ctxt: the XPath Parser context
6496 * @nargs: the number of arguments
6497 *
6498 * Implement the round() XPath function
6499 * number round(number)
6500 * The round function returns the number that is closest to the
6501 * argument and that is an integer. If there are two such numbers,
6502 * then the one that is even is returned.
6503 */
6504void
6505xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6506 double f;
6507
6508 CHECK_ARITY(1);
6509 CAST_TO_NUMBER;
6510 CHECK_TYPE(XPATH_NUMBER);
6511
Daniel Veillardcda96922001-08-21 10:56:31 +00006512 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6513 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6514 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006515 (ctxt->value->floatval == 0.0))
6516 return;
6517
6518#if 0
6519 f = floor(ctxt->value->floatval);
6520#else
6521 f = (double)((int) ctxt->value->floatval);
6522#endif
6523 if (ctxt->value->floatval < f + 0.5)
6524 ctxt->value->floatval = f;
6525 else
6526 ctxt->value->floatval = f + 1;
6527}
6528
6529/************************************************************************
6530 * *
6531 * The Parser *
6532 * *
6533 ************************************************************************/
6534
6535/*
6536 * a couple of forward declarations since we use a recursive call based
6537 * implementation.
6538 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006539static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006540static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006541static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006542#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006543static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6544#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006545#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006546static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006547#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006548static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6549 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006550
6551/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006552 * xmlXPathCurrentChar:
6553 * @ctxt: the XPath parser context
6554 * @cur: pointer to the beginning of the char
6555 * @len: pointer to the length of the char read
6556 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006557 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006558 * bytes in the input buffer.
6559 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006560 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006561 */
6562
6563static int
6564xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6565 unsigned char c;
6566 unsigned int val;
6567 const xmlChar *cur;
6568
6569 if (ctxt == NULL)
6570 return(0);
6571 cur = ctxt->cur;
6572
6573 /*
6574 * We are supposed to handle UTF8, check it's valid
6575 * From rfc2044: encoding of the Unicode values on UTF-8:
6576 *
6577 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6578 * 0000 0000-0000 007F 0xxxxxxx
6579 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6580 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6581 *
6582 * Check for the 0x110000 limit too
6583 */
6584 c = *cur;
6585 if (c & 0x80) {
6586 if ((cur[1] & 0xc0) != 0x80)
6587 goto encoding_error;
6588 if ((c & 0xe0) == 0xe0) {
6589
6590 if ((cur[2] & 0xc0) != 0x80)
6591 goto encoding_error;
6592 if ((c & 0xf0) == 0xf0) {
6593 if (((c & 0xf8) != 0xf0) ||
6594 ((cur[3] & 0xc0) != 0x80))
6595 goto encoding_error;
6596 /* 4-byte code */
6597 *len = 4;
6598 val = (cur[0] & 0x7) << 18;
6599 val |= (cur[1] & 0x3f) << 12;
6600 val |= (cur[2] & 0x3f) << 6;
6601 val |= cur[3] & 0x3f;
6602 } else {
6603 /* 3-byte code */
6604 *len = 3;
6605 val = (cur[0] & 0xf) << 12;
6606 val |= (cur[1] & 0x3f) << 6;
6607 val |= cur[2] & 0x3f;
6608 }
6609 } else {
6610 /* 2-byte code */
6611 *len = 2;
6612 val = (cur[0] & 0x1f) << 6;
6613 val |= cur[1] & 0x3f;
6614 }
6615 if (!IS_CHAR(val)) {
6616 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6617 }
6618 return(val);
6619 } else {
6620 /* 1-byte code */
6621 *len = 1;
6622 return((int) *cur);
6623 }
6624encoding_error:
6625 /*
6626 * If we detect an UTF8 error that probably mean that the
6627 * input encoding didn't get properly advertized in the
6628 * declaration header. Report the error and switch the encoding
6629 * to ISO-Latin-1 (if you don't like this policy, just declare the
6630 * encoding !)
6631 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006632 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006633 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006634}
6635
6636/**
Owen Taylor3473f882001-02-23 17:55:21 +00006637 * xmlXPathParseNCName:
6638 * @ctxt: the XPath Parser context
6639 *
6640 * parse an XML namespace non qualified name.
6641 *
6642 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6643 *
6644 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6645 * CombiningChar | Extender
6646 *
6647 * Returns the namespace name or NULL
6648 */
6649
6650xmlChar *
6651xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006652 const xmlChar *in;
6653 xmlChar *ret;
6654 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006655
Daniel Veillard2156a562001-04-28 12:24:34 +00006656 /*
6657 * Accelerator for simple ASCII names
6658 */
6659 in = ctxt->cur;
6660 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6661 ((*in >= 0x41) && (*in <= 0x5A)) ||
6662 (*in == '_')) {
6663 in++;
6664 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6665 ((*in >= 0x41) && (*in <= 0x5A)) ||
6666 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006667 (*in == '_') || (*in == '.') ||
6668 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006669 in++;
6670 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6671 (*in == '[') || (*in == ']') || (*in == ':') ||
6672 (*in == '@') || (*in == '*')) {
6673 count = in - ctxt->cur;
6674 if (count == 0)
6675 return(NULL);
6676 ret = xmlStrndup(ctxt->cur, count);
6677 ctxt->cur = in;
6678 return(ret);
6679 }
6680 }
6681 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006682}
6683
Daniel Veillard2156a562001-04-28 12:24:34 +00006684
Owen Taylor3473f882001-02-23 17:55:21 +00006685/**
6686 * xmlXPathParseQName:
6687 * @ctxt: the XPath Parser context
6688 * @prefix: a xmlChar **
6689 *
6690 * parse an XML qualified name
6691 *
6692 * [NS 5] QName ::= (Prefix ':')? LocalPart
6693 *
6694 * [NS 6] Prefix ::= NCName
6695 *
6696 * [NS 7] LocalPart ::= NCName
6697 *
6698 * Returns the function returns the local part, and prefix is updated
6699 * to get the Prefix if any.
6700 */
6701
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006702static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006703xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6704 xmlChar *ret = NULL;
6705
6706 *prefix = NULL;
6707 ret = xmlXPathParseNCName(ctxt);
6708 if (CUR == ':') {
6709 *prefix = ret;
6710 NEXT;
6711 ret = xmlXPathParseNCName(ctxt);
6712 }
6713 return(ret);
6714}
6715
6716/**
6717 * xmlXPathParseName:
6718 * @ctxt: the XPath Parser context
6719 *
6720 * parse an XML name
6721 *
6722 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6723 * CombiningChar | Extender
6724 *
6725 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6726 *
6727 * Returns the namespace name or NULL
6728 */
6729
6730xmlChar *
6731xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006732 const xmlChar *in;
6733 xmlChar *ret;
6734 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006735
Daniel Veillard61d80a22001-04-27 17:13:01 +00006736 /*
6737 * Accelerator for simple ASCII names
6738 */
6739 in = ctxt->cur;
6740 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6741 ((*in >= 0x41) && (*in <= 0x5A)) ||
6742 (*in == '_') || (*in == ':')) {
6743 in++;
6744 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6745 ((*in >= 0x41) && (*in <= 0x5A)) ||
6746 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006747 (*in == '_') || (*in == '-') ||
6748 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006749 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006750 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006751 count = in - ctxt->cur;
6752 ret = xmlStrndup(ctxt->cur, count);
6753 ctxt->cur = in;
6754 return(ret);
6755 }
6756 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006757 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006758}
6759
Daniel Veillard61d80a22001-04-27 17:13:01 +00006760static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006761xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006762 xmlChar buf[XML_MAX_NAMELEN + 5];
6763 int len = 0, l;
6764 int c;
6765
6766 /*
6767 * Handler for more complex cases
6768 */
6769 c = CUR_CHAR(l);
6770 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006771 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6772 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006773 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006774 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006775 return(NULL);
6776 }
6777
6778 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6779 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6780 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006781 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006782 (IS_COMBINING(c)) ||
6783 (IS_EXTENDER(c)))) {
6784 COPY_BUF(l,buf,len,c);
6785 NEXTL(l);
6786 c = CUR_CHAR(l);
6787 if (len >= XML_MAX_NAMELEN) {
6788 /*
6789 * Okay someone managed to make a huge name, so he's ready to pay
6790 * for the processing speed.
6791 */
6792 xmlChar *buffer;
6793 int max = len * 2;
6794
6795 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6796 if (buffer == NULL) {
6797 XP_ERROR0(XPATH_MEMORY_ERROR);
6798 }
6799 memcpy(buffer, buf, len);
6800 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6801 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006802 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006803 (IS_COMBINING(c)) ||
6804 (IS_EXTENDER(c))) {
6805 if (len + 10 > max) {
6806 max *= 2;
6807 buffer = (xmlChar *) xmlRealloc(buffer,
6808 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006809 if (buffer == NULL) {
6810 XP_ERROR0(XPATH_MEMORY_ERROR);
6811 }
6812 }
6813 COPY_BUF(l,buffer,len,c);
6814 NEXTL(l);
6815 c = CUR_CHAR(l);
6816 }
6817 buffer[len] = 0;
6818 return(buffer);
6819 }
6820 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006821 if (len == 0)
6822 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006823 return(xmlStrndup(buf, len));
6824}
Owen Taylor3473f882001-02-23 17:55:21 +00006825/**
6826 * xmlXPathStringEvalNumber:
6827 * @str: A string to scan
6828 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006829 * [30a] Float ::= Number ('e' Digits?)?
6830 *
Owen Taylor3473f882001-02-23 17:55:21 +00006831 * [30] Number ::= Digits ('.' Digits?)?
6832 * | '.' Digits
6833 * [31] Digits ::= [0-9]+
6834 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006835 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006836 * In complement of the Number expression, this function also handles
6837 * negative values : '-' Number.
6838 *
6839 * Returns the double value.
6840 */
6841double
6842xmlXPathStringEvalNumber(const xmlChar *str) {
6843 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00006844 double ret;
Owen Taylor3473f882001-02-23 17:55:21 +00006845 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006846 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006847 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006848 int exponent = 0;
6849 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006850#ifdef __GNUC__
6851 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006852 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006853#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006854
Owen Taylor3473f882001-02-23 17:55:21 +00006855 while (IS_BLANK(*cur)) cur++;
6856 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6857 return(xmlXPathNAN);
6858 }
6859 if (*cur == '-') {
6860 isneg = 1;
6861 cur++;
6862 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006863
6864#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006865 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006866 * tmp/temp is a workaround against a gcc compiler bug
6867 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006868 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006869 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006870 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006871 ret = ret * 10;
6872 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006873 ok = 1;
6874 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00006875 temp = (double) tmp;
6876 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006877 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006878#else
Daniel Veillard7b416132002-03-07 08:36:03 +00006879 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006880 while ((*cur >= '0') && (*cur <= '9')) {
6881 ret = ret * 10 + (*cur - '0');
6882 ok = 1;
6883 cur++;
6884 }
6885#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006886
Owen Taylor3473f882001-02-23 17:55:21 +00006887 if (*cur == '.') {
6888 cur++;
6889 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6890 return(xmlXPathNAN);
6891 }
6892 while ((*cur >= '0') && (*cur <= '9')) {
6893 mult /= 10;
6894 ret = ret + (*cur - '0') * mult;
6895 cur++;
6896 }
6897 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006898 if ((*cur == 'e') || (*cur == 'E')) {
6899 cur++;
6900 if (*cur == '-') {
6901 is_exponent_negative = 1;
6902 cur++;
6903 }
6904 while ((*cur >= '0') && (*cur <= '9')) {
6905 exponent = exponent * 10 + (*cur - '0');
6906 cur++;
6907 }
6908 }
Owen Taylor3473f882001-02-23 17:55:21 +00006909 while (IS_BLANK(*cur)) cur++;
6910 if (*cur != 0) return(xmlXPathNAN);
6911 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006912 if (is_exponent_negative) exponent = -exponent;
6913 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006914 return(ret);
6915}
6916
6917/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006918 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006919 * @ctxt: the XPath Parser context
6920 *
6921 * [30] Number ::= Digits ('.' Digits?)?
6922 * | '.' Digits
6923 * [31] Digits ::= [0-9]+
6924 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006925 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006926 *
6927 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006928static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006929xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6930{
Owen Taylor3473f882001-02-23 17:55:21 +00006931 double ret = 0.0;
6932 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00006933 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006934 int exponent = 0;
6935 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006936#ifdef __GNUC__
6937 unsigned long tmp = 0;
6938 double temp;
6939#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006940
6941 CHECK_ERROR;
6942 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6943 XP_ERROR(XPATH_NUMBER_ERROR);
6944 }
Daniel Veillard7b416132002-03-07 08:36:03 +00006945#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006946 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006947 * tmp/temp is a workaround against a gcc compiler bug
6948 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006949 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006950 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006951 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006952 ret = ret * 10;
6953 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006954 ok = 1;
6955 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00006956 temp = (double) tmp;
6957 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006958 }
Daniel Veillard7b416132002-03-07 08:36:03 +00006959#else
6960 ret = 0;
6961 while ((CUR >= '0') && (CUR <= '9')) {
6962 ret = ret * 10 + (CUR - '0');
6963 ok = 1;
6964 NEXT;
6965 }
6966#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006967 if (CUR == '.') {
6968 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006969 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6970 XP_ERROR(XPATH_NUMBER_ERROR);
6971 }
6972 while ((CUR >= '0') && (CUR <= '9')) {
6973 mult /= 10;
6974 ret = ret + (CUR - '0') * mult;
6975 NEXT;
6976 }
Owen Taylor3473f882001-02-23 17:55:21 +00006977 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006978 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006979 NEXT;
6980 if (CUR == '-') {
6981 is_exponent_negative = 1;
6982 NEXT;
6983 }
6984 while ((CUR >= '0') && (CUR <= '9')) {
6985 exponent = exponent * 10 + (CUR - '0');
6986 NEXT;
6987 }
6988 if (is_exponent_negative)
6989 exponent = -exponent;
6990 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006991 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006992 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006993 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006994}
6995
6996/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006997 * xmlXPathParseLiteral:
6998 * @ctxt: the XPath Parser context
6999 *
7000 * Parse a Literal
7001 *
7002 * [29] Literal ::= '"' [^"]* '"'
7003 * | "'" [^']* "'"
7004 *
7005 * Returns the value found or NULL in case of error
7006 */
7007static xmlChar *
7008xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7009 const xmlChar *q;
7010 xmlChar *ret = NULL;
7011
7012 if (CUR == '"') {
7013 NEXT;
7014 q = CUR_PTR;
7015 while ((IS_CHAR(CUR)) && (CUR != '"'))
7016 NEXT;
7017 if (!IS_CHAR(CUR)) {
7018 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7019 } else {
7020 ret = xmlStrndup(q, CUR_PTR - q);
7021 NEXT;
7022 }
7023 } else if (CUR == '\'') {
7024 NEXT;
7025 q = CUR_PTR;
7026 while ((IS_CHAR(CUR)) && (CUR != '\''))
7027 NEXT;
7028 if (!IS_CHAR(CUR)) {
7029 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7030 } else {
7031 ret = xmlStrndup(q, CUR_PTR - q);
7032 NEXT;
7033 }
7034 } else {
7035 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7036 }
7037 return(ret);
7038}
7039
7040/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007041 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007042 * @ctxt: the XPath Parser context
7043 *
7044 * Parse a Literal and push it on the stack.
7045 *
7046 * [29] Literal ::= '"' [^"]* '"'
7047 * | "'" [^']* "'"
7048 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007049 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007050 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007051static void
7052xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007053 const xmlChar *q;
7054 xmlChar *ret = NULL;
7055
7056 if (CUR == '"') {
7057 NEXT;
7058 q = CUR_PTR;
7059 while ((IS_CHAR(CUR)) && (CUR != '"'))
7060 NEXT;
7061 if (!IS_CHAR(CUR)) {
7062 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7063 } else {
7064 ret = xmlStrndup(q, CUR_PTR - q);
7065 NEXT;
7066 }
7067 } else if (CUR == '\'') {
7068 NEXT;
7069 q = CUR_PTR;
7070 while ((IS_CHAR(CUR)) && (CUR != '\''))
7071 NEXT;
7072 if (!IS_CHAR(CUR)) {
7073 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7074 } else {
7075 ret = xmlStrndup(q, CUR_PTR - q);
7076 NEXT;
7077 }
7078 } else {
7079 XP_ERROR(XPATH_START_LITERAL_ERROR);
7080 }
7081 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007082 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7083 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007084 xmlFree(ret);
7085}
7086
7087/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007088 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007089 * @ctxt: the XPath Parser context
7090 *
7091 * Parse a VariableReference, evaluate it and push it on the stack.
7092 *
7093 * The variable bindings consist of a mapping from variable names
7094 * to variable values. The value of a variable is an object, which
7095 * of any of the types that are possible for the value of an expression,
7096 * and may also be of additional types not specified here.
7097 *
7098 * Early evaluation is possible since:
7099 * The variable bindings [...] used to evaluate a subexpression are
7100 * always the same as those used to evaluate the containing expression.
7101 *
7102 * [36] VariableReference ::= '$' QName
7103 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007104static void
7105xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007106 xmlChar *name;
7107 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007108
7109 SKIP_BLANKS;
7110 if (CUR != '$') {
7111 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7112 }
7113 NEXT;
7114 name = xmlXPathParseQName(ctxt, &prefix);
7115 if (name == NULL) {
7116 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7117 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007118 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007119 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7120 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007121 SKIP_BLANKS;
7122}
7123
7124/**
7125 * xmlXPathIsNodeType:
7126 * @ctxt: the XPath Parser context
7127 * @name: a name string
7128 *
7129 * Is the name given a NodeType one.
7130 *
7131 * [38] NodeType ::= 'comment'
7132 * | 'text'
7133 * | 'processing-instruction'
7134 * | 'node'
7135 *
7136 * Returns 1 if true 0 otherwise
7137 */
7138int
7139xmlXPathIsNodeType(const xmlChar *name) {
7140 if (name == NULL)
7141 return(0);
7142
Daniel Veillard1971ee22002-01-31 20:29:19 +00007143 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007144 return(1);
7145 if (xmlStrEqual(name, BAD_CAST "text"))
7146 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007147 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007148 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007149 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007150 return(1);
7151 return(0);
7152}
7153
7154/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007155 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007156 * @ctxt: the XPath Parser context
7157 *
7158 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7159 * [17] Argument ::= Expr
7160 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007161 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007162 * pushed on the stack
7163 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007164static void
7165xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007166 xmlChar *name;
7167 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007168 int nbargs = 0;
7169
7170 name = xmlXPathParseQName(ctxt, &prefix);
7171 if (name == NULL) {
7172 XP_ERROR(XPATH_EXPR_ERROR);
7173 }
7174 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007175#ifdef DEBUG_EXPR
7176 if (prefix == NULL)
7177 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7178 name);
7179 else
7180 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7181 prefix, name);
7182#endif
7183
Owen Taylor3473f882001-02-23 17:55:21 +00007184 if (CUR != '(') {
7185 XP_ERROR(XPATH_EXPR_ERROR);
7186 }
7187 NEXT;
7188 SKIP_BLANKS;
7189
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007190 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007191 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007192 int op1 = ctxt->comp->last;
7193 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007194 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007195 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007196 nbargs++;
7197 if (CUR == ')') break;
7198 if (CUR != ',') {
7199 XP_ERROR(XPATH_EXPR_ERROR);
7200 }
7201 NEXT;
7202 SKIP_BLANKS;
7203 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007204 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7205 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007206 NEXT;
7207 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007208}
7209
7210/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007211 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007212 * @ctxt: the XPath Parser context
7213 *
7214 * [15] PrimaryExpr ::= VariableReference
7215 * | '(' Expr ')'
7216 * | Literal
7217 * | Number
7218 * | FunctionCall
7219 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007220 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007221 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007222static void
7223xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007224 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007225 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007226 else if (CUR == '(') {
7227 NEXT;
7228 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007229 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007230 if (CUR != ')') {
7231 XP_ERROR(XPATH_EXPR_ERROR);
7232 }
7233 NEXT;
7234 SKIP_BLANKS;
7235 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007236 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007237 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007238 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007239 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007240 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007241 }
7242 SKIP_BLANKS;
7243}
7244
7245/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007246 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007247 * @ctxt: the XPath Parser context
7248 *
7249 * [20] FilterExpr ::= PrimaryExpr
7250 * | FilterExpr Predicate
7251 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007252 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007253 * Square brackets are used to filter expressions in the same way that
7254 * they are used in location paths. It is an error if the expression to
7255 * be filtered does not evaluate to a node-set. The context node list
7256 * used for evaluating the expression in square brackets is the node-set
7257 * to be filtered listed in document order.
7258 */
7259
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007260static void
7261xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7262 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007263 CHECK_ERROR;
7264 SKIP_BLANKS;
7265
7266 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007267 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007268 SKIP_BLANKS;
7269 }
7270
7271
7272}
7273
7274/**
7275 * xmlXPathScanName:
7276 * @ctxt: the XPath Parser context
7277 *
7278 * Trickery: parse an XML name but without consuming the input flow
7279 * Needed to avoid insanity in the parser state.
7280 *
7281 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7282 * CombiningChar | Extender
7283 *
7284 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7285 *
7286 * [6] Names ::= Name (S Name)*
7287 *
7288 * Returns the Name parsed or NULL
7289 */
7290
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007291static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007292xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7293 xmlChar buf[XML_MAX_NAMELEN];
7294 int len = 0;
7295
7296 SKIP_BLANKS;
7297 if (!IS_LETTER(CUR) && (CUR != '_') &&
7298 (CUR != ':')) {
7299 return(NULL);
7300 }
7301
7302 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7303 (NXT(len) == '.') || (NXT(len) == '-') ||
7304 (NXT(len) == '_') || (NXT(len) == ':') ||
7305 (IS_COMBINING(NXT(len))) ||
7306 (IS_EXTENDER(NXT(len)))) {
7307 buf[len] = NXT(len);
7308 len++;
7309 if (len >= XML_MAX_NAMELEN) {
7310 xmlGenericError(xmlGenericErrorContext,
7311 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7312 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7313 (NXT(len) == '.') || (NXT(len) == '-') ||
7314 (NXT(len) == '_') || (NXT(len) == ':') ||
7315 (IS_COMBINING(NXT(len))) ||
7316 (IS_EXTENDER(NXT(len))))
7317 len++;
7318 break;
7319 }
7320 }
7321 return(xmlStrndup(buf, len));
7322}
7323
7324/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007325 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007326 * @ctxt: the XPath Parser context
7327 *
7328 * [19] PathExpr ::= LocationPath
7329 * | FilterExpr
7330 * | FilterExpr '/' RelativeLocationPath
7331 * | FilterExpr '//' RelativeLocationPath
7332 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007333 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007334 * The / operator and // operators combine an arbitrary expression
7335 * and a relative location path. It is an error if the expression
7336 * does not evaluate to a node-set.
7337 * The / operator does composition in the same way as when / is
7338 * used in a location path. As in location paths, // is short for
7339 * /descendant-or-self::node()/.
7340 */
7341
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007342static void
7343xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007344 int lc = 1; /* Should we branch to LocationPath ? */
7345 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7346
7347 SKIP_BLANKS;
7348 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7349 (CUR == '\'') || (CUR == '"')) {
7350 lc = 0;
7351 } else if (CUR == '*') {
7352 /* relative or absolute location path */
7353 lc = 1;
7354 } else if (CUR == '/') {
7355 /* relative or absolute location path */
7356 lc = 1;
7357 } else if (CUR == '@') {
7358 /* relative abbreviated attribute location path */
7359 lc = 1;
7360 } else if (CUR == '.') {
7361 /* relative abbreviated attribute location path */
7362 lc = 1;
7363 } else {
7364 /*
7365 * Problem is finding if we have a name here whether it's:
7366 * - a nodetype
7367 * - a function call in which case it's followed by '('
7368 * - an axis in which case it's followed by ':'
7369 * - a element name
7370 * We do an a priori analysis here rather than having to
7371 * maintain parsed token content through the recursive function
7372 * calls. This looks uglier but makes the code quite easier to
7373 * read/write/debug.
7374 */
7375 SKIP_BLANKS;
7376 name = xmlXPathScanName(ctxt);
7377 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7378#ifdef DEBUG_STEP
7379 xmlGenericError(xmlGenericErrorContext,
7380 "PathExpr: Axis\n");
7381#endif
7382 lc = 1;
7383 xmlFree(name);
7384 } else if (name != NULL) {
7385 int len =xmlStrlen(name);
7386 int blank = 0;
7387
7388
7389 while (NXT(len) != 0) {
7390 if (NXT(len) == '/') {
7391 /* element name */
7392#ifdef DEBUG_STEP
7393 xmlGenericError(xmlGenericErrorContext,
7394 "PathExpr: AbbrRelLocation\n");
7395#endif
7396 lc = 1;
7397 break;
7398 } else if (IS_BLANK(NXT(len))) {
7399 /* skip to next */
7400 blank = 1;
7401 } else if (NXT(len) == ':') {
7402#ifdef DEBUG_STEP
7403 xmlGenericError(xmlGenericErrorContext,
7404 "PathExpr: AbbrRelLocation\n");
7405#endif
7406 lc = 1;
7407 break;
7408 } else if ((NXT(len) == '(')) {
7409 /* Note Type or Function */
7410 if (xmlXPathIsNodeType(name)) {
7411#ifdef DEBUG_STEP
7412 xmlGenericError(xmlGenericErrorContext,
7413 "PathExpr: Type search\n");
7414#endif
7415 lc = 1;
7416 } else {
7417#ifdef DEBUG_STEP
7418 xmlGenericError(xmlGenericErrorContext,
7419 "PathExpr: function call\n");
7420#endif
7421 lc = 0;
7422 }
7423 break;
7424 } else if ((NXT(len) == '[')) {
7425 /* element name */
7426#ifdef DEBUG_STEP
7427 xmlGenericError(xmlGenericErrorContext,
7428 "PathExpr: AbbrRelLocation\n");
7429#endif
7430 lc = 1;
7431 break;
7432 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7433 (NXT(len) == '=')) {
7434 lc = 1;
7435 break;
7436 } else {
7437 lc = 1;
7438 break;
7439 }
7440 len++;
7441 }
7442 if (NXT(len) == 0) {
7443#ifdef DEBUG_STEP
7444 xmlGenericError(xmlGenericErrorContext,
7445 "PathExpr: AbbrRelLocation\n");
7446#endif
7447 /* element name */
7448 lc = 1;
7449 }
7450 xmlFree(name);
7451 } else {
7452 /* make sure all cases are covered explicitely */
7453 XP_ERROR(XPATH_EXPR_ERROR);
7454 }
7455 }
7456
7457 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007458 if (CUR == '/') {
7459 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7460 } else {
7461 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007462 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007463 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007464 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007465 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007466 CHECK_ERROR;
7467 if ((CUR == '/') && (NXT(1) == '/')) {
7468 SKIP(2);
7469 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007470
7471 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7472 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7473 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7474
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007475 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007476 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007477 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007478 }
7479 }
7480 SKIP_BLANKS;
7481}
7482
7483/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007484 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007485 * @ctxt: the XPath Parser context
7486 *
7487 * [18] UnionExpr ::= PathExpr
7488 * | UnionExpr '|' PathExpr
7489 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007490 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007491 */
7492
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007493static void
7494xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7495 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007496 CHECK_ERROR;
7497 SKIP_BLANKS;
7498 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007499 int op1 = ctxt->comp->last;
7500 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007501
7502 NEXT;
7503 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007504 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007505
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007506 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7507
Owen Taylor3473f882001-02-23 17:55:21 +00007508 SKIP_BLANKS;
7509 }
Owen Taylor3473f882001-02-23 17:55:21 +00007510}
7511
7512/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007513 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007514 * @ctxt: the XPath Parser context
7515 *
7516 * [27] UnaryExpr ::= UnionExpr
7517 * | '-' UnaryExpr
7518 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007519 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007520 */
7521
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007522static void
7523xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007524 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007525 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007526
7527 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007528 while (CUR == '-') {
7529 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007530 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007531 NEXT;
7532 SKIP_BLANKS;
7533 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007534
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007535 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007536 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007537 if (found) {
7538 if (minus)
7539 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7540 else
7541 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007542 }
7543}
7544
7545/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007546 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007547 * @ctxt: the XPath Parser context
7548 *
7549 * [26] MultiplicativeExpr ::= UnaryExpr
7550 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7551 * | MultiplicativeExpr 'div' UnaryExpr
7552 * | MultiplicativeExpr 'mod' UnaryExpr
7553 * [34] MultiplyOperator ::= '*'
7554 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007555 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007556 */
7557
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007558static void
7559xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7560 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007561 CHECK_ERROR;
7562 SKIP_BLANKS;
7563 while ((CUR == '*') ||
7564 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7565 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7566 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007567 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007568
7569 if (CUR == '*') {
7570 op = 0;
7571 NEXT;
7572 } else if (CUR == 'd') {
7573 op = 1;
7574 SKIP(3);
7575 } else if (CUR == 'm') {
7576 op = 2;
7577 SKIP(3);
7578 }
7579 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007580 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007581 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007582 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007583 SKIP_BLANKS;
7584 }
7585}
7586
7587/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007588 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007589 * @ctxt: the XPath Parser context
7590 *
7591 * [25] AdditiveExpr ::= MultiplicativeExpr
7592 * | AdditiveExpr '+' MultiplicativeExpr
7593 * | AdditiveExpr '-' MultiplicativeExpr
7594 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007595 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007596 */
7597
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007598static void
7599xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007600
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007601 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007602 CHECK_ERROR;
7603 SKIP_BLANKS;
7604 while ((CUR == '+') || (CUR == '-')) {
7605 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007606 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007607
7608 if (CUR == '+') plus = 1;
7609 else plus = 0;
7610 NEXT;
7611 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007612 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007613 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007614 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007615 SKIP_BLANKS;
7616 }
7617}
7618
7619/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007620 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007621 * @ctxt: the XPath Parser context
7622 *
7623 * [24] RelationalExpr ::= AdditiveExpr
7624 * | RelationalExpr '<' AdditiveExpr
7625 * | RelationalExpr '>' AdditiveExpr
7626 * | RelationalExpr '<=' AdditiveExpr
7627 * | RelationalExpr '>=' AdditiveExpr
7628 *
7629 * A <= B > C is allowed ? Answer from James, yes with
7630 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7631 * which is basically what got implemented.
7632 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007633 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007634 * on the stack
7635 */
7636
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007637static void
7638xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7639 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007640 CHECK_ERROR;
7641 SKIP_BLANKS;
7642 while ((CUR == '<') ||
7643 (CUR == '>') ||
7644 ((CUR == '<') && (NXT(1) == '=')) ||
7645 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007646 int inf, strict;
7647 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007648
7649 if (CUR == '<') inf = 1;
7650 else inf = 0;
7651 if (NXT(1) == '=') strict = 0;
7652 else strict = 1;
7653 NEXT;
7654 if (!strict) NEXT;
7655 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007656 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007657 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007658 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007659 SKIP_BLANKS;
7660 }
7661}
7662
7663/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007664 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007665 * @ctxt: the XPath Parser context
7666 *
7667 * [23] EqualityExpr ::= RelationalExpr
7668 * | EqualityExpr '=' RelationalExpr
7669 * | EqualityExpr '!=' RelationalExpr
7670 *
7671 * A != B != C is allowed ? Answer from James, yes with
7672 * (RelationalExpr = RelationalExpr) = RelationalExpr
7673 * (RelationalExpr != RelationalExpr) != RelationalExpr
7674 * which is basically what got implemented.
7675 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007676 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007677 *
7678 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007679static void
7680xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7681 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007682 CHECK_ERROR;
7683 SKIP_BLANKS;
7684 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007685 int eq;
7686 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007687
7688 if (CUR == '=') eq = 1;
7689 else eq = 0;
7690 NEXT;
7691 if (!eq) NEXT;
7692 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007693 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007694 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007695 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007696 SKIP_BLANKS;
7697 }
7698}
7699
7700/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007701 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007702 * @ctxt: the XPath Parser context
7703 *
7704 * [22] AndExpr ::= EqualityExpr
7705 * | AndExpr 'and' EqualityExpr
7706 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007707 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007708 *
7709 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007710static void
7711xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7712 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007713 CHECK_ERROR;
7714 SKIP_BLANKS;
7715 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007716 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007717 SKIP(3);
7718 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007719 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007720 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007721 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007722 SKIP_BLANKS;
7723 }
7724}
7725
7726/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007727 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007728 * @ctxt: the XPath Parser context
7729 *
7730 * [14] Expr ::= OrExpr
7731 * [21] OrExpr ::= AndExpr
7732 * | OrExpr 'or' AndExpr
7733 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007734 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007735 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007736static void
7737xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7738 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007739 CHECK_ERROR;
7740 SKIP_BLANKS;
7741 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007742 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007743 SKIP(2);
7744 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007745 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007746 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007747 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7748 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007749 SKIP_BLANKS;
7750 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007751 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7752 /* more ops could be optimized too */
7753 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7754 }
Owen Taylor3473f882001-02-23 17:55:21 +00007755}
7756
7757/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007758 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007759 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007760 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007761 *
7762 * [8] Predicate ::= '[' PredicateExpr ']'
7763 * [9] PredicateExpr ::= Expr
7764 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007765 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007766 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007767static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007768xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007769 int op1 = ctxt->comp->last;
7770
7771 SKIP_BLANKS;
7772 if (CUR != '[') {
7773 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7774 }
7775 NEXT;
7776 SKIP_BLANKS;
7777
7778 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007779 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007780 CHECK_ERROR;
7781
7782 if (CUR != ']') {
7783 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7784 }
7785
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007786 if (filter)
7787 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7788 else
7789 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007790
7791 NEXT;
7792 SKIP_BLANKS;
7793}
7794
7795/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007796 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007797 * @ctxt: the XPath Parser context
7798 * @test: pointer to a xmlXPathTestVal
7799 * @type: pointer to a xmlXPathTypeVal
7800 * @prefix: placeholder for a possible name prefix
7801 *
7802 * [7] NodeTest ::= NameTest
7803 * | NodeType '(' ')'
7804 * | 'processing-instruction' '(' Literal ')'
7805 *
7806 * [37] NameTest ::= '*'
7807 * | NCName ':' '*'
7808 * | QName
7809 * [38] NodeType ::= 'comment'
7810 * | 'text'
7811 * | 'processing-instruction'
7812 * | 'node'
7813 *
7814 * Returns the name found and update @test, @type and @prefix appropriately
7815 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007816static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007817xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7818 xmlXPathTypeVal *type, const xmlChar **prefix,
7819 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007820 int blanks;
7821
7822 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7823 STRANGE;
7824 return(NULL);
7825 }
7826 *type = 0;
7827 *test = 0;
7828 *prefix = NULL;
7829 SKIP_BLANKS;
7830
7831 if ((name == NULL) && (CUR == '*')) {
7832 /*
7833 * All elements
7834 */
7835 NEXT;
7836 *test = NODE_TEST_ALL;
7837 return(NULL);
7838 }
7839
7840 if (name == NULL)
7841 name = xmlXPathParseNCName(ctxt);
7842 if (name == NULL) {
7843 XP_ERROR0(XPATH_EXPR_ERROR);
7844 }
7845
7846 blanks = IS_BLANK(CUR);
7847 SKIP_BLANKS;
7848 if (CUR == '(') {
7849 NEXT;
7850 /*
7851 * NodeType or PI search
7852 */
7853 if (xmlStrEqual(name, BAD_CAST "comment"))
7854 *type = NODE_TYPE_COMMENT;
7855 else if (xmlStrEqual(name, BAD_CAST "node"))
7856 *type = NODE_TYPE_NODE;
7857 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7858 *type = NODE_TYPE_PI;
7859 else if (xmlStrEqual(name, BAD_CAST "text"))
7860 *type = NODE_TYPE_TEXT;
7861 else {
7862 if (name != NULL)
7863 xmlFree(name);
7864 XP_ERROR0(XPATH_EXPR_ERROR);
7865 }
7866
7867 *test = NODE_TEST_TYPE;
7868
7869 SKIP_BLANKS;
7870 if (*type == NODE_TYPE_PI) {
7871 /*
7872 * Specific case: search a PI by name.
7873 */
Owen Taylor3473f882001-02-23 17:55:21 +00007874 if (name != NULL)
7875 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007876 name = NULL;
7877 if (CUR != ')') {
7878 name = xmlXPathParseLiteral(ctxt);
7879 CHECK_ERROR 0;
7880 SKIP_BLANKS;
7881 }
Owen Taylor3473f882001-02-23 17:55:21 +00007882 }
7883 if (CUR != ')') {
7884 if (name != NULL)
7885 xmlFree(name);
7886 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7887 }
7888 NEXT;
7889 return(name);
7890 }
7891 *test = NODE_TEST_NAME;
7892 if ((!blanks) && (CUR == ':')) {
7893 NEXT;
7894
7895 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007896 * Since currently the parser context don't have a
7897 * namespace list associated:
7898 * The namespace name for this prefix can be computed
7899 * only at evaluation time. The compilation is done
7900 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007901 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007902#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007903 *prefix = xmlXPathNsLookup(ctxt->context, name);
7904 if (name != NULL)
7905 xmlFree(name);
7906 if (*prefix == NULL) {
7907 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7908 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007909#else
7910 *prefix = name;
7911#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007912
7913 if (CUR == '*') {
7914 /*
7915 * All elements
7916 */
7917 NEXT;
7918 *test = NODE_TEST_ALL;
7919 return(NULL);
7920 }
7921
7922 name = xmlXPathParseNCName(ctxt);
7923 if (name == NULL) {
7924 XP_ERROR0(XPATH_EXPR_ERROR);
7925 }
7926 }
7927 return(name);
7928}
7929
7930/**
7931 * xmlXPathIsAxisName:
7932 * @name: a preparsed name token
7933 *
7934 * [6] AxisName ::= 'ancestor'
7935 * | 'ancestor-or-self'
7936 * | 'attribute'
7937 * | 'child'
7938 * | 'descendant'
7939 * | 'descendant-or-self'
7940 * | 'following'
7941 * | 'following-sibling'
7942 * | 'namespace'
7943 * | 'parent'
7944 * | 'preceding'
7945 * | 'preceding-sibling'
7946 * | 'self'
7947 *
7948 * Returns the axis or 0
7949 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007950static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007951xmlXPathIsAxisName(const xmlChar *name) {
7952 xmlXPathAxisVal ret = 0;
7953 switch (name[0]) {
7954 case 'a':
7955 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7956 ret = AXIS_ANCESTOR;
7957 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7958 ret = AXIS_ANCESTOR_OR_SELF;
7959 if (xmlStrEqual(name, BAD_CAST "attribute"))
7960 ret = AXIS_ATTRIBUTE;
7961 break;
7962 case 'c':
7963 if (xmlStrEqual(name, BAD_CAST "child"))
7964 ret = AXIS_CHILD;
7965 break;
7966 case 'd':
7967 if (xmlStrEqual(name, BAD_CAST "descendant"))
7968 ret = AXIS_DESCENDANT;
7969 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7970 ret = AXIS_DESCENDANT_OR_SELF;
7971 break;
7972 case 'f':
7973 if (xmlStrEqual(name, BAD_CAST "following"))
7974 ret = AXIS_FOLLOWING;
7975 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7976 ret = AXIS_FOLLOWING_SIBLING;
7977 break;
7978 case 'n':
7979 if (xmlStrEqual(name, BAD_CAST "namespace"))
7980 ret = AXIS_NAMESPACE;
7981 break;
7982 case 'p':
7983 if (xmlStrEqual(name, BAD_CAST "parent"))
7984 ret = AXIS_PARENT;
7985 if (xmlStrEqual(name, BAD_CAST "preceding"))
7986 ret = AXIS_PRECEDING;
7987 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7988 ret = AXIS_PRECEDING_SIBLING;
7989 break;
7990 case 's':
7991 if (xmlStrEqual(name, BAD_CAST "self"))
7992 ret = AXIS_SELF;
7993 break;
7994 }
7995 return(ret);
7996}
7997
7998/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007999 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008000 * @ctxt: the XPath Parser context
8001 *
8002 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8003 * | AbbreviatedStep
8004 *
8005 * [12] AbbreviatedStep ::= '.' | '..'
8006 *
8007 * [5] AxisSpecifier ::= AxisName '::'
8008 * | AbbreviatedAxisSpecifier
8009 *
8010 * [13] AbbreviatedAxisSpecifier ::= '@'?
8011 *
8012 * Modified for XPtr range support as:
8013 *
8014 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8015 * | AbbreviatedStep
8016 * | 'range-to' '(' Expr ')' Predicate*
8017 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008018 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008019 * A location step of . is short for self::node(). This is
8020 * particularly useful in conjunction with //. For example, the
8021 * location path .//para is short for
8022 * self::node()/descendant-or-self::node()/child::para
8023 * and so will select all para descendant elements of the context
8024 * node.
8025 * Similarly, a location step of .. is short for parent::node().
8026 * For example, ../title is short for parent::node()/child::title
8027 * and so will select the title children of the parent of the context
8028 * node.
8029 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008030static void
8031xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008032#ifdef LIBXML_XPTR_ENABLED
8033 int rangeto = 0;
8034 int op2 = -1;
8035#endif
8036
Owen Taylor3473f882001-02-23 17:55:21 +00008037 SKIP_BLANKS;
8038 if ((CUR == '.') && (NXT(1) == '.')) {
8039 SKIP(2);
8040 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008041 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8042 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008043 } else if (CUR == '.') {
8044 NEXT;
8045 SKIP_BLANKS;
8046 } else {
8047 xmlChar *name = NULL;
8048 const xmlChar *prefix = NULL;
8049 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008050 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008051 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008052 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008053
8054 /*
8055 * The modification needed for XPointer change to the production
8056 */
8057#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008058 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008059 name = xmlXPathParseNCName(ctxt);
8060 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008061 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008062 xmlFree(name);
8063 SKIP_BLANKS;
8064 if (CUR != '(') {
8065 XP_ERROR(XPATH_EXPR_ERROR);
8066 }
8067 NEXT;
8068 SKIP_BLANKS;
8069
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008070 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008071 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008072 CHECK_ERROR;
8073
8074 SKIP_BLANKS;
8075 if (CUR != ')') {
8076 XP_ERROR(XPATH_EXPR_ERROR);
8077 }
8078 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008079 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008080 goto eval_predicates;
8081 }
8082 }
8083#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008084 if (CUR == '*') {
8085 axis = AXIS_CHILD;
8086 } else {
8087 if (name == NULL)
8088 name = xmlXPathParseNCName(ctxt);
8089 if (name != NULL) {
8090 axis = xmlXPathIsAxisName(name);
8091 if (axis != 0) {
8092 SKIP_BLANKS;
8093 if ((CUR == ':') && (NXT(1) == ':')) {
8094 SKIP(2);
8095 xmlFree(name);
8096 name = NULL;
8097 } else {
8098 /* an element name can conflict with an axis one :-\ */
8099 axis = AXIS_CHILD;
8100 }
Owen Taylor3473f882001-02-23 17:55:21 +00008101 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008102 axis = AXIS_CHILD;
8103 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008104 } else if (CUR == '@') {
8105 NEXT;
8106 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008107 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008108 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008109 }
Owen Taylor3473f882001-02-23 17:55:21 +00008110 }
8111
8112 CHECK_ERROR;
8113
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008114 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008115 if (test == 0)
8116 return;
8117
8118#ifdef DEBUG_STEP
8119 xmlGenericError(xmlGenericErrorContext,
8120 "Basis : computing new set\n");
8121#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008122
Owen Taylor3473f882001-02-23 17:55:21 +00008123#ifdef DEBUG_STEP
8124 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008125 if (ctxt->value == NULL)
8126 xmlGenericError(xmlGenericErrorContext, "no value\n");
8127 else if (ctxt->value->nodesetval == NULL)
8128 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8129 else
8130 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008131#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008132
8133eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008134 op1 = ctxt->comp->last;
8135 ctxt->comp->last = -1;
8136
Owen Taylor3473f882001-02-23 17:55:21 +00008137 SKIP_BLANKS;
8138 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008139 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008140 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008141
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008142#ifdef LIBXML_XPTR_ENABLED
8143 if (rangeto) {
8144 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8145 } else
8146#endif
8147 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8148 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008149
Owen Taylor3473f882001-02-23 17:55:21 +00008150 }
8151#ifdef DEBUG_STEP
8152 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008153 if (ctxt->value == NULL)
8154 xmlGenericError(xmlGenericErrorContext, "no value\n");
8155 else if (ctxt->value->nodesetval == NULL)
8156 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8157 else
8158 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8159 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008160#endif
8161}
8162
8163/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008164 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008165 * @ctxt: the XPath Parser context
8166 *
8167 * [3] RelativeLocationPath ::= Step
8168 * | RelativeLocationPath '/' Step
8169 * | AbbreviatedRelativeLocationPath
8170 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8171 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008172 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008173 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008174static void
Owen Taylor3473f882001-02-23 17:55:21 +00008175#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008176xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008177#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008178xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008179#endif
8180(xmlXPathParserContextPtr ctxt) {
8181 SKIP_BLANKS;
8182 if ((CUR == '/') && (NXT(1) == '/')) {
8183 SKIP(2);
8184 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008185 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8186 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008187 } else if (CUR == '/') {
8188 NEXT;
8189 SKIP_BLANKS;
8190 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008191 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008192 SKIP_BLANKS;
8193 while (CUR == '/') {
8194 if ((CUR == '/') && (NXT(1) == '/')) {
8195 SKIP(2);
8196 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008197 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008198 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008199 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008200 } else if (CUR == '/') {
8201 NEXT;
8202 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008203 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008204 }
8205 SKIP_BLANKS;
8206 }
8207}
8208
8209/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008210 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008211 * @ctxt: the XPath Parser context
8212 *
8213 * [1] LocationPath ::= RelativeLocationPath
8214 * | AbsoluteLocationPath
8215 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8216 * | AbbreviatedAbsoluteLocationPath
8217 * [10] AbbreviatedAbsoluteLocationPath ::=
8218 * '//' RelativeLocationPath
8219 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008220 * Compile a location path
8221 *
Owen Taylor3473f882001-02-23 17:55:21 +00008222 * // is short for /descendant-or-self::node()/. For example,
8223 * //para is short for /descendant-or-self::node()/child::para and
8224 * so will select any para element in the document (even a para element
8225 * that is a document element will be selected by //para since the
8226 * document element node is a child of the root node); div//para is
8227 * short for div/descendant-or-self::node()/child::para and so will
8228 * select all para descendants of div children.
8229 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008230static void
8231xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008232 SKIP_BLANKS;
8233 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008234 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008235 } else {
8236 while (CUR == '/') {
8237 if ((CUR == '/') && (NXT(1) == '/')) {
8238 SKIP(2);
8239 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008240 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8241 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008242 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008243 } else if (CUR == '/') {
8244 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008245 SKIP_BLANKS;
8246 if ((CUR != 0 ) &&
8247 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8248 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008249 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008250 }
8251 }
8252 }
8253}
8254
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008255/************************************************************************
8256 * *
8257 * XPath precompiled expression evaluation *
8258 * *
8259 ************************************************************************/
8260
Daniel Veillardf06307e2001-07-03 10:35:50 +00008261static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008262xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8263
8264/**
8265 * xmlXPathNodeCollectAndTest:
8266 * @ctxt: the XPath Parser context
8267 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008268 * @first: pointer to the first element in document order
8269 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008270 *
8271 * This is the function implementing a step: based on the current list
8272 * of nodes, it builds up a new list, looking at all nodes under that
8273 * axis and selecting them it also do the predicate filtering
8274 *
8275 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008276 *
8277 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008278 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008279static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008280xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008281 xmlXPathStepOpPtr op,
8282 xmlNodePtr * first, xmlNodePtr * last)
8283{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008284 xmlXPathAxisVal axis = op->value;
8285 xmlXPathTestVal test = op->value2;
8286 xmlXPathTypeVal type = op->value3;
8287 const xmlChar *prefix = op->value4;
8288 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008289 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008290
8291#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008292 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008293#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008294 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008295 xmlNodeSetPtr ret, list;
8296 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008297 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008298 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008299 xmlNodePtr cur = NULL;
8300 xmlXPathObjectPtr obj;
8301 xmlNodeSetPtr nodelist;
8302 xmlNodePtr tmp;
8303
Daniel Veillardf06307e2001-07-03 10:35:50 +00008304 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008305 obj = valuePop(ctxt);
8306 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008307 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008308 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008309 URI = xmlXPathNsLookup(ctxt->context, prefix);
8310 if (URI == NULL)
8311 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008312 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008313#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008314 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008315#endif
8316 switch (axis) {
8317 case AXIS_ANCESTOR:
8318#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008319 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008320#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008321 first = NULL;
8322 next = xmlXPathNextAncestor;
8323 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008324 case AXIS_ANCESTOR_OR_SELF:
8325#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008326 xmlGenericError(xmlGenericErrorContext,
8327 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008328#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008329 first = NULL;
8330 next = xmlXPathNextAncestorOrSelf;
8331 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008332 case AXIS_ATTRIBUTE:
8333#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008334 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008335#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008336 first = NULL;
8337 last = NULL;
8338 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008339 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008340 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008341 case AXIS_CHILD:
8342#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008343 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008344#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008345 last = NULL;
8346 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008347 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008348 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008349 case AXIS_DESCENDANT:
8350#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008351 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008352#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008353 last = NULL;
8354 next = xmlXPathNextDescendant;
8355 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008356 case AXIS_DESCENDANT_OR_SELF:
8357#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008358 xmlGenericError(xmlGenericErrorContext,
8359 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008360#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008361 last = NULL;
8362 next = xmlXPathNextDescendantOrSelf;
8363 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008364 case AXIS_FOLLOWING:
8365#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008366 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008367#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008368 last = NULL;
8369 next = xmlXPathNextFollowing;
8370 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008371 case AXIS_FOLLOWING_SIBLING:
8372#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008373 xmlGenericError(xmlGenericErrorContext,
8374 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008375#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008376 last = NULL;
8377 next = xmlXPathNextFollowingSibling;
Daniel Veillard75be0132002-03-13 10:03:35 +00008378 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008379 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008380 case AXIS_NAMESPACE:
8381#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008382 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008383#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008384 first = NULL;
8385 last = NULL;
8386 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008387 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008388 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008389 case AXIS_PARENT:
8390#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008391 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008392#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008393 first = NULL;
8394 next = xmlXPathNextParent;
8395 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008396 case AXIS_PRECEDING:
8397#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008398 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008399#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008400 first = NULL;
8401 next = xmlXPathNextPrecedingInternal;
8402 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008403 case AXIS_PRECEDING_SIBLING:
8404#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008405 xmlGenericError(xmlGenericErrorContext,
8406 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008407#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008408 first = NULL;
8409 next = xmlXPathNextPrecedingSibling;
Daniel Veillard75be0132002-03-13 10:03:35 +00008410 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008411 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008412 case AXIS_SELF:
8413#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008414 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008415#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008416 first = NULL;
8417 last = NULL;
8418 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008419 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008420 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008421 }
8422 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008423 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008424
8425 nodelist = obj->nodesetval;
8426 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008427 xmlXPathFreeObject(obj);
8428 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8429 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008430 }
8431 addNode = xmlXPathNodeSetAddUnique;
8432 ret = NULL;
8433#ifdef DEBUG_STEP
8434 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008435 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008436 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008437 case NODE_TEST_NONE:
8438 xmlGenericError(xmlGenericErrorContext,
8439 " searching for none !!!\n");
8440 break;
8441 case NODE_TEST_TYPE:
8442 xmlGenericError(xmlGenericErrorContext,
8443 " searching for type %d\n", type);
8444 break;
8445 case NODE_TEST_PI:
8446 xmlGenericError(xmlGenericErrorContext,
8447 " searching for PI !!!\n");
8448 break;
8449 case NODE_TEST_ALL:
8450 xmlGenericError(xmlGenericErrorContext,
8451 " searching for *\n");
8452 break;
8453 case NODE_TEST_NS:
8454 xmlGenericError(xmlGenericErrorContext,
8455 " searching for namespace %s\n",
8456 prefix);
8457 break;
8458 case NODE_TEST_NAME:
8459 xmlGenericError(xmlGenericErrorContext,
8460 " searching for name %s\n", name);
8461 if (prefix != NULL)
8462 xmlGenericError(xmlGenericErrorContext,
8463 " with namespace %s\n", prefix);
8464 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008465 }
8466 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8467#endif
8468 /*
8469 * 2.3 Node Tests
8470 * - For the attribute axis, the principal node type is attribute.
8471 * - For the namespace axis, the principal node type is namespace.
8472 * - For other axes, the principal node type is element.
8473 *
8474 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008475 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008476 * select all element children of the context node
8477 */
8478 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008479 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008480 ctxt->context->node = nodelist->nodeTab[i];
8481
Daniel Veillardf06307e2001-07-03 10:35:50 +00008482 cur = NULL;
8483 list = xmlXPathNodeSetCreate(NULL);
8484 do {
8485 cur = next(ctxt, cur);
8486 if (cur == NULL)
8487 break;
8488 if ((first != NULL) && (*first == cur))
8489 break;
8490 if (((t % 256) == 0) &&
8491 (first != NULL) && (*first != NULL) &&
8492 (xmlXPathCmpNodes(*first, cur) >= 0))
8493 break;
8494 if ((last != NULL) && (*last == cur))
8495 break;
8496 if (((t % 256) == 0) &&
8497 (last != NULL) && (*last != NULL) &&
8498 (xmlXPathCmpNodes(cur, *last) >= 0))
8499 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008500 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008501#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008502 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8503#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008504 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008505 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008506 ctxt->context->node = tmp;
8507 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008508 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008509 if ((cur->type == type) ||
8510 ((type == NODE_TYPE_NODE) &&
8511 ((cur->type == XML_DOCUMENT_NODE) ||
8512 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8513 (cur->type == XML_ELEMENT_NODE) ||
8514 (cur->type == XML_PI_NODE) ||
8515 (cur->type == XML_COMMENT_NODE) ||
8516 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008517 (cur->type == XML_TEXT_NODE))) ||
8518 ((type == NODE_TYPE_TEXT) &&
8519 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008520#ifdef DEBUG_STEP
8521 n++;
8522#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008523 addNode(list, cur);
8524 }
8525 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008526 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008527 if (cur->type == XML_PI_NODE) {
8528 if ((name != NULL) &&
8529 (!xmlStrEqual(name, cur->name)))
8530 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008531#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008532 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008533#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008534 addNode(list, cur);
8535 }
8536 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008537 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008538 if (axis == AXIS_ATTRIBUTE) {
8539 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008540#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008541 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008542#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008543 addNode(list, cur);
8544 }
8545 } else if (axis == AXIS_NAMESPACE) {
8546 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008547#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008548 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008549#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008550 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8551 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008552 }
8553 } else {
8554 if (cur->type == XML_ELEMENT_NODE) {
8555 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008556#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008557 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008558#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008559 addNode(list, cur);
8560 } else if ((cur->ns != NULL) &&
8561 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008562#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008563 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008564#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008565 addNode(list, cur);
8566 }
8567 }
8568 }
8569 break;
8570 case NODE_TEST_NS:{
8571 TODO;
8572 break;
8573 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008574 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008575 switch (cur->type) {
8576 case XML_ELEMENT_NODE:
8577 if (xmlStrEqual(name, cur->name)) {
8578 if (prefix == NULL) {
8579 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008580#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008581 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008582#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008583 addNode(list, cur);
8584 }
8585 } else {
8586 if ((cur->ns != NULL) &&
8587 (xmlStrEqual(URI,
8588 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008589#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008590 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008591#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008592 addNode(list, cur);
8593 }
8594 }
8595 }
8596 break;
8597 case XML_ATTRIBUTE_NODE:{
8598 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008599
Daniel Veillardf06307e2001-07-03 10:35:50 +00008600 if (xmlStrEqual(name, attr->name)) {
8601 if (prefix == NULL) {
8602 if ((attr->ns == NULL) ||
8603 (attr->ns->prefix == NULL)) {
8604#ifdef DEBUG_STEP
8605 n++;
8606#endif
8607 addNode(list,
8608 (xmlNodePtr) attr);
8609 }
8610 } else {
8611 if ((attr->ns != NULL) &&
8612 (xmlStrEqual(URI,
8613 attr->ns->
8614 href))) {
8615#ifdef DEBUG_STEP
8616 n++;
8617#endif
8618 addNode(list,
8619 (xmlNodePtr) attr);
8620 }
8621 }
8622 }
8623 break;
8624 }
8625 case XML_NAMESPACE_DECL:
8626 if (cur->type == XML_NAMESPACE_DECL) {
8627 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008628
Daniel Veillardf06307e2001-07-03 10:35:50 +00008629 if ((ns->prefix != NULL) && (name != NULL)
8630 && (xmlStrEqual(ns->prefix, name))) {
8631#ifdef DEBUG_STEP
8632 n++;
8633#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008634 xmlXPathNodeSetAddNs(list,
8635 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008636 }
8637 }
8638 break;
8639 default:
8640 break;
8641 }
8642 break;
8643 break;
8644 }
8645 } while (cur != NULL);
8646
8647 /*
8648 * If there is some predicate filtering do it now
8649 */
8650 if (op->ch2 != -1) {
8651 xmlXPathObjectPtr obj2;
8652
8653 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8654 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8655 CHECK_TYPE0(XPATH_NODESET);
8656 obj2 = valuePop(ctxt);
8657 list = obj2->nodesetval;
8658 obj2->nodesetval = NULL;
8659 xmlXPathFreeObject(obj2);
8660 }
8661 if (ret == NULL) {
8662 ret = list;
8663 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00008664 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008665 xmlXPathFreeNodeSet(list);
8666 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008667 }
8668 ctxt->context->node = tmp;
8669#ifdef DEBUG_STEP
8670 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008671 "\nExamined %d nodes, found %d nodes at that step\n",
8672 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008673#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008674 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008675 if ((obj->boolval) && (obj->user != NULL)) {
8676 ctxt->value->boolval = 1;
8677 ctxt->value->user = obj->user;
8678 obj->user = NULL;
8679 obj->boolval = 0;
8680 }
8681 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008682 return(t);
8683}
8684
8685/**
8686 * xmlXPathNodeCollectAndTestNth:
8687 * @ctxt: the XPath Parser context
8688 * @op: the XPath precompiled step operation
8689 * @indx: the index to collect
8690 * @first: pointer to the first element in document order
8691 * @last: pointer to the last element in document order
8692 *
8693 * This is the function implementing a step: based on the current list
8694 * of nodes, it builds up a new list, looking at all nodes under that
8695 * axis and selecting them it also do the predicate filtering
8696 *
8697 * Pushes the new NodeSet resulting from the search.
8698 * Returns the number of node traversed
8699 */
8700static int
8701xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8702 xmlXPathStepOpPtr op, int indx,
8703 xmlNodePtr * first, xmlNodePtr * last)
8704{
8705 xmlXPathAxisVal axis = op->value;
8706 xmlXPathTestVal test = op->value2;
8707 xmlXPathTypeVal type = op->value3;
8708 const xmlChar *prefix = op->value4;
8709 const xmlChar *name = op->value5;
8710 const xmlChar *URI = NULL;
8711 int n = 0, t = 0;
8712
8713 int i;
8714 xmlNodeSetPtr list;
8715 xmlXPathTraversalFunction next = NULL;
8716 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8717 xmlNodePtr cur = NULL;
8718 xmlXPathObjectPtr obj;
8719 xmlNodeSetPtr nodelist;
8720 xmlNodePtr tmp;
8721
8722 CHECK_TYPE0(XPATH_NODESET);
8723 obj = valuePop(ctxt);
8724 addNode = xmlXPathNodeSetAdd;
8725 if (prefix != NULL) {
8726 URI = xmlXPathNsLookup(ctxt->context, prefix);
8727 if (URI == NULL)
8728 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8729 }
8730#ifdef DEBUG_STEP_NTH
8731 xmlGenericError(xmlGenericErrorContext, "new step : ");
8732 if (first != NULL) {
8733 if (*first != NULL)
8734 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8735 (*first)->name);
8736 else
8737 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8738 }
8739 if (last != NULL) {
8740 if (*last != NULL)
8741 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8742 (*last)->name);
8743 else
8744 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8745 }
8746#endif
8747 switch (axis) {
8748 case AXIS_ANCESTOR:
8749#ifdef DEBUG_STEP_NTH
8750 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8751#endif
8752 first = NULL;
8753 next = xmlXPathNextAncestor;
8754 break;
8755 case AXIS_ANCESTOR_OR_SELF:
8756#ifdef DEBUG_STEP_NTH
8757 xmlGenericError(xmlGenericErrorContext,
8758 "axis 'ancestors-or-self' ");
8759#endif
8760 first = NULL;
8761 next = xmlXPathNextAncestorOrSelf;
8762 break;
8763 case AXIS_ATTRIBUTE:
8764#ifdef DEBUG_STEP_NTH
8765 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8766#endif
8767 first = NULL;
8768 last = NULL;
8769 next = xmlXPathNextAttribute;
8770 break;
8771 case AXIS_CHILD:
8772#ifdef DEBUG_STEP_NTH
8773 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8774#endif
8775 last = NULL;
8776 next = xmlXPathNextChild;
8777 break;
8778 case AXIS_DESCENDANT:
8779#ifdef DEBUG_STEP_NTH
8780 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8781#endif
8782 last = NULL;
8783 next = xmlXPathNextDescendant;
8784 break;
8785 case AXIS_DESCENDANT_OR_SELF:
8786#ifdef DEBUG_STEP_NTH
8787 xmlGenericError(xmlGenericErrorContext,
8788 "axis 'descendant-or-self' ");
8789#endif
8790 last = NULL;
8791 next = xmlXPathNextDescendantOrSelf;
8792 break;
8793 case AXIS_FOLLOWING:
8794#ifdef DEBUG_STEP_NTH
8795 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8796#endif
8797 last = NULL;
8798 next = xmlXPathNextFollowing;
8799 break;
8800 case AXIS_FOLLOWING_SIBLING:
8801#ifdef DEBUG_STEP_NTH
8802 xmlGenericError(xmlGenericErrorContext,
8803 "axis 'following-siblings' ");
8804#endif
8805 last = NULL;
8806 next = xmlXPathNextFollowingSibling;
8807 break;
8808 case AXIS_NAMESPACE:
8809#ifdef DEBUG_STEP_NTH
8810 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8811#endif
8812 last = NULL;
8813 first = NULL;
8814 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8815 break;
8816 case AXIS_PARENT:
8817#ifdef DEBUG_STEP_NTH
8818 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8819#endif
8820 first = NULL;
8821 next = xmlXPathNextParent;
8822 break;
8823 case AXIS_PRECEDING:
8824#ifdef DEBUG_STEP_NTH
8825 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8826#endif
8827 first = NULL;
8828 next = xmlXPathNextPrecedingInternal;
8829 break;
8830 case AXIS_PRECEDING_SIBLING:
8831#ifdef DEBUG_STEP_NTH
8832 xmlGenericError(xmlGenericErrorContext,
8833 "axis 'preceding-sibling' ");
8834#endif
8835 first = NULL;
8836 next = xmlXPathNextPrecedingSibling;
8837 break;
8838 case AXIS_SELF:
8839#ifdef DEBUG_STEP_NTH
8840 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8841#endif
8842 first = NULL;
8843 last = NULL;
8844 next = xmlXPathNextSelf;
8845 break;
8846 }
8847 if (next == NULL)
8848 return(0);
8849
8850 nodelist = obj->nodesetval;
8851 if (nodelist == NULL) {
8852 xmlXPathFreeObject(obj);
8853 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8854 return(0);
8855 }
8856 addNode = xmlXPathNodeSetAddUnique;
8857#ifdef DEBUG_STEP_NTH
8858 xmlGenericError(xmlGenericErrorContext,
8859 " context contains %d nodes\n", nodelist->nodeNr);
8860 switch (test) {
8861 case NODE_TEST_NONE:
8862 xmlGenericError(xmlGenericErrorContext,
8863 " searching for none !!!\n");
8864 break;
8865 case NODE_TEST_TYPE:
8866 xmlGenericError(xmlGenericErrorContext,
8867 " searching for type %d\n", type);
8868 break;
8869 case NODE_TEST_PI:
8870 xmlGenericError(xmlGenericErrorContext,
8871 " searching for PI !!!\n");
8872 break;
8873 case NODE_TEST_ALL:
8874 xmlGenericError(xmlGenericErrorContext,
8875 " searching for *\n");
8876 break;
8877 case NODE_TEST_NS:
8878 xmlGenericError(xmlGenericErrorContext,
8879 " searching for namespace %s\n",
8880 prefix);
8881 break;
8882 case NODE_TEST_NAME:
8883 xmlGenericError(xmlGenericErrorContext,
8884 " searching for name %s\n", name);
8885 if (prefix != NULL)
8886 xmlGenericError(xmlGenericErrorContext,
8887 " with namespace %s\n", prefix);
8888 break;
8889 }
8890 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8891#endif
8892 /*
8893 * 2.3 Node Tests
8894 * - For the attribute axis, the principal node type is attribute.
8895 * - For the namespace axis, the principal node type is namespace.
8896 * - For other axes, the principal node type is element.
8897 *
8898 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008899 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008900 * select all element children of the context node
8901 */
8902 tmp = ctxt->context->node;
8903 list = xmlXPathNodeSetCreate(NULL);
8904 for (i = 0; i < nodelist->nodeNr; i++) {
8905 ctxt->context->node = nodelist->nodeTab[i];
8906
8907 cur = NULL;
8908 n = 0;
8909 do {
8910 cur = next(ctxt, cur);
8911 if (cur == NULL)
8912 break;
8913 if ((first != NULL) && (*first == cur))
8914 break;
8915 if (((t % 256) == 0) &&
8916 (first != NULL) && (*first != NULL) &&
8917 (xmlXPathCmpNodes(*first, cur) >= 0))
8918 break;
8919 if ((last != NULL) && (*last == cur))
8920 break;
8921 if (((t % 256) == 0) &&
8922 (last != NULL) && (*last != NULL) &&
8923 (xmlXPathCmpNodes(cur, *last) >= 0))
8924 break;
8925 t++;
8926 switch (test) {
8927 case NODE_TEST_NONE:
8928 ctxt->context->node = tmp;
8929 STRANGE return(0);
8930 case NODE_TEST_TYPE:
8931 if ((cur->type == type) ||
8932 ((type == NODE_TYPE_NODE) &&
8933 ((cur->type == XML_DOCUMENT_NODE) ||
8934 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8935 (cur->type == XML_ELEMENT_NODE) ||
8936 (cur->type == XML_PI_NODE) ||
8937 (cur->type == XML_COMMENT_NODE) ||
8938 (cur->type == XML_CDATA_SECTION_NODE) ||
8939 (cur->type == XML_TEXT_NODE)))) {
8940 n++;
8941 if (n == indx)
8942 addNode(list, cur);
8943 }
8944 break;
8945 case NODE_TEST_PI:
8946 if (cur->type == XML_PI_NODE) {
8947 if ((name != NULL) &&
8948 (!xmlStrEqual(name, cur->name)))
8949 break;
8950 n++;
8951 if (n == indx)
8952 addNode(list, cur);
8953 }
8954 break;
8955 case NODE_TEST_ALL:
8956 if (axis == AXIS_ATTRIBUTE) {
8957 if (cur->type == XML_ATTRIBUTE_NODE) {
8958 n++;
8959 if (n == indx)
8960 addNode(list, cur);
8961 }
8962 } else if (axis == AXIS_NAMESPACE) {
8963 if (cur->type == XML_NAMESPACE_DECL) {
8964 n++;
8965 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008966 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8967 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008968 }
8969 } else {
8970 if (cur->type == XML_ELEMENT_NODE) {
8971 if (prefix == NULL) {
8972 n++;
8973 if (n == indx)
8974 addNode(list, cur);
8975 } else if ((cur->ns != NULL) &&
8976 (xmlStrEqual(URI, cur->ns->href))) {
8977 n++;
8978 if (n == indx)
8979 addNode(list, cur);
8980 }
8981 }
8982 }
8983 break;
8984 case NODE_TEST_NS:{
8985 TODO;
8986 break;
8987 }
8988 case NODE_TEST_NAME:
8989 switch (cur->type) {
8990 case XML_ELEMENT_NODE:
8991 if (xmlStrEqual(name, cur->name)) {
8992 if (prefix == NULL) {
8993 if (cur->ns == NULL) {
8994 n++;
8995 if (n == indx)
8996 addNode(list, cur);
8997 }
8998 } else {
8999 if ((cur->ns != NULL) &&
9000 (xmlStrEqual(URI,
9001 cur->ns->href))) {
9002 n++;
9003 if (n == indx)
9004 addNode(list, cur);
9005 }
9006 }
9007 }
9008 break;
9009 case XML_ATTRIBUTE_NODE:{
9010 xmlAttrPtr attr = (xmlAttrPtr) cur;
9011
9012 if (xmlStrEqual(name, attr->name)) {
9013 if (prefix == NULL) {
9014 if ((attr->ns == NULL) ||
9015 (attr->ns->prefix == NULL)) {
9016 n++;
9017 if (n == indx)
9018 addNode(list, cur);
9019 }
9020 } else {
9021 if ((attr->ns != NULL) &&
9022 (xmlStrEqual(URI,
9023 attr->ns->
9024 href))) {
9025 n++;
9026 if (n == indx)
9027 addNode(list, cur);
9028 }
9029 }
9030 }
9031 break;
9032 }
9033 case XML_NAMESPACE_DECL:
9034 if (cur->type == XML_NAMESPACE_DECL) {
9035 xmlNsPtr ns = (xmlNsPtr) cur;
9036
9037 if ((ns->prefix != NULL) && (name != NULL)
9038 && (xmlStrEqual(ns->prefix, name))) {
9039 n++;
9040 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009041 xmlXPathNodeSetAddNs(list,
9042 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009043 }
9044 }
9045 break;
9046 default:
9047 break;
9048 }
9049 break;
9050 break;
9051 }
9052 } while (n < indx);
9053 }
9054 ctxt->context->node = tmp;
9055#ifdef DEBUG_STEP_NTH
9056 xmlGenericError(xmlGenericErrorContext,
9057 "\nExamined %d nodes, found %d nodes at that step\n",
9058 t, list->nodeNr);
9059#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009060 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009061 if ((obj->boolval) && (obj->user != NULL)) {
9062 ctxt->value->boolval = 1;
9063 ctxt->value->user = obj->user;
9064 obj->user = NULL;
9065 obj->boolval = 0;
9066 }
9067 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009068 return(t);
9069}
9070
9071/**
9072 * xmlXPathCompOpEvalFirst:
9073 * @ctxt: the XPath parser context with the compiled expression
9074 * @op: an XPath compiled operation
9075 * @first: the first elem found so far
9076 *
9077 * Evaluate the Precompiled XPath operation searching only the first
9078 * element in document order
9079 *
9080 * Returns the number of examined objects.
9081 */
9082static int
9083xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9084 xmlXPathStepOpPtr op, xmlNodePtr * first)
9085{
9086 int total = 0, cur;
9087 xmlXPathCompExprPtr comp;
9088 xmlXPathObjectPtr arg1, arg2;
9089
Daniel Veillard556c6682001-10-06 09:59:51 +00009090 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009091 comp = ctxt->comp;
9092 switch (op->op) {
9093 case XPATH_OP_END:
9094 return (0);
9095 case XPATH_OP_UNION:
9096 total =
9097 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9098 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009099 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 if ((ctxt->value != NULL)
9101 && (ctxt->value->type == XPATH_NODESET)
9102 && (ctxt->value->nodesetval != NULL)
9103 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9104 /*
9105 * limit tree traversing to first node in the result
9106 */
9107 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9108 *first = ctxt->value->nodesetval->nodeTab[0];
9109 }
9110 cur =
9111 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9112 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009113 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 CHECK_TYPE0(XPATH_NODESET);
9115 arg2 = valuePop(ctxt);
9116
9117 CHECK_TYPE0(XPATH_NODESET);
9118 arg1 = valuePop(ctxt);
9119
9120 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9121 arg2->nodesetval);
9122 valuePush(ctxt, arg1);
9123 xmlXPathFreeObject(arg2);
9124 /* optimizer */
9125 if (total > cur)
9126 xmlXPathCompSwap(op);
9127 return (total + cur);
9128 case XPATH_OP_ROOT:
9129 xmlXPathRoot(ctxt);
9130 return (0);
9131 case XPATH_OP_NODE:
9132 if (op->ch1 != -1)
9133 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009134 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009135 if (op->ch2 != -1)
9136 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009137 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9139 return (total);
9140 case XPATH_OP_RESET:
9141 if (op->ch1 != -1)
9142 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009143 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009144 if (op->ch2 != -1)
9145 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009146 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009147 ctxt->context->node = NULL;
9148 return (total);
9149 case XPATH_OP_COLLECT:{
9150 if (op->ch1 == -1)
9151 return (total);
9152
9153 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009154 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155
9156 /*
9157 * Optimization for [n] selection where n is a number
9158 */
9159 if ((op->ch2 != -1) &&
9160 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9161 (comp->steps[op->ch2].ch1 == -1) &&
9162 (comp->steps[op->ch2].ch2 != -1) &&
9163 (comp->steps[comp->steps[op->ch2].ch2].op ==
9164 XPATH_OP_VALUE)) {
9165 xmlXPathObjectPtr val;
9166
9167 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9168 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9169 int indx = (int) val->floatval;
9170
9171 if (val->floatval == (float) indx) {
9172 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9173 first, NULL);
9174 return (total);
9175 }
9176 }
9177 }
9178 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9179 return (total);
9180 }
9181 case XPATH_OP_VALUE:
9182 valuePush(ctxt,
9183 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9184 return (0);
9185 case XPATH_OP_SORT:
9186 if (op->ch1 != -1)
9187 total +=
9188 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9189 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009190 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009191 if ((ctxt->value != NULL)
9192 && (ctxt->value->type == XPATH_NODESET)
9193 && (ctxt->value->nodesetval != NULL))
9194 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9195 return (total);
9196 default:
9197 return (xmlXPathCompOpEval(ctxt, op));
9198 }
9199}
9200
9201/**
9202 * xmlXPathCompOpEvalLast:
9203 * @ctxt: the XPath parser context with the compiled expression
9204 * @op: an XPath compiled operation
9205 * @last: the last elem found so far
9206 *
9207 * Evaluate the Precompiled XPath operation searching only the last
9208 * element in document order
9209 *
9210 * Returns the number of node traversed
9211 */
9212static int
9213xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9214 xmlNodePtr * last)
9215{
9216 int total = 0, cur;
9217 xmlXPathCompExprPtr comp;
9218 xmlXPathObjectPtr arg1, arg2;
9219
Daniel Veillard556c6682001-10-06 09:59:51 +00009220 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009221 comp = ctxt->comp;
9222 switch (op->op) {
9223 case XPATH_OP_END:
9224 return (0);
9225 case XPATH_OP_UNION:
9226 total =
9227 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009228 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009229 if ((ctxt->value != NULL)
9230 && (ctxt->value->type == XPATH_NODESET)
9231 && (ctxt->value->nodesetval != NULL)
9232 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9233 /*
9234 * limit tree traversing to first node in the result
9235 */
9236 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9237 *last =
9238 ctxt->value->nodesetval->nodeTab[ctxt->value->
9239 nodesetval->nodeNr -
9240 1];
9241 }
9242 cur =
9243 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009244 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009245 if ((ctxt->value != NULL)
9246 && (ctxt->value->type == XPATH_NODESET)
9247 && (ctxt->value->nodesetval != NULL)
9248 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9249 }
9250 CHECK_TYPE0(XPATH_NODESET);
9251 arg2 = valuePop(ctxt);
9252
9253 CHECK_TYPE0(XPATH_NODESET);
9254 arg1 = valuePop(ctxt);
9255
9256 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9257 arg2->nodesetval);
9258 valuePush(ctxt, arg1);
9259 xmlXPathFreeObject(arg2);
9260 /* optimizer */
9261 if (total > cur)
9262 xmlXPathCompSwap(op);
9263 return (total + cur);
9264 case XPATH_OP_ROOT:
9265 xmlXPathRoot(ctxt);
9266 return (0);
9267 case XPATH_OP_NODE:
9268 if (op->ch1 != -1)
9269 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009270 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009271 if (op->ch2 != -1)
9272 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009273 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009274 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9275 return (total);
9276 case XPATH_OP_RESET:
9277 if (op->ch1 != -1)
9278 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009279 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009280 if (op->ch2 != -1)
9281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009282 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009283 ctxt->context->node = NULL;
9284 return (total);
9285 case XPATH_OP_COLLECT:{
9286 if (op->ch1 == -1)
9287 return (0);
9288
9289 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009290 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009291
9292 /*
9293 * Optimization for [n] selection where n is a number
9294 */
9295 if ((op->ch2 != -1) &&
9296 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9297 (comp->steps[op->ch2].ch1 == -1) &&
9298 (comp->steps[op->ch2].ch2 != -1) &&
9299 (comp->steps[comp->steps[op->ch2].ch2].op ==
9300 XPATH_OP_VALUE)) {
9301 xmlXPathObjectPtr val;
9302
9303 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9304 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9305 int indx = (int) val->floatval;
9306
9307 if (val->floatval == (float) indx) {
9308 total +=
9309 xmlXPathNodeCollectAndTestNth(ctxt, op,
9310 indx, NULL,
9311 last);
9312 return (total);
9313 }
9314 }
9315 }
9316 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9317 return (total);
9318 }
9319 case XPATH_OP_VALUE:
9320 valuePush(ctxt,
9321 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9322 return (0);
9323 case XPATH_OP_SORT:
9324 if (op->ch1 != -1)
9325 total +=
9326 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9327 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009328 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009329 if ((ctxt->value != NULL)
9330 && (ctxt->value->type == XPATH_NODESET)
9331 && (ctxt->value->nodesetval != NULL))
9332 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9333 return (total);
9334 default:
9335 return (xmlXPathCompOpEval(ctxt, op));
9336 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009337}
9338
Owen Taylor3473f882001-02-23 17:55:21 +00009339/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009340 * xmlXPathCompOpEval:
9341 * @ctxt: the XPath parser context with the compiled expression
9342 * @op: an XPath compiled operation
9343 *
9344 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009345 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009346 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009347static int
9348xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9349{
9350 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009351 int equal, ret;
9352 xmlXPathCompExprPtr comp;
9353 xmlXPathObjectPtr arg1, arg2;
9354
Daniel Veillard556c6682001-10-06 09:59:51 +00009355 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009356 comp = ctxt->comp;
9357 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009358 case XPATH_OP_END:
9359 return (0);
9360 case XPATH_OP_AND:
9361 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009362 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009363 xmlXPathBooleanFunction(ctxt, 1);
9364 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9365 return (total);
9366 arg2 = valuePop(ctxt);
9367 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009368 if (ctxt->error) {
9369 xmlXPathFreeObject(arg2);
9370 return(0);
9371 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009372 xmlXPathBooleanFunction(ctxt, 1);
9373 arg1 = valuePop(ctxt);
9374 arg1->boolval &= arg2->boolval;
9375 valuePush(ctxt, arg1);
9376 xmlXPathFreeObject(arg2);
9377 return (total);
9378 case XPATH_OP_OR:
9379 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009380 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009381 xmlXPathBooleanFunction(ctxt, 1);
9382 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9383 return (total);
9384 arg2 = valuePop(ctxt);
9385 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009386 if (ctxt->error) {
9387 xmlXPathFreeObject(arg2);
9388 return(0);
9389 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009390 xmlXPathBooleanFunction(ctxt, 1);
9391 arg1 = valuePop(ctxt);
9392 arg1->boolval |= arg2->boolval;
9393 valuePush(ctxt, arg1);
9394 xmlXPathFreeObject(arg2);
9395 return (total);
9396 case XPATH_OP_EQUAL:
9397 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009398 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009399 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009400 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009401 equal = xmlXPathEqualValues(ctxt);
9402 if (op->value)
9403 valuePush(ctxt, xmlXPathNewBoolean(equal));
9404 else
9405 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9406 return (total);
9407 case XPATH_OP_CMP:
9408 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009409 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009410 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009411 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009412 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9413 valuePush(ctxt, xmlXPathNewBoolean(ret));
9414 return (total);
9415 case XPATH_OP_PLUS:
9416 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009417 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009418 if (op->ch2 != -1)
9419 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009420 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009421 if (op->value == 0)
9422 xmlXPathSubValues(ctxt);
9423 else if (op->value == 1)
9424 xmlXPathAddValues(ctxt);
9425 else if (op->value == 2)
9426 xmlXPathValueFlipSign(ctxt);
9427 else if (op->value == 3) {
9428 CAST_TO_NUMBER;
9429 CHECK_TYPE0(XPATH_NUMBER);
9430 }
9431 return (total);
9432 case XPATH_OP_MULT:
9433 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009434 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009435 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009436 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009437 if (op->value == 0)
9438 xmlXPathMultValues(ctxt);
9439 else if (op->value == 1)
9440 xmlXPathDivValues(ctxt);
9441 else if (op->value == 2)
9442 xmlXPathModValues(ctxt);
9443 return (total);
9444 case XPATH_OP_UNION:
9445 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009446 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009447 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009448 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009449 CHECK_TYPE0(XPATH_NODESET);
9450 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009451
Daniel Veillardf06307e2001-07-03 10:35:50 +00009452 CHECK_TYPE0(XPATH_NODESET);
9453 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009454
Daniel Veillardf06307e2001-07-03 10:35:50 +00009455 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9456 arg2->nodesetval);
9457 valuePush(ctxt, arg1);
9458 xmlXPathFreeObject(arg2);
9459 return (total);
9460 case XPATH_OP_ROOT:
9461 xmlXPathRoot(ctxt);
9462 return (total);
9463 case XPATH_OP_NODE:
9464 if (op->ch1 != -1)
9465 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009466 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009467 if (op->ch2 != -1)
9468 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009469 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009470 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9471 return (total);
9472 case XPATH_OP_RESET:
9473 if (op->ch1 != -1)
9474 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009475 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009476 if (op->ch2 != -1)
9477 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009478 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009479 ctxt->context->node = NULL;
9480 return (total);
9481 case XPATH_OP_COLLECT:{
9482 if (op->ch1 == -1)
9483 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009484
Daniel Veillardf06307e2001-07-03 10:35:50 +00009485 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009486 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009487
Daniel Veillardf06307e2001-07-03 10:35:50 +00009488 /*
9489 * Optimization for [n] selection where n is a number
9490 */
9491 if ((op->ch2 != -1) &&
9492 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9493 (comp->steps[op->ch2].ch1 == -1) &&
9494 (comp->steps[op->ch2].ch2 != -1) &&
9495 (comp->steps[comp->steps[op->ch2].ch2].op ==
9496 XPATH_OP_VALUE)) {
9497 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009498
Daniel Veillardf06307e2001-07-03 10:35:50 +00009499 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9500 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9501 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009502
Daniel Veillardf06307e2001-07-03 10:35:50 +00009503 if (val->floatval == (float) indx) {
9504 total +=
9505 xmlXPathNodeCollectAndTestNth(ctxt, op,
9506 indx, NULL,
9507 NULL);
9508 return (total);
9509 }
9510 }
9511 }
9512 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9513 return (total);
9514 }
9515 case XPATH_OP_VALUE:
9516 valuePush(ctxt,
9517 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9518 return (total);
9519 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009520 xmlXPathObjectPtr val;
9521
Daniel Veillardf06307e2001-07-03 10:35:50 +00009522 if (op->ch1 != -1)
9523 total +=
9524 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009525 if (op->value5 == NULL) {
9526 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9527 if (val == NULL) {
9528 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9529 return(0);
9530 }
9531 valuePush(ctxt, val);
9532 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009533 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009534
Daniel Veillardf06307e2001-07-03 10:35:50 +00009535 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9536 if (URI == NULL) {
9537 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009538 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009539 op->value4, op->value5);
9540 return (total);
9541 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009542 val = xmlXPathVariableLookupNS(ctxt->context,
9543 op->value4, URI);
9544 if (val == NULL) {
9545 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9546 return(0);
9547 }
9548 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009549 }
9550 return (total);
9551 }
9552 case XPATH_OP_FUNCTION:{
9553 xmlXPathFunction func;
9554 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009555 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009556
9557 if (op->ch1 != -1)
9558 total +=
9559 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009560 if (ctxt->valueNr < op->value) {
9561 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009562 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009563 ctxt->error = XPATH_INVALID_OPERAND;
9564 return (total);
9565 }
9566 for (i = 0; i < op->value; i++)
9567 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9568 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009569 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009570 ctxt->error = XPATH_INVALID_OPERAND;
9571 return (total);
9572 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009573 if (op->cache != NULL)
9574 func = (xmlXPathFunction) op->cache;
9575 else {
9576 const xmlChar *URI = NULL;
9577
9578 if (op->value5 == NULL)
9579 func =
9580 xmlXPathFunctionLookup(ctxt->context,
9581 op->value4);
9582 else {
9583 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9584 if (URI == NULL) {
9585 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009586 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009587 op->value4, op->value5);
9588 return (total);
9589 }
9590 func = xmlXPathFunctionLookupNS(ctxt->context,
9591 op->value4, URI);
9592 }
9593 if (func == NULL) {
9594 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009595 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009596 op->value4);
9597 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009598 }
9599 op->cache = (void *) func;
9600 op->cacheURI = (void *) URI;
9601 }
9602 oldFunc = ctxt->context->function;
9603 oldFuncURI = ctxt->context->functionURI;
9604 ctxt->context->function = op->value4;
9605 ctxt->context->functionURI = op->cacheURI;
9606 func(ctxt, op->value);
9607 ctxt->context->function = oldFunc;
9608 ctxt->context->functionURI = oldFuncURI;
9609 return (total);
9610 }
9611 case XPATH_OP_ARG:
9612 if (op->ch1 != -1)
9613 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009614 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009615 if (op->ch2 != -1)
9616 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009617 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009618 return (total);
9619 case XPATH_OP_PREDICATE:
9620 case XPATH_OP_FILTER:{
9621 xmlXPathObjectPtr res;
9622 xmlXPathObjectPtr obj, tmp;
9623 xmlNodeSetPtr newset = NULL;
9624 xmlNodeSetPtr oldset;
9625 xmlNodePtr oldnode;
9626 int i;
9627
9628 /*
9629 * Optimization for ()[1] selection i.e. the first elem
9630 */
9631 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9632 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9633 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9634 xmlXPathObjectPtr val;
9635
9636 val = comp->steps[op->ch2].value4;
9637 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9638 (val->floatval == 1.0)) {
9639 xmlNodePtr first = NULL;
9640
9641 total +=
9642 xmlXPathCompOpEvalFirst(ctxt,
9643 &comp->steps[op->ch1],
9644 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009645 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009646 /*
9647 * The nodeset should be in document order,
9648 * Keep only the first value
9649 */
9650 if ((ctxt->value != NULL) &&
9651 (ctxt->value->type == XPATH_NODESET) &&
9652 (ctxt->value->nodesetval != NULL) &&
9653 (ctxt->value->nodesetval->nodeNr > 1))
9654 ctxt->value->nodesetval->nodeNr = 1;
9655 return (total);
9656 }
9657 }
9658 /*
9659 * Optimization for ()[last()] selection i.e. the last elem
9660 */
9661 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9662 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9663 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9664 int f = comp->steps[op->ch2].ch1;
9665
9666 if ((f != -1) &&
9667 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9668 (comp->steps[f].value5 == NULL) &&
9669 (comp->steps[f].value == 0) &&
9670 (comp->steps[f].value4 != NULL) &&
9671 (xmlStrEqual
9672 (comp->steps[f].value4, BAD_CAST "last"))) {
9673 xmlNodePtr last = NULL;
9674
9675 total +=
9676 xmlXPathCompOpEvalLast(ctxt,
9677 &comp->steps[op->ch1],
9678 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009679 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009680 /*
9681 * The nodeset should be in document order,
9682 * Keep only the last value
9683 */
9684 if ((ctxt->value != NULL) &&
9685 (ctxt->value->type == XPATH_NODESET) &&
9686 (ctxt->value->nodesetval != NULL) &&
9687 (ctxt->value->nodesetval->nodeTab != NULL) &&
9688 (ctxt->value->nodesetval->nodeNr > 1)) {
9689 ctxt->value->nodesetval->nodeTab[0] =
9690 ctxt->value->nodesetval->nodeTab[ctxt->
9691 value->
9692 nodesetval->
9693 nodeNr -
9694 1];
9695 ctxt->value->nodesetval->nodeNr = 1;
9696 }
9697 return (total);
9698 }
9699 }
9700
9701 if (op->ch1 != -1)
9702 total +=
9703 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009704 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009705 if (op->ch2 == -1)
9706 return (total);
9707 if (ctxt->value == NULL)
9708 return (total);
9709
9710 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009711
9712#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009713 /*
9714 * Hum are we filtering the result of an XPointer expression
9715 */
9716 if (ctxt->value->type == XPATH_LOCATIONSET) {
9717 xmlLocationSetPtr newlocset = NULL;
9718 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009719
Daniel Veillardf06307e2001-07-03 10:35:50 +00009720 /*
9721 * Extract the old locset, and then evaluate the result of the
9722 * expression for all the element in the locset. use it to grow
9723 * up a new locset.
9724 */
9725 CHECK_TYPE0(XPATH_LOCATIONSET);
9726 obj = valuePop(ctxt);
9727 oldlocset = obj->user;
9728 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009729
Daniel Veillardf06307e2001-07-03 10:35:50 +00009730 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9731 ctxt->context->contextSize = 0;
9732 ctxt->context->proximityPosition = 0;
9733 if (op->ch2 != -1)
9734 total +=
9735 xmlXPathCompOpEval(ctxt,
9736 &comp->steps[op->ch2]);
9737 res = valuePop(ctxt);
9738 if (res != NULL)
9739 xmlXPathFreeObject(res);
9740 valuePush(ctxt, obj);
9741 CHECK_ERROR0;
9742 return (total);
9743 }
9744 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009745
Daniel Veillardf06307e2001-07-03 10:35:50 +00009746 for (i = 0; i < oldlocset->locNr; i++) {
9747 /*
9748 * Run the evaluation with a node list made of a
9749 * single item in the nodelocset.
9750 */
9751 ctxt->context->node = oldlocset->locTab[i]->user;
9752 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9753 valuePush(ctxt, tmp);
9754 ctxt->context->contextSize = oldlocset->locNr;
9755 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009756
Daniel Veillardf06307e2001-07-03 10:35:50 +00009757 if (op->ch2 != -1)
9758 total +=
9759 xmlXPathCompOpEval(ctxt,
9760 &comp->steps[op->ch2]);
9761 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009762
Daniel Veillardf06307e2001-07-03 10:35:50 +00009763 /*
9764 * The result of the evaluation need to be tested to
9765 * decided whether the filter succeeded or not
9766 */
9767 res = valuePop(ctxt);
9768 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9769 xmlXPtrLocationSetAdd(newlocset,
9770 xmlXPathObjectCopy
9771 (oldlocset->locTab[i]));
9772 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009773
Daniel Veillardf06307e2001-07-03 10:35:50 +00009774 /*
9775 * Cleanup
9776 */
9777 if (res != NULL)
9778 xmlXPathFreeObject(res);
9779 if (ctxt->value == tmp) {
9780 res = valuePop(ctxt);
9781 xmlXPathFreeObject(res);
9782 }
9783
9784 ctxt->context->node = NULL;
9785 }
9786
9787 /*
9788 * The result is used as the new evaluation locset.
9789 */
9790 xmlXPathFreeObject(obj);
9791 ctxt->context->node = NULL;
9792 ctxt->context->contextSize = -1;
9793 ctxt->context->proximityPosition = -1;
9794 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9795 ctxt->context->node = oldnode;
9796 return (total);
9797 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009798#endif /* LIBXML_XPTR_ENABLED */
9799
Daniel Veillardf06307e2001-07-03 10:35:50 +00009800 /*
9801 * Extract the old set, and then evaluate the result of the
9802 * expression for all the element in the set. use it to grow
9803 * up a new set.
9804 */
9805 CHECK_TYPE0(XPATH_NODESET);
9806 obj = valuePop(ctxt);
9807 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009808
Daniel Veillardf06307e2001-07-03 10:35:50 +00009809 oldnode = ctxt->context->node;
9810 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009811
Daniel Veillardf06307e2001-07-03 10:35:50 +00009812 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9813 ctxt->context->contextSize = 0;
9814 ctxt->context->proximityPosition = 0;
9815 if (op->ch2 != -1)
9816 total +=
9817 xmlXPathCompOpEval(ctxt,
9818 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009819 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009820 res = valuePop(ctxt);
9821 if (res != NULL)
9822 xmlXPathFreeObject(res);
9823 valuePush(ctxt, obj);
9824 ctxt->context->node = oldnode;
9825 CHECK_ERROR0;
9826 } else {
9827 /*
9828 * Initialize the new set.
9829 */
9830 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009831
Daniel Veillardf06307e2001-07-03 10:35:50 +00009832 for (i = 0; i < oldset->nodeNr; i++) {
9833 /*
9834 * Run the evaluation with a node list made of
9835 * a single item in the nodeset.
9836 */
9837 ctxt->context->node = oldset->nodeTab[i];
9838 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9839 valuePush(ctxt, tmp);
9840 ctxt->context->contextSize = oldset->nodeNr;
9841 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009842
Daniel Veillardf06307e2001-07-03 10:35:50 +00009843 if (op->ch2 != -1)
9844 total +=
9845 xmlXPathCompOpEval(ctxt,
9846 &comp->steps[op->ch2]);
9847 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009848
Daniel Veillardf06307e2001-07-03 10:35:50 +00009849 /*
9850 * The result of the evaluation need to be tested to
9851 * decided whether the filter succeeded or not
9852 */
9853 res = valuePop(ctxt);
9854 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9855 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9856 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009857
Daniel Veillardf06307e2001-07-03 10:35:50 +00009858 /*
9859 * Cleanup
9860 */
9861 if (res != NULL)
9862 xmlXPathFreeObject(res);
9863 if (ctxt->value == tmp) {
9864 res = valuePop(ctxt);
9865 xmlXPathFreeObject(res);
9866 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009867
Daniel Veillardf06307e2001-07-03 10:35:50 +00009868 ctxt->context->node = NULL;
9869 }
9870
9871 /*
9872 * The result is used as the new evaluation set.
9873 */
9874 xmlXPathFreeObject(obj);
9875 ctxt->context->node = NULL;
9876 ctxt->context->contextSize = -1;
9877 ctxt->context->proximityPosition = -1;
9878 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9879 }
9880 ctxt->context->node = oldnode;
9881 return (total);
9882 }
9883 case XPATH_OP_SORT:
9884 if (op->ch1 != -1)
9885 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009886 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009887 if ((ctxt->value != NULL) &&
9888 (ctxt->value->type == XPATH_NODESET) &&
9889 (ctxt->value->nodesetval != NULL))
9890 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9891 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009892#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009893 case XPATH_OP_RANGETO:{
9894 xmlXPathObjectPtr range;
9895 xmlXPathObjectPtr res, obj;
9896 xmlXPathObjectPtr tmp;
9897 xmlLocationSetPtr newset = NULL;
9898 xmlNodeSetPtr oldset;
9899 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009900
Daniel Veillardf06307e2001-07-03 10:35:50 +00009901 if (op->ch1 != -1)
9902 total +=
9903 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9904 if (op->ch2 == -1)
9905 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009906
Daniel Veillardf06307e2001-07-03 10:35:50 +00009907 CHECK_TYPE0(XPATH_NODESET);
9908 obj = valuePop(ctxt);
9909 oldset = obj->nodesetval;
9910 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009911
Daniel Veillardf06307e2001-07-03 10:35:50 +00009912 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009913
Daniel Veillardf06307e2001-07-03 10:35:50 +00009914 if (oldset != NULL) {
9915 for (i = 0; i < oldset->nodeNr; i++) {
9916 /*
9917 * Run the evaluation with a node list made of a single item
9918 * in the nodeset.
9919 */
9920 ctxt->context->node = oldset->nodeTab[i];
9921 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9922 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009923
Daniel Veillardf06307e2001-07-03 10:35:50 +00009924 if (op->ch2 != -1)
9925 total +=
9926 xmlXPathCompOpEval(ctxt,
9927 &comp->steps[op->ch2]);
9928 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009929
Daniel Veillardf06307e2001-07-03 10:35:50 +00009930 /*
9931 * The result of the evaluation need to be tested to
9932 * decided whether the filter succeeded or not
9933 */
9934 res = valuePop(ctxt);
9935 range =
9936 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9937 res);
9938 if (range != NULL) {
9939 xmlXPtrLocationSetAdd(newset, range);
9940 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009941
Daniel Veillardf06307e2001-07-03 10:35:50 +00009942 /*
9943 * Cleanup
9944 */
9945 if (res != NULL)
9946 xmlXPathFreeObject(res);
9947 if (ctxt->value == tmp) {
9948 res = valuePop(ctxt);
9949 xmlXPathFreeObject(res);
9950 }
9951
9952 ctxt->context->node = NULL;
9953 }
9954 }
9955
9956 /*
9957 * The result is used as the new evaluation set.
9958 */
9959 xmlXPathFreeObject(obj);
9960 ctxt->context->node = NULL;
9961 ctxt->context->contextSize = -1;
9962 ctxt->context->proximityPosition = -1;
9963 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9964 return (total);
9965 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009966#endif /* LIBXML_XPTR_ENABLED */
9967 }
9968 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009969 "XPath: unknown precompiled operation %d\n", op->op);
9970 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009971}
9972
9973/**
9974 * xmlXPathRunEval:
9975 * @ctxt: the XPath parser context with the compiled expression
9976 *
9977 * Evaluate the Precompiled XPath expression in the given context.
9978 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009979static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009980xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9981 xmlXPathCompExprPtr comp;
9982
9983 if ((ctxt == NULL) || (ctxt->comp == NULL))
9984 return;
9985
9986 if (ctxt->valueTab == NULL) {
9987 /* Allocate the value stack */
9988 ctxt->valueTab = (xmlXPathObjectPtr *)
9989 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9990 if (ctxt->valueTab == NULL) {
9991 xmlFree(ctxt);
9992 xmlGenericError(xmlGenericErrorContext,
9993 "xmlXPathRunEval: out of memory\n");
9994 return;
9995 }
9996 ctxt->valueNr = 0;
9997 ctxt->valueMax = 10;
9998 ctxt->value = NULL;
9999 }
10000 comp = ctxt->comp;
10001 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10002}
10003
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010004/************************************************************************
10005 * *
10006 * Public interfaces *
10007 * *
10008 ************************************************************************/
10009
10010/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010011 * xmlXPathEvalPredicate:
10012 * @ctxt: the XPath context
10013 * @res: the Predicate Expression evaluation result
10014 *
10015 * Evaluate a predicate result for the current node.
10016 * A PredicateExpr is evaluated by evaluating the Expr and converting
10017 * the result to a boolean. If the result is a number, the result will
10018 * be converted to true if the number is equal to the position of the
10019 * context node in the context node list (as returned by the position
10020 * function) and will be converted to false otherwise; if the result
10021 * is not a number, then the result will be converted as if by a call
10022 * to the boolean function.
10023 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010024 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010025 */
10026int
10027xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10028 if (res == NULL) return(0);
10029 switch (res->type) {
10030 case XPATH_BOOLEAN:
10031 return(res->boolval);
10032 case XPATH_NUMBER:
10033 return(res->floatval == ctxt->proximityPosition);
10034 case XPATH_NODESET:
10035 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010036 if (res->nodesetval == NULL)
10037 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010038 return(res->nodesetval->nodeNr != 0);
10039 case XPATH_STRING:
10040 return((res->stringval != NULL) &&
10041 (xmlStrlen(res->stringval) != 0));
10042 default:
10043 STRANGE
10044 }
10045 return(0);
10046}
10047
10048/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010049 * xmlXPathEvaluatePredicateResult:
10050 * @ctxt: the XPath Parser context
10051 * @res: the Predicate Expression evaluation result
10052 *
10053 * Evaluate a predicate result for the current node.
10054 * A PredicateExpr is evaluated by evaluating the Expr and converting
10055 * the result to a boolean. If the result is a number, the result will
10056 * be converted to true if the number is equal to the position of the
10057 * context node in the context node list (as returned by the position
10058 * function) and will be converted to false otherwise; if the result
10059 * is not a number, then the result will be converted as if by a call
10060 * to the boolean function.
10061 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010062 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010063 */
10064int
10065xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10066 xmlXPathObjectPtr res) {
10067 if (res == NULL) return(0);
10068 switch (res->type) {
10069 case XPATH_BOOLEAN:
10070 return(res->boolval);
10071 case XPATH_NUMBER:
10072 return(res->floatval == ctxt->context->proximityPosition);
10073 case XPATH_NODESET:
10074 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010075 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010076 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010077 return(res->nodesetval->nodeNr != 0);
10078 case XPATH_STRING:
10079 return((res->stringval != NULL) &&
10080 (xmlStrlen(res->stringval) != 0));
10081 default:
10082 STRANGE
10083 }
10084 return(0);
10085}
10086
10087/**
10088 * xmlXPathCompile:
10089 * @str: the XPath expression
10090 *
10091 * Compile an XPath expression
10092 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010093 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010094 * the caller has to free the object.
10095 */
10096xmlXPathCompExprPtr
10097xmlXPathCompile(const xmlChar *str) {
10098 xmlXPathParserContextPtr ctxt;
10099 xmlXPathCompExprPtr comp;
10100
10101 xmlXPathInit();
10102
10103 ctxt = xmlXPathNewParserContext(str, NULL);
10104 xmlXPathCompileExpr(ctxt);
10105
Daniel Veillard40af6492001-04-22 08:50:55 +000010106 if (*ctxt->cur != 0) {
10107 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10108 comp = NULL;
10109 } else {
10110 comp = ctxt->comp;
10111 ctxt->comp = NULL;
10112 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010113 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010114#ifdef DEBUG_EVAL_COUNTS
10115 if (comp != NULL) {
10116 comp->string = xmlStrdup(str);
10117 comp->nb = 0;
10118 }
10119#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010120 return(comp);
10121}
10122
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010123/**
10124 * xmlXPathCompiledEval:
10125 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010126 * @ctx: the XPath context
10127 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010128 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010129 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010130 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010131 * the caller has to free the object.
10132 */
10133xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010134xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010135 xmlXPathParserContextPtr ctxt;
10136 xmlXPathObjectPtr res, tmp, init = NULL;
10137 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010138#ifndef LIBXML_THREAD_ENABLED
10139 static int reentance = 0;
10140#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010141
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010142 if ((comp == NULL) || (ctx == NULL))
10143 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010144 xmlXPathInit();
10145
10146 CHECK_CONTEXT(ctx)
10147
Daniel Veillard81463942001-10-16 12:34:39 +000010148#ifndef LIBXML_THREAD_ENABLED
10149 reentance++;
10150 if (reentance > 1)
10151 xmlXPathDisableOptimizer = 1;
10152#endif
10153
Daniel Veillardf06307e2001-07-03 10:35:50 +000010154#ifdef DEBUG_EVAL_COUNTS
10155 comp->nb++;
10156 if ((comp->string != NULL) && (comp->nb > 100)) {
10157 fprintf(stderr, "100 x %s\n", comp->string);
10158 comp->nb = 0;
10159 }
10160#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010161 ctxt = xmlXPathCompParserContext(comp, ctx);
10162 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010163
10164 if (ctxt->value == NULL) {
10165 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010166 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010167 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010168 } else {
10169 res = valuePop(ctxt);
10170 }
10171
Daniel Veillardf06307e2001-07-03 10:35:50 +000010172
Owen Taylor3473f882001-02-23 17:55:21 +000010173 do {
10174 tmp = valuePop(ctxt);
10175 if (tmp != NULL) {
10176 if (tmp != init)
10177 stack++;
10178 xmlXPathFreeObject(tmp);
10179 }
10180 } while (tmp != NULL);
10181 if ((stack != 0) && (res != NULL)) {
10182 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010183 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010184 stack);
10185 }
10186 if (ctxt->error != XPATH_EXPRESSION_OK) {
10187 xmlXPathFreeObject(res);
10188 res = NULL;
10189 }
10190
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010191
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010192 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010193 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010194#ifndef LIBXML_THREAD_ENABLED
10195 reentance--;
10196#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010197 return(res);
10198}
10199
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010200/**
10201 * xmlXPathEvalExpr:
10202 * @ctxt: the XPath Parser context
10203 *
10204 * Parse and evaluate an XPath expression in the given context,
10205 * then push the result on the context stack
10206 */
10207void
10208xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10209 xmlXPathCompileExpr(ctxt);
10210 xmlXPathRunEval(ctxt);
10211}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010212
10213/**
10214 * xmlXPathEval:
10215 * @str: the XPath expression
10216 * @ctx: the XPath context
10217 *
10218 * Evaluate the XPath Location Path in the given context.
10219 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010220 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010221 * the caller has to free the object.
10222 */
10223xmlXPathObjectPtr
10224xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10225 xmlXPathParserContextPtr ctxt;
10226 xmlXPathObjectPtr res, tmp, init = NULL;
10227 int stack = 0;
10228
10229 xmlXPathInit();
10230
10231 CHECK_CONTEXT(ctx)
10232
10233 ctxt = xmlXPathNewParserContext(str, ctx);
10234 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010235
10236 if (ctxt->value == NULL) {
10237 xmlGenericError(xmlGenericErrorContext,
10238 "xmlXPathEval: evaluation failed\n");
10239 res = NULL;
10240 } else if (*ctxt->cur != 0) {
10241 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10242 res = NULL;
10243 } else {
10244 res = valuePop(ctxt);
10245 }
10246
10247 do {
10248 tmp = valuePop(ctxt);
10249 if (tmp != NULL) {
10250 if (tmp != init)
10251 stack++;
10252 xmlXPathFreeObject(tmp);
10253 }
10254 } while (tmp != NULL);
10255 if ((stack != 0) && (res != NULL)) {
10256 xmlGenericError(xmlGenericErrorContext,
10257 "xmlXPathEval: %d object left on the stack\n",
10258 stack);
10259 }
10260 if (ctxt->error != XPATH_EXPRESSION_OK) {
10261 xmlXPathFreeObject(res);
10262 res = NULL;
10263 }
10264
Owen Taylor3473f882001-02-23 17:55:21 +000010265 xmlXPathFreeParserContext(ctxt);
10266 return(res);
10267}
10268
10269/**
10270 * xmlXPathEvalExpression:
10271 * @str: the XPath expression
10272 * @ctxt: the XPath context
10273 *
10274 * Evaluate the XPath expression in the given context.
10275 *
10276 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10277 * the caller has to free the object.
10278 */
10279xmlXPathObjectPtr
10280xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10281 xmlXPathParserContextPtr pctxt;
10282 xmlXPathObjectPtr res, tmp;
10283 int stack = 0;
10284
10285 xmlXPathInit();
10286
10287 CHECK_CONTEXT(ctxt)
10288
10289 pctxt = xmlXPathNewParserContext(str, ctxt);
10290 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010291
10292 if (*pctxt->cur != 0) {
10293 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10294 res = NULL;
10295 } else {
10296 res = valuePop(pctxt);
10297 }
10298 do {
10299 tmp = valuePop(pctxt);
10300 if (tmp != NULL) {
10301 xmlXPathFreeObject(tmp);
10302 stack++;
10303 }
10304 } while (tmp != NULL);
10305 if ((stack != 0) && (res != NULL)) {
10306 xmlGenericError(xmlGenericErrorContext,
10307 "xmlXPathEvalExpression: %d object left on the stack\n",
10308 stack);
10309 }
10310 xmlXPathFreeParserContext(pctxt);
10311 return(res);
10312}
10313
10314/**
10315 * xmlXPathRegisterAllFunctions:
10316 * @ctxt: the XPath context
10317 *
10318 * Registers all default XPath functions in this context
10319 */
10320void
10321xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10322{
10323 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10324 xmlXPathBooleanFunction);
10325 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10326 xmlXPathCeilingFunction);
10327 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10328 xmlXPathCountFunction);
10329 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10330 xmlXPathConcatFunction);
10331 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10332 xmlXPathContainsFunction);
10333 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10334 xmlXPathIdFunction);
10335 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10336 xmlXPathFalseFunction);
10337 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10338 xmlXPathFloorFunction);
10339 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10340 xmlXPathLastFunction);
10341 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10342 xmlXPathLangFunction);
10343 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10344 xmlXPathLocalNameFunction);
10345 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10346 xmlXPathNotFunction);
10347 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10348 xmlXPathNameFunction);
10349 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10350 xmlXPathNamespaceURIFunction);
10351 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10352 xmlXPathNormalizeFunction);
10353 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10354 xmlXPathNumberFunction);
10355 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10356 xmlXPathPositionFunction);
10357 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10358 xmlXPathRoundFunction);
10359 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10360 xmlXPathStringFunction);
10361 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10362 xmlXPathStringLengthFunction);
10363 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10364 xmlXPathStartsWithFunction);
10365 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10366 xmlXPathSubstringFunction);
10367 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10368 xmlXPathSubstringBeforeFunction);
10369 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10370 xmlXPathSubstringAfterFunction);
10371 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10372 xmlXPathSumFunction);
10373 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10374 xmlXPathTrueFunction);
10375 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10376 xmlXPathTranslateFunction);
10377}
10378
10379#endif /* LIBXML_XPATH_ENABLED */