blob: 96b39168db931594c9084a980273af97a8e12d4f [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/**
1776 * xmlXPathNodeSetDel:
1777 * @cur: the initial node set
1778 * @val: an xmlNodePtr
1779 *
1780 * Removes an xmlNodePtr from an existing NodeSet
1781 */
1782void
1783xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1784 int i;
1785
1786 if (cur == NULL) return;
1787 if (val == NULL) return;
1788
1789 /*
1790 * check against doublons
1791 */
1792 for (i = 0;i < cur->nodeNr;i++)
1793 if (cur->nodeTab[i] == val) break;
1794
1795 if (i >= cur->nodeNr) {
1796#ifdef DEBUG
1797 xmlGenericError(xmlGenericErrorContext,
1798 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1799 val->name);
1800#endif
1801 return;
1802 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001803 if ((cur->nodeTab[i] != NULL) &&
1804 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1805 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001806 cur->nodeNr--;
1807 for (;i < cur->nodeNr;i++)
1808 cur->nodeTab[i] = cur->nodeTab[i + 1];
1809 cur->nodeTab[cur->nodeNr] = NULL;
1810}
1811
1812/**
1813 * xmlXPathNodeSetRemove:
1814 * @cur: the initial node set
1815 * @val: the index to remove
1816 *
1817 * Removes an entry from an existing NodeSet list.
1818 */
1819void
1820xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1821 if (cur == NULL) return;
1822 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001823 if ((cur->nodeTab[val] != NULL) &&
1824 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1825 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001826 cur->nodeNr--;
1827 for (;val < cur->nodeNr;val++)
1828 cur->nodeTab[val] = cur->nodeTab[val + 1];
1829 cur->nodeTab[cur->nodeNr] = NULL;
1830}
1831
1832/**
1833 * xmlXPathFreeNodeSet:
1834 * @obj: the xmlNodeSetPtr to free
1835 *
1836 * Free the NodeSet compound (not the actual nodes !).
1837 */
1838void
1839xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1840 if (obj == NULL) return;
1841 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001842 int i;
1843
1844 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1845 for (i = 0;i < obj->nodeNr;i++)
1846 if ((obj->nodeTab[i] != NULL) &&
1847 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1848 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001849 xmlFree(obj->nodeTab);
1850 }
Owen Taylor3473f882001-02-23 17:55:21 +00001851 xmlFree(obj);
1852}
1853
1854/**
1855 * xmlXPathFreeValueTree:
1856 * @obj: the xmlNodeSetPtr to free
1857 *
1858 * Free the NodeSet compound and the actual tree, this is different
1859 * from xmlXPathFreeNodeSet()
1860 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001861static void
Owen Taylor3473f882001-02-23 17:55:21 +00001862xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1863 int i;
1864
1865 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001866
1867 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001868 for (i = 0;i < obj->nodeNr;i++) {
1869 if (obj->nodeTab[i] != NULL) {
1870 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1871 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
1872 } else {
1873 xmlFreeNodeList(obj->nodeTab[i]);
1874 }
1875 }
1876 }
Owen Taylor3473f882001-02-23 17:55:21 +00001877 xmlFree(obj->nodeTab);
1878 }
Owen Taylor3473f882001-02-23 17:55:21 +00001879 xmlFree(obj);
1880}
1881
1882#if defined(DEBUG) || defined(DEBUG_STEP)
1883/**
1884 * xmlGenericErrorContextNodeSet:
1885 * @output: a FILE * for the output
1886 * @obj: the xmlNodeSetPtr to free
1887 *
1888 * Quick display of a NodeSet
1889 */
1890void
1891xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1892 int i;
1893
1894 if (output == NULL) output = xmlGenericErrorContext;
1895 if (obj == NULL) {
1896 fprintf(output, "NodeSet == NULL !\n");
1897 return;
1898 }
1899 if (obj->nodeNr == 0) {
1900 fprintf(output, "NodeSet is empty\n");
1901 return;
1902 }
1903 if (obj->nodeTab == NULL) {
1904 fprintf(output, " nodeTab == NULL !\n");
1905 return;
1906 }
1907 for (i = 0; i < obj->nodeNr; i++) {
1908 if (obj->nodeTab[i] == NULL) {
1909 fprintf(output, " NULL !\n");
1910 return;
1911 }
1912 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1913 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1914 fprintf(output, " /");
1915 else if (obj->nodeTab[i]->name == NULL)
1916 fprintf(output, " noname!");
1917 else fprintf(output, " %s", obj->nodeTab[i]->name);
1918 }
1919 fprintf(output, "\n");
1920}
1921#endif
1922
1923/**
1924 * xmlXPathNewNodeSet:
1925 * @val: the NodePtr value
1926 *
1927 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1928 * it with the single Node @val
1929 *
1930 * Returns the newly created object.
1931 */
1932xmlXPathObjectPtr
1933xmlXPathNewNodeSet(xmlNodePtr val) {
1934 xmlXPathObjectPtr ret;
1935
1936 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1937 if (ret == NULL) {
1938 xmlGenericError(xmlGenericErrorContext,
1939 "xmlXPathNewNodeSet: out of memory\n");
1940 return(NULL);
1941 }
1942 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1943 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001944 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001945 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001946 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001947 return(ret);
1948}
1949
1950/**
1951 * xmlXPathNewValueTree:
1952 * @val: the NodePtr value
1953 *
1954 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1955 * it with the tree root @val
1956 *
1957 * Returns the newly created object.
1958 */
1959xmlXPathObjectPtr
1960xmlXPathNewValueTree(xmlNodePtr val) {
1961 xmlXPathObjectPtr ret;
1962
1963 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1964 if (ret == NULL) {
1965 xmlGenericError(xmlGenericErrorContext,
1966 "xmlXPathNewNodeSet: out of memory\n");
1967 return(NULL);
1968 }
1969 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1970 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001971 ret->boolval = 1;
1972 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00001973 ret->nodesetval = xmlXPathNodeSetCreate(val);
1974 return(ret);
1975}
1976
1977/**
1978 * xmlXPathNewNodeSetList:
1979 * @val: an existing NodeSet
1980 *
1981 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1982 * it with the Nodeset @val
1983 *
1984 * Returns the newly created object.
1985 */
1986xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001987xmlXPathNewNodeSetList(xmlNodeSetPtr val)
1988{
Owen Taylor3473f882001-02-23 17:55:21 +00001989 xmlXPathObjectPtr ret;
1990 int i;
1991
1992 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001993 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001994 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001995 ret = xmlXPathNewNodeSet(NULL);
1996 else {
1997 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1998 for (i = 1; i < val->nodeNr; ++i)
1999 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2000 }
Owen Taylor3473f882001-02-23 17:55:21 +00002001
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002002 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002003}
2004
2005/**
2006 * xmlXPathWrapNodeSet:
2007 * @val: the NodePtr value
2008 *
2009 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2010 *
2011 * Returns the newly created object.
2012 */
2013xmlXPathObjectPtr
2014xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2015 xmlXPathObjectPtr ret;
2016
2017 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2018 if (ret == NULL) {
2019 xmlGenericError(xmlGenericErrorContext,
2020 "xmlXPathWrapNodeSet: out of memory\n");
2021 return(NULL);
2022 }
2023 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2024 ret->type = XPATH_NODESET;
2025 ret->nodesetval = val;
2026 return(ret);
2027}
2028
2029/**
2030 * xmlXPathFreeNodeSetList:
2031 * @obj: an existing NodeSetList object
2032 *
2033 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2034 * the list contrary to xmlXPathFreeObject().
2035 */
2036void
2037xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2038 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002039 xmlFree(obj);
2040}
2041
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002042/**
2043 * xmlXPathDifference:
2044 * @nodes1: a node-set
2045 * @nodes2: a node-set
2046 *
2047 * Implements the EXSLT - Sets difference() function:
2048 * node-set set:difference (node-set, node-set)
2049 *
2050 * Returns the difference between the two node sets, or nodes1 if
2051 * nodes2 is empty
2052 */
2053xmlNodeSetPtr
2054xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2055 xmlNodeSetPtr ret;
2056 int i, l1;
2057 xmlNodePtr cur;
2058
2059 if (xmlXPathNodeSetIsEmpty(nodes2))
2060 return(nodes1);
2061
2062 ret = xmlXPathNodeSetCreate(NULL);
2063 if (xmlXPathNodeSetIsEmpty(nodes1))
2064 return(ret);
2065
2066 l1 = xmlXPathNodeSetGetLength(nodes1);
2067
2068 for (i = 0; i < l1; i++) {
2069 cur = xmlXPathNodeSetItem(nodes1, i);
2070 if (!xmlXPathNodeSetContains(nodes2, cur))
2071 xmlXPathNodeSetAddUnique(ret, cur);
2072 }
2073 return(ret);
2074}
2075
2076/**
2077 * xmlXPathIntersection:
2078 * @nodes1: a node-set
2079 * @nodes2: a node-set
2080 *
2081 * Implements the EXSLT - Sets intersection() function:
2082 * node-set set:intersection (node-set, node-set)
2083 *
2084 * Returns a node set comprising the nodes that are within both the
2085 * node sets passed as arguments
2086 */
2087xmlNodeSetPtr
2088xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2089 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2090 int i, l1;
2091 xmlNodePtr cur;
2092
2093 if (xmlXPathNodeSetIsEmpty(nodes1))
2094 return(ret);
2095 if (xmlXPathNodeSetIsEmpty(nodes2))
2096 return(ret);
2097
2098 l1 = xmlXPathNodeSetGetLength(nodes1);
2099
2100 for (i = 0; i < l1; i++) {
2101 cur = xmlXPathNodeSetItem(nodes1, i);
2102 if (xmlXPathNodeSetContains(nodes2, cur))
2103 xmlXPathNodeSetAddUnique(ret, cur);
2104 }
2105 return(ret);
2106}
2107
2108/**
2109 * xmlXPathDistinctSorted:
2110 * @nodes: a node-set, sorted by document order
2111 *
2112 * Implements the EXSLT - Sets distinct() function:
2113 * node-set set:distinct (node-set)
2114 *
2115 * Returns a subset of the nodes contained in @nodes, or @nodes if
2116 * it is empty
2117 */
2118xmlNodeSetPtr
2119xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2120 xmlNodeSetPtr ret;
2121 xmlHashTablePtr hash;
2122 int i, l;
2123 xmlChar * strval;
2124 xmlNodePtr cur;
2125
2126 if (xmlXPathNodeSetIsEmpty(nodes))
2127 return(nodes);
2128
2129 ret = xmlXPathNodeSetCreate(NULL);
2130 l = xmlXPathNodeSetGetLength(nodes);
2131 hash = xmlHashCreate (l);
2132 for (i = 0; i < l; i++) {
2133 cur = xmlXPathNodeSetItem(nodes, i);
2134 strval = xmlXPathCastNodeToString(cur);
2135 if (xmlHashLookup(hash, strval) == NULL) {
2136 xmlHashAddEntry(hash, strval, strval);
2137 xmlXPathNodeSetAddUnique(ret, cur);
2138 } else {
2139 xmlFree(strval);
2140 }
2141 }
2142 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2143 return(ret);
2144}
2145
2146/**
2147 * xmlXPathDistinct:
2148 * @nodes: a node-set
2149 *
2150 * Implements the EXSLT - Sets distinct() function:
2151 * node-set set:distinct (node-set)
2152 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2153 * is called with the sorted node-set
2154 *
2155 * Returns a subset of the nodes contained in @nodes, or @nodes if
2156 * it is empty
2157 */
2158xmlNodeSetPtr
2159xmlXPathDistinct (xmlNodeSetPtr nodes) {
2160 if (xmlXPathNodeSetIsEmpty(nodes))
2161 return(nodes);
2162
2163 xmlXPathNodeSetSort(nodes);
2164 return(xmlXPathDistinctSorted(nodes));
2165}
2166
2167/**
2168 * xmlXPathHasSameNodes:
2169 * @nodes1: a node-set
2170 * @nodes2: a node-set
2171 *
2172 * Implements the EXSLT - Sets has-same-nodes function:
2173 * boolean set:has-same-node(node-set, node-set)
2174 *
2175 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2176 * otherwise
2177 */
2178int
2179xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2180 int i, l;
2181 xmlNodePtr cur;
2182
2183 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2184 xmlXPathNodeSetIsEmpty(nodes2))
2185 return(0);
2186
2187 l = xmlXPathNodeSetGetLength(nodes1);
2188 for (i = 0; i < l; i++) {
2189 cur = xmlXPathNodeSetItem(nodes1, i);
2190 if (xmlXPathNodeSetContains(nodes2, cur))
2191 return(1);
2192 }
2193 return(0);
2194}
2195
2196/**
2197 * xmlXPathNodeLeadingSorted:
2198 * @nodes: a node-set, sorted by document order
2199 * @node: a node
2200 *
2201 * Implements the EXSLT - Sets leading() function:
2202 * node-set set:leading (node-set, node-set)
2203 *
2204 * Returns the nodes in @nodes that precede @node in document order,
2205 * @nodes if @node is NULL or an empty node-set if @nodes
2206 * doesn't contain @node
2207 */
2208xmlNodeSetPtr
2209xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2210 int i, l;
2211 xmlNodePtr cur;
2212 xmlNodeSetPtr ret;
2213
2214 if (node == NULL)
2215 return(nodes);
2216
2217 ret = xmlXPathNodeSetCreate(NULL);
2218 if (xmlXPathNodeSetIsEmpty(nodes) ||
2219 (!xmlXPathNodeSetContains(nodes, node)))
2220 return(ret);
2221
2222 l = xmlXPathNodeSetGetLength(nodes);
2223 for (i = 0; i < l; i++) {
2224 cur = xmlXPathNodeSetItem(nodes, i);
2225 if (cur == node)
2226 break;
2227 xmlXPathNodeSetAddUnique(ret, cur);
2228 }
2229 return(ret);
2230}
2231
2232/**
2233 * xmlXPathNodeLeading:
2234 * @nodes: a node-set
2235 * @node: a node
2236 *
2237 * Implements the EXSLT - Sets leading() function:
2238 * node-set set:leading (node-set, node-set)
2239 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2240 * is called.
2241 *
2242 * Returns the nodes in @nodes that precede @node in document order,
2243 * @nodes if @node is NULL or an empty node-set if @nodes
2244 * doesn't contain @node
2245 */
2246xmlNodeSetPtr
2247xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2248 xmlXPathNodeSetSort(nodes);
2249 return(xmlXPathNodeLeadingSorted(nodes, node));
2250}
2251
2252/**
2253 * xmlXPathLeadingSorted:
2254 * @nodes1: a node-set, sorted by document order
2255 * @nodes2: a node-set, sorted by document order
2256 *
2257 * Implements the EXSLT - Sets leading() function:
2258 * node-set set:leading (node-set, node-set)
2259 *
2260 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2261 * in document order, @nodes1 if @nodes2 is NULL or empty or
2262 * an empty node-set if @nodes1 doesn't contain @nodes2
2263 */
2264xmlNodeSetPtr
2265xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2266 if (xmlXPathNodeSetIsEmpty(nodes2))
2267 return(nodes1);
2268 return(xmlXPathNodeLeadingSorted(nodes1,
2269 xmlXPathNodeSetItem(nodes2, 1)));
2270}
2271
2272/**
2273 * xmlXPathLeading:
2274 * @nodes1: a node-set
2275 * @nodes2: a node-set
2276 *
2277 * Implements the EXSLT - Sets leading() function:
2278 * node-set set:leading (node-set, node-set)
2279 * @nodes1 and @nodes2 are sorted by document order, then
2280 * #exslSetsLeadingSorted is called.
2281 *
2282 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2283 * in document order, @nodes1 if @nodes2 is NULL or empty or
2284 * an empty node-set if @nodes1 doesn't contain @nodes2
2285 */
2286xmlNodeSetPtr
2287xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2288 if (xmlXPathNodeSetIsEmpty(nodes2))
2289 return(nodes1);
2290 if (xmlXPathNodeSetIsEmpty(nodes1))
2291 return(xmlXPathNodeSetCreate(NULL));
2292 xmlXPathNodeSetSort(nodes1);
2293 xmlXPathNodeSetSort(nodes2);
2294 return(xmlXPathNodeLeadingSorted(nodes1,
2295 xmlXPathNodeSetItem(nodes2, 1)));
2296}
2297
2298/**
2299 * xmlXPathNodeTrailingSorted:
2300 * @nodes: a node-set, sorted by document order
2301 * @node: a node
2302 *
2303 * Implements the EXSLT - Sets trailing() function:
2304 * node-set set:trailing (node-set, node-set)
2305 *
2306 * Returns the nodes in @nodes that follow @node in document order,
2307 * @nodes if @node is NULL or an empty node-set if @nodes
2308 * doesn't contain @node
2309 */
2310xmlNodeSetPtr
2311xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2312 int i, l;
2313 xmlNodePtr cur;
2314 xmlNodeSetPtr ret;
2315
2316 if (node == NULL)
2317 return(nodes);
2318
2319 ret = xmlXPathNodeSetCreate(NULL);
2320 if (xmlXPathNodeSetIsEmpty(nodes) ||
2321 (!xmlXPathNodeSetContains(nodes, node)))
2322 return(ret);
2323
2324 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002325 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002326 cur = xmlXPathNodeSetItem(nodes, i);
2327 if (cur == node)
2328 break;
2329 xmlXPathNodeSetAddUnique(ret, cur);
2330 }
2331 return(ret);
2332}
2333
2334/**
2335 * xmlXPathNodeTrailing:
2336 * @nodes: a node-set
2337 * @node: a node
2338 *
2339 * Implements the EXSLT - Sets trailing() function:
2340 * node-set set:trailing (node-set, node-set)
2341 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2342 * is called.
2343 *
2344 * Returns the nodes in @nodes that follow @node in document order,
2345 * @nodes if @node is NULL or an empty node-set if @nodes
2346 * doesn't contain @node
2347 */
2348xmlNodeSetPtr
2349xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2350 xmlXPathNodeSetSort(nodes);
2351 return(xmlXPathNodeTrailingSorted(nodes, node));
2352}
2353
2354/**
2355 * xmlXPathTrailingSorted:
2356 * @nodes1: a node-set, sorted by document order
2357 * @nodes2: a node-set, sorted by document order
2358 *
2359 * Implements the EXSLT - Sets trailing() function:
2360 * node-set set:trailing (node-set, node-set)
2361 *
2362 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2363 * in document order, @nodes1 if @nodes2 is NULL or empty or
2364 * an empty node-set if @nodes1 doesn't contain @nodes2
2365 */
2366xmlNodeSetPtr
2367xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2368 if (xmlXPathNodeSetIsEmpty(nodes2))
2369 return(nodes1);
2370 return(xmlXPathNodeTrailingSorted(nodes1,
2371 xmlXPathNodeSetItem(nodes2, 0)));
2372}
2373
2374/**
2375 * xmlXPathTrailing:
2376 * @nodes1: a node-set
2377 * @nodes2: a node-set
2378 *
2379 * Implements the EXSLT - Sets trailing() function:
2380 * node-set set:trailing (node-set, node-set)
2381 * @nodes1 and @nodes2 are sorted by document order, then
2382 * #xmlXPathTrailingSorted is called.
2383 *
2384 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2385 * in document order, @nodes1 if @nodes2 is NULL or empty or
2386 * an empty node-set if @nodes1 doesn't contain @nodes2
2387 */
2388xmlNodeSetPtr
2389xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2390 if (xmlXPathNodeSetIsEmpty(nodes2))
2391 return(nodes1);
2392 if (xmlXPathNodeSetIsEmpty(nodes1))
2393 return(xmlXPathNodeSetCreate(NULL));
2394 xmlXPathNodeSetSort(nodes1);
2395 xmlXPathNodeSetSort(nodes2);
2396 return(xmlXPathNodeTrailingSorted(nodes1,
2397 xmlXPathNodeSetItem(nodes2, 0)));
2398}
2399
Owen Taylor3473f882001-02-23 17:55:21 +00002400/************************************************************************
2401 * *
2402 * Routines to handle extra functions *
2403 * *
2404 ************************************************************************/
2405
2406/**
2407 * xmlXPathRegisterFunc:
2408 * @ctxt: the XPath context
2409 * @name: the function name
2410 * @f: the function implementation or NULL
2411 *
2412 * Register a new function. If @f is NULL it unregisters the function
2413 *
2414 * Returns 0 in case of success, -1 in case of error
2415 */
2416int
2417xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2418 xmlXPathFunction f) {
2419 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2420}
2421
2422/**
2423 * xmlXPathRegisterFuncNS:
2424 * @ctxt: the XPath context
2425 * @name: the function name
2426 * @ns_uri: the function namespace URI
2427 * @f: the function implementation or NULL
2428 *
2429 * Register a new function. If @f is NULL it unregisters the function
2430 *
2431 * Returns 0 in case of success, -1 in case of error
2432 */
2433int
2434xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2435 const xmlChar *ns_uri, xmlXPathFunction f) {
2436 if (ctxt == NULL)
2437 return(-1);
2438 if (name == NULL)
2439 return(-1);
2440
2441 if (ctxt->funcHash == NULL)
2442 ctxt->funcHash = xmlHashCreate(0);
2443 if (ctxt->funcHash == NULL)
2444 return(-1);
2445 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2446}
2447
2448/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002449 * xmlXPathRegisterFuncLookup:
2450 * @ctxt: the XPath context
2451 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002452 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002453 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002454 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002455 */
2456void
2457xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2458 xmlXPathFuncLookupFunc f,
2459 void *funcCtxt) {
2460 if (ctxt == NULL)
2461 return;
2462 ctxt->funcLookupFunc = (void *) f;
2463 ctxt->funcLookupData = funcCtxt;
2464}
2465
2466/**
Owen Taylor3473f882001-02-23 17:55:21 +00002467 * xmlXPathFunctionLookup:
2468 * @ctxt: the XPath context
2469 * @name: the function name
2470 *
2471 * Search in the Function array of the context for the given
2472 * function.
2473 *
2474 * Returns the xmlXPathFunction or NULL if not found
2475 */
2476xmlXPathFunction
2477xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002478 if (ctxt == NULL)
2479 return (NULL);
2480
2481 if (ctxt->funcLookupFunc != NULL) {
2482 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002483 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002484
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002485 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002486 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002487 if (ret != NULL)
2488 return(ret);
2489 }
Owen Taylor3473f882001-02-23 17:55:21 +00002490 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2491}
2492
2493/**
2494 * xmlXPathFunctionLookupNS:
2495 * @ctxt: the XPath context
2496 * @name: the function name
2497 * @ns_uri: the function namespace URI
2498 *
2499 * Search in the Function array of the context for the given
2500 * function.
2501 *
2502 * Returns the xmlXPathFunction or NULL if not found
2503 */
2504xmlXPathFunction
2505xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2506 const xmlChar *ns_uri) {
2507 if (ctxt == NULL)
2508 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002509 if (name == NULL)
2510 return(NULL);
2511
Thomas Broyerba4ad322001-07-26 16:55:21 +00002512 if (ctxt->funcLookupFunc != NULL) {
2513 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002514 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002515
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002516 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002517 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002518 if (ret != NULL)
2519 return(ret);
2520 }
2521
2522 if (ctxt->funcHash == NULL)
2523 return(NULL);
2524
Owen Taylor3473f882001-02-23 17:55:21 +00002525 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2526}
2527
2528/**
2529 * xmlXPathRegisteredFuncsCleanup:
2530 * @ctxt: the XPath context
2531 *
2532 * Cleanup the XPath context data associated to registered functions
2533 */
2534void
2535xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2536 if (ctxt == NULL)
2537 return;
2538
2539 xmlHashFree(ctxt->funcHash, NULL);
2540 ctxt->funcHash = NULL;
2541}
2542
2543/************************************************************************
2544 * *
2545 * Routines to handle Variable *
2546 * *
2547 ************************************************************************/
2548
2549/**
2550 * xmlXPathRegisterVariable:
2551 * @ctxt: the XPath context
2552 * @name: the variable name
2553 * @value: the variable value or NULL
2554 *
2555 * Register a new variable value. If @value is NULL it unregisters
2556 * the variable
2557 *
2558 * Returns 0 in case of success, -1 in case of error
2559 */
2560int
2561xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2562 xmlXPathObjectPtr value) {
2563 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2564}
2565
2566/**
2567 * xmlXPathRegisterVariableNS:
2568 * @ctxt: the XPath context
2569 * @name: the variable name
2570 * @ns_uri: the variable namespace URI
2571 * @value: the variable value or NULL
2572 *
2573 * Register a new variable value. If @value is NULL it unregisters
2574 * the variable
2575 *
2576 * Returns 0 in case of success, -1 in case of error
2577 */
2578int
2579xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2580 const xmlChar *ns_uri,
2581 xmlXPathObjectPtr value) {
2582 if (ctxt == NULL)
2583 return(-1);
2584 if (name == NULL)
2585 return(-1);
2586
2587 if (ctxt->varHash == NULL)
2588 ctxt->varHash = xmlHashCreate(0);
2589 if (ctxt->varHash == NULL)
2590 return(-1);
2591 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2592 (void *) value,
2593 (xmlHashDeallocator)xmlXPathFreeObject));
2594}
2595
2596/**
2597 * xmlXPathRegisterVariableLookup:
2598 * @ctxt: the XPath context
2599 * @f: the lookup function
2600 * @data: the lookup data
2601 *
2602 * register an external mechanism to do variable lookup
2603 */
2604void
2605xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2606 xmlXPathVariableLookupFunc f, void *data) {
2607 if (ctxt == NULL)
2608 return;
2609 ctxt->varLookupFunc = (void *) f;
2610 ctxt->varLookupData = data;
2611}
2612
2613/**
2614 * xmlXPathVariableLookup:
2615 * @ctxt: the XPath context
2616 * @name: the variable name
2617 *
2618 * Search in the Variable array of the context for the given
2619 * variable value.
2620 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002621 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002622 */
2623xmlXPathObjectPtr
2624xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2625 if (ctxt == NULL)
2626 return(NULL);
2627
2628 if (ctxt->varLookupFunc != NULL) {
2629 xmlXPathObjectPtr ret;
2630
2631 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2632 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002633 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002634 }
2635 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2636}
2637
2638/**
2639 * xmlXPathVariableLookupNS:
2640 * @ctxt: the XPath context
2641 * @name: the variable name
2642 * @ns_uri: the variable namespace URI
2643 *
2644 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002645 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002646 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002647 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002648 */
2649xmlXPathObjectPtr
2650xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2651 const xmlChar *ns_uri) {
2652 if (ctxt == NULL)
2653 return(NULL);
2654
2655 if (ctxt->varLookupFunc != NULL) {
2656 xmlXPathObjectPtr ret;
2657
2658 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2659 (ctxt->varLookupData, name, ns_uri);
2660 if (ret != NULL) return(ret);
2661 }
2662
2663 if (ctxt->varHash == NULL)
2664 return(NULL);
2665 if (name == NULL)
2666 return(NULL);
2667
Daniel Veillard8c357d52001-07-03 23:43:33 +00002668 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2669 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002670}
2671
2672/**
2673 * xmlXPathRegisteredVariablesCleanup:
2674 * @ctxt: the XPath context
2675 *
2676 * Cleanup the XPath context data associated to registered variables
2677 */
2678void
2679xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2680 if (ctxt == NULL)
2681 return;
2682
Daniel Veillard76d66f42001-05-16 21:05:17 +00002683 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002684 ctxt->varHash = NULL;
2685}
2686
2687/**
2688 * xmlXPathRegisterNs:
2689 * @ctxt: the XPath context
2690 * @prefix: the namespace prefix
2691 * @ns_uri: the namespace name
2692 *
2693 * Register a new namespace. If @ns_uri is NULL it unregisters
2694 * the namespace
2695 *
2696 * Returns 0 in case of success, -1 in case of error
2697 */
2698int
2699xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2700 const xmlChar *ns_uri) {
2701 if (ctxt == NULL)
2702 return(-1);
2703 if (prefix == NULL)
2704 return(-1);
2705
2706 if (ctxt->nsHash == NULL)
2707 ctxt->nsHash = xmlHashCreate(10);
2708 if (ctxt->nsHash == NULL)
2709 return(-1);
2710 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2711 (xmlHashDeallocator)xmlFree));
2712}
2713
2714/**
2715 * xmlXPathNsLookup:
2716 * @ctxt: the XPath context
2717 * @prefix: the namespace prefix value
2718 *
2719 * Search in the namespace declaration array of the context for the given
2720 * namespace name associated to the given prefix
2721 *
2722 * Returns the value or NULL if not found
2723 */
2724const xmlChar *
2725xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2726 if (ctxt == NULL)
2727 return(NULL);
2728 if (prefix == NULL)
2729 return(NULL);
2730
2731#ifdef XML_XML_NAMESPACE
2732 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2733 return(XML_XML_NAMESPACE);
2734#endif
2735
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002736 if (ctxt->namespaces != NULL) {
2737 int i;
2738
2739 for (i = 0;i < ctxt->nsNr;i++) {
2740 if ((ctxt->namespaces[i] != NULL) &&
2741 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2742 return(ctxt->namespaces[i]->href);
2743 }
2744 }
Owen Taylor3473f882001-02-23 17:55:21 +00002745
2746 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2747}
2748
2749/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002750 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002751 * @ctxt: the XPath context
2752 *
2753 * Cleanup the XPath context data associated to registered variables
2754 */
2755void
2756xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2757 if (ctxt == NULL)
2758 return;
2759
2760 xmlHashFree(ctxt->nsHash, NULL);
2761 ctxt->nsHash = NULL;
2762}
2763
2764/************************************************************************
2765 * *
2766 * Routines to handle Values *
2767 * *
2768 ************************************************************************/
2769
2770/* Allocations are terrible, one need to optimize all this !!! */
2771
2772/**
2773 * xmlXPathNewFloat:
2774 * @val: the double value
2775 *
2776 * Create a new xmlXPathObjectPtr of type double and of value @val
2777 *
2778 * Returns the newly created object.
2779 */
2780xmlXPathObjectPtr
2781xmlXPathNewFloat(double val) {
2782 xmlXPathObjectPtr ret;
2783
2784 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2785 if (ret == NULL) {
2786 xmlGenericError(xmlGenericErrorContext,
2787 "xmlXPathNewFloat: out of memory\n");
2788 return(NULL);
2789 }
2790 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2791 ret->type = XPATH_NUMBER;
2792 ret->floatval = val;
2793 return(ret);
2794}
2795
2796/**
2797 * xmlXPathNewBoolean:
2798 * @val: the boolean value
2799 *
2800 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2801 *
2802 * Returns the newly created object.
2803 */
2804xmlXPathObjectPtr
2805xmlXPathNewBoolean(int val) {
2806 xmlXPathObjectPtr ret;
2807
2808 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2809 if (ret == NULL) {
2810 xmlGenericError(xmlGenericErrorContext,
2811 "xmlXPathNewBoolean: out of memory\n");
2812 return(NULL);
2813 }
2814 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2815 ret->type = XPATH_BOOLEAN;
2816 ret->boolval = (val != 0);
2817 return(ret);
2818}
2819
2820/**
2821 * xmlXPathNewString:
2822 * @val: the xmlChar * value
2823 *
2824 * Create a new xmlXPathObjectPtr of type string and of value @val
2825 *
2826 * Returns the newly created object.
2827 */
2828xmlXPathObjectPtr
2829xmlXPathNewString(const xmlChar *val) {
2830 xmlXPathObjectPtr ret;
2831
2832 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2833 if (ret == NULL) {
2834 xmlGenericError(xmlGenericErrorContext,
2835 "xmlXPathNewString: out of memory\n");
2836 return(NULL);
2837 }
2838 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2839 ret->type = XPATH_STRING;
2840 if (val != NULL)
2841 ret->stringval = xmlStrdup(val);
2842 else
2843 ret->stringval = xmlStrdup((const xmlChar *)"");
2844 return(ret);
2845}
2846
2847/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002848 * xmlXPathWrapString:
2849 * @val: the xmlChar * value
2850 *
2851 * Wraps the @val string into an XPath object.
2852 *
2853 * Returns the newly created object.
2854 */
2855xmlXPathObjectPtr
2856xmlXPathWrapString (xmlChar *val) {
2857 xmlXPathObjectPtr ret;
2858
2859 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2860 if (ret == NULL) {
2861 xmlGenericError(xmlGenericErrorContext,
2862 "xmlXPathWrapString: out of memory\n");
2863 return(NULL);
2864 }
2865 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2866 ret->type = XPATH_STRING;
2867 ret->stringval = val;
2868 return(ret);
2869}
2870
2871/**
Owen Taylor3473f882001-02-23 17:55:21 +00002872 * xmlXPathNewCString:
2873 * @val: the char * value
2874 *
2875 * Create a new xmlXPathObjectPtr of type string and of value @val
2876 *
2877 * Returns the newly created object.
2878 */
2879xmlXPathObjectPtr
2880xmlXPathNewCString(const char *val) {
2881 xmlXPathObjectPtr ret;
2882
2883 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2884 if (ret == NULL) {
2885 xmlGenericError(xmlGenericErrorContext,
2886 "xmlXPathNewCString: out of memory\n");
2887 return(NULL);
2888 }
2889 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2890 ret->type = XPATH_STRING;
2891 ret->stringval = xmlStrdup(BAD_CAST val);
2892 return(ret);
2893}
2894
2895/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002896 * xmlXPathWrapCString:
2897 * @val: the char * value
2898 *
2899 * Wraps a string into an XPath object.
2900 *
2901 * Returns the newly created object.
2902 */
2903xmlXPathObjectPtr
2904xmlXPathWrapCString (char * val) {
2905 return(xmlXPathWrapString((xmlChar *)(val)));
2906}
2907
2908/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002909 * xmlXPathWrapExternal:
2910 * @val: the user data
2911 *
2912 * Wraps the @val data into an XPath object.
2913 *
2914 * Returns the newly created object.
2915 */
2916xmlXPathObjectPtr
2917xmlXPathWrapExternal (void *val) {
2918 xmlXPathObjectPtr ret;
2919
2920 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2921 if (ret == NULL) {
2922 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002923 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002924 return(NULL);
2925 }
2926 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2927 ret->type = XPATH_USERS;
2928 ret->user = val;
2929 return(ret);
2930}
2931
2932/**
Owen Taylor3473f882001-02-23 17:55:21 +00002933 * xmlXPathObjectCopy:
2934 * @val: the original object
2935 *
2936 * allocate a new copy of a given object
2937 *
2938 * Returns the newly created object.
2939 */
2940xmlXPathObjectPtr
2941xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2942 xmlXPathObjectPtr ret;
2943
2944 if (val == NULL)
2945 return(NULL);
2946
2947 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2948 if (ret == NULL) {
2949 xmlGenericError(xmlGenericErrorContext,
2950 "xmlXPathObjectCopy: out of memory\n");
2951 return(NULL);
2952 }
2953 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2954 switch (val->type) {
2955 case XPATH_BOOLEAN:
2956 case XPATH_NUMBER:
2957 case XPATH_POINT:
2958 case XPATH_RANGE:
2959 break;
2960 case XPATH_STRING:
2961 ret->stringval = xmlStrdup(val->stringval);
2962 break;
2963 case XPATH_XSLT_TREE:
2964 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002965 (val->nodesetval->nodeTab != NULL)) {
2966 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00002967 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
2968 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002969 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002970 (xmlNodePtr) ret->user);
2971 } else
Owen Taylor3473f882001-02-23 17:55:21 +00002972 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002973 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00002974 break;
2975 case XPATH_NODESET:
2976 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002977 /* Do not deallocate the copied tree value */
2978 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002979 break;
2980 case XPATH_LOCATIONSET:
2981#ifdef LIBXML_XPTR_ENABLED
2982 {
2983 xmlLocationSetPtr loc = val->user;
2984 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2985 break;
2986 }
2987#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00002988 case XPATH_USERS:
2989 ret->user = val->user;
2990 break;
2991 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00002992 xmlGenericError(xmlGenericErrorContext,
2993 "xmlXPathObjectCopy: unsupported type %d\n",
2994 val->type);
2995 break;
2996 }
2997 return(ret);
2998}
2999
3000/**
3001 * xmlXPathFreeObject:
3002 * @obj: the object to free
3003 *
3004 * Free up an xmlXPathObjectPtr object.
3005 */
3006void
3007xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3008 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003009 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003010 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003011 if (obj->user != NULL) {
3012 xmlFreeNodeList((xmlNodePtr) obj->user);
3013 xmlXPathFreeNodeSet(obj->nodesetval);
3014 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003015 xmlXPathFreeValueTree(obj->nodesetval);
3016 } else {
3017 if (obj->nodesetval != NULL)
3018 xmlXPathFreeNodeSet(obj->nodesetval);
3019 }
Owen Taylor3473f882001-02-23 17:55:21 +00003020#ifdef LIBXML_XPTR_ENABLED
3021 } else if (obj->type == XPATH_LOCATIONSET) {
3022 if (obj->user != NULL)
3023 xmlXPtrFreeLocationSet(obj->user);
3024#endif
3025 } else if (obj->type == XPATH_STRING) {
3026 if (obj->stringval != NULL)
3027 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003028 }
3029
Owen Taylor3473f882001-02-23 17:55:21 +00003030 xmlFree(obj);
3031}
3032
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003033
3034/************************************************************************
3035 * *
3036 * Type Casting Routines *
3037 * *
3038 ************************************************************************/
3039
3040/**
3041 * xmlXPathCastBooleanToString:
3042 * @val: a boolean
3043 *
3044 * Converts a boolean to its string value.
3045 *
3046 * Returns a newly allocated string.
3047 */
3048xmlChar *
3049xmlXPathCastBooleanToString (int val) {
3050 xmlChar *ret;
3051 if (val)
3052 ret = xmlStrdup((const xmlChar *) "true");
3053 else
3054 ret = xmlStrdup((const xmlChar *) "false");
3055 return(ret);
3056}
3057
3058/**
3059 * xmlXPathCastNumberToString:
3060 * @val: a number
3061 *
3062 * Converts a number to its string value.
3063 *
3064 * Returns a newly allocated string.
3065 */
3066xmlChar *
3067xmlXPathCastNumberToString (double val) {
3068 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003069 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003070 case 1:
3071 ret = xmlStrdup((const xmlChar *) "+Infinity");
3072 break;
3073 case -1:
3074 ret = xmlStrdup((const xmlChar *) "-Infinity");
3075 break;
3076 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003077 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003078 ret = xmlStrdup((const xmlChar *) "NaN");
3079 } else {
3080 /* could be improved */
3081 char buf[100];
3082 xmlXPathFormatNumber(val, buf, 100);
3083 ret = xmlStrdup((const xmlChar *) buf);
3084 }
3085 }
3086 return(ret);
3087}
3088
3089/**
3090 * xmlXPathCastNodeToString:
3091 * @node: a node
3092 *
3093 * Converts a node to its string value.
3094 *
3095 * Returns a newly allocated string.
3096 */
3097xmlChar *
3098xmlXPathCastNodeToString (xmlNodePtr node) {
3099 return(xmlNodeGetContent(node));
3100}
3101
3102/**
3103 * xmlXPathCastNodeSetToString:
3104 * @ns: a node-set
3105 *
3106 * Converts a node-set to its string value.
3107 *
3108 * Returns a newly allocated string.
3109 */
3110xmlChar *
3111xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3112 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3113 return(xmlStrdup((const xmlChar *) ""));
3114
3115 xmlXPathNodeSetSort(ns);
3116 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3117}
3118
3119/**
3120 * xmlXPathCastToString:
3121 * @val: an XPath object
3122 *
3123 * Converts an existing object to its string() equivalent
3124 *
3125 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003126 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003127 * string object).
3128 */
3129xmlChar *
3130xmlXPathCastToString(xmlXPathObjectPtr val) {
3131 xmlChar *ret = NULL;
3132
3133 if (val == NULL)
3134 return(xmlStrdup((const xmlChar *) ""));
3135 switch (val->type) {
3136 case XPATH_UNDEFINED:
3137#ifdef DEBUG_EXPR
3138 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3139#endif
3140 ret = xmlStrdup((const xmlChar *) "");
3141 break;
3142 case XPATH_XSLT_TREE:
3143 case XPATH_NODESET:
3144 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3145 break;
3146 case XPATH_STRING:
3147 return(val->stringval);
3148 case XPATH_BOOLEAN:
3149 ret = xmlXPathCastBooleanToString(val->boolval);
3150 break;
3151 case XPATH_NUMBER: {
3152 ret = xmlXPathCastNumberToString(val->floatval);
3153 break;
3154 }
3155 case XPATH_USERS:
3156 case XPATH_POINT:
3157 case XPATH_RANGE:
3158 case XPATH_LOCATIONSET:
3159 TODO
3160 ret = xmlStrdup((const xmlChar *) "");
3161 break;
3162 }
3163 return(ret);
3164}
3165
3166/**
3167 * xmlXPathConvertString:
3168 * @val: an XPath object
3169 *
3170 * Converts an existing object to its string() equivalent
3171 *
3172 * Returns the new object, the old one is freed (or the operation
3173 * is done directly on @val)
3174 */
3175xmlXPathObjectPtr
3176xmlXPathConvertString(xmlXPathObjectPtr val) {
3177 xmlChar *res = NULL;
3178
3179 if (val == NULL)
3180 return(xmlXPathNewCString(""));
3181
3182 switch (val->type) {
3183 case XPATH_UNDEFINED:
3184#ifdef DEBUG_EXPR
3185 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3186#endif
3187 break;
3188 case XPATH_XSLT_TREE:
3189 case XPATH_NODESET:
3190 res = xmlXPathCastNodeSetToString(val->nodesetval);
3191 break;
3192 case XPATH_STRING:
3193 return(val);
3194 case XPATH_BOOLEAN:
3195 res = xmlXPathCastBooleanToString(val->boolval);
3196 break;
3197 case XPATH_NUMBER:
3198 res = xmlXPathCastNumberToString(val->floatval);
3199 break;
3200 case XPATH_USERS:
3201 case XPATH_POINT:
3202 case XPATH_RANGE:
3203 case XPATH_LOCATIONSET:
3204 TODO;
3205 break;
3206 }
3207 xmlXPathFreeObject(val);
3208 if (res == NULL)
3209 return(xmlXPathNewCString(""));
3210 return(xmlXPathWrapString(res));
3211}
3212
3213/**
3214 * xmlXPathCastBooleanToNumber:
3215 * @val: a boolean
3216 *
3217 * Converts a boolean to its number value
3218 *
3219 * Returns the number value
3220 */
3221double
3222xmlXPathCastBooleanToNumber(int val) {
3223 if (val)
3224 return(1.0);
3225 return(0.0);
3226}
3227
3228/**
3229 * xmlXPathCastStringToNumber:
3230 * @val: a string
3231 *
3232 * Converts a string to its number value
3233 *
3234 * Returns the number value
3235 */
3236double
3237xmlXPathCastStringToNumber(const xmlChar * val) {
3238 return(xmlXPathStringEvalNumber(val));
3239}
3240
3241/**
3242 * xmlXPathCastNodeToNumber:
3243 * @node: a node
3244 *
3245 * Converts a node to its number value
3246 *
3247 * Returns the number value
3248 */
3249double
3250xmlXPathCastNodeToNumber (xmlNodePtr node) {
3251 xmlChar *strval;
3252 double ret;
3253
3254 if (node == NULL)
3255 return(xmlXPathNAN);
3256 strval = xmlXPathCastNodeToString(node);
3257 if (strval == NULL)
3258 return(xmlXPathNAN);
3259 ret = xmlXPathCastStringToNumber(strval);
3260 xmlFree(strval);
3261
3262 return(ret);
3263}
3264
3265/**
3266 * xmlXPathCastNodeSetToNumber:
3267 * @ns: a node-set
3268 *
3269 * Converts a node-set to its number value
3270 *
3271 * Returns the number value
3272 */
3273double
3274xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3275 xmlChar *str;
3276 double ret;
3277
3278 if (ns == NULL)
3279 return(xmlXPathNAN);
3280 str = xmlXPathCastNodeSetToString(ns);
3281 ret = xmlXPathCastStringToNumber(str);
3282 xmlFree(str);
3283 return(ret);
3284}
3285
3286/**
3287 * xmlXPathCastToNumber:
3288 * @val: an XPath object
3289 *
3290 * Converts an XPath object to its number value
3291 *
3292 * Returns the number value
3293 */
3294double
3295xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3296 double ret = 0.0;
3297
3298 if (val == NULL)
3299 return(xmlXPathNAN);
3300 switch (val->type) {
3301 case XPATH_UNDEFINED:
3302#ifdef DEGUB_EXPR
3303 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3304#endif
3305 ret = xmlXPathNAN;
3306 break;
3307 case XPATH_XSLT_TREE:
3308 case XPATH_NODESET:
3309 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3310 break;
3311 case XPATH_STRING:
3312 ret = xmlXPathCastStringToNumber(val->stringval);
3313 break;
3314 case XPATH_NUMBER:
3315 ret = val->floatval;
3316 break;
3317 case XPATH_BOOLEAN:
3318 ret = xmlXPathCastBooleanToNumber(val->boolval);
3319 break;
3320 case XPATH_USERS:
3321 case XPATH_POINT:
3322 case XPATH_RANGE:
3323 case XPATH_LOCATIONSET:
3324 TODO;
3325 ret = xmlXPathNAN;
3326 break;
3327 }
3328 return(ret);
3329}
3330
3331/**
3332 * xmlXPathConvertNumber:
3333 * @val: an XPath object
3334 *
3335 * Converts an existing object to its number() equivalent
3336 *
3337 * Returns the new object, the old one is freed (or the operation
3338 * is done directly on @val)
3339 */
3340xmlXPathObjectPtr
3341xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3342 xmlXPathObjectPtr ret;
3343
3344 if (val == NULL)
3345 return(xmlXPathNewFloat(0.0));
3346 if (val->type == XPATH_NUMBER)
3347 return(val);
3348 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3349 xmlXPathFreeObject(val);
3350 return(ret);
3351}
3352
3353/**
3354 * xmlXPathCastNumberToBoolean:
3355 * @val: a number
3356 *
3357 * Converts a number to its boolean value
3358 *
3359 * Returns the boolean value
3360 */
3361int
3362xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003363 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003364 return(0);
3365 return(1);
3366}
3367
3368/**
3369 * xmlXPathCastStringToBoolean:
3370 * @val: a string
3371 *
3372 * Converts a string to its boolean value
3373 *
3374 * Returns the boolean value
3375 */
3376int
3377xmlXPathCastStringToBoolean (const xmlChar *val) {
3378 if ((val == NULL) || (xmlStrlen(val) == 0))
3379 return(0);
3380 return(1);
3381}
3382
3383/**
3384 * xmlXPathCastNodeSetToBoolean:
3385 * @ns: a node-set
3386 *
3387 * Converts a node-set to its boolean value
3388 *
3389 * Returns the boolean value
3390 */
3391int
3392xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3393 if ((ns == NULL) || (ns->nodeNr == 0))
3394 return(0);
3395 return(1);
3396}
3397
3398/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003399 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003400 * @val: an XPath object
3401 *
3402 * Converts an XPath object to its boolean value
3403 *
3404 * Returns the boolean value
3405 */
3406int
3407xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3408 int ret = 0;
3409
3410 if (val == NULL)
3411 return(0);
3412 switch (val->type) {
3413 case XPATH_UNDEFINED:
3414#ifdef DEBUG_EXPR
3415 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3416#endif
3417 ret = 0;
3418 break;
3419 case XPATH_XSLT_TREE:
3420 case XPATH_NODESET:
3421 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3422 break;
3423 case XPATH_STRING:
3424 ret = xmlXPathCastStringToBoolean(val->stringval);
3425 break;
3426 case XPATH_NUMBER:
3427 ret = xmlXPathCastNumberToBoolean(val->floatval);
3428 break;
3429 case XPATH_BOOLEAN:
3430 ret = val->boolval;
3431 break;
3432 case XPATH_USERS:
3433 case XPATH_POINT:
3434 case XPATH_RANGE:
3435 case XPATH_LOCATIONSET:
3436 TODO;
3437 ret = 0;
3438 break;
3439 }
3440 return(ret);
3441}
3442
3443
3444/**
3445 * xmlXPathConvertBoolean:
3446 * @val: an XPath object
3447 *
3448 * Converts an existing object to its boolean() equivalent
3449 *
3450 * Returns the new object, the old one is freed (or the operation
3451 * is done directly on @val)
3452 */
3453xmlXPathObjectPtr
3454xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3455 xmlXPathObjectPtr ret;
3456
3457 if (val == NULL)
3458 return(xmlXPathNewBoolean(0));
3459 if (val->type == XPATH_BOOLEAN)
3460 return(val);
3461 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3462 xmlXPathFreeObject(val);
3463 return(ret);
3464}
3465
Owen Taylor3473f882001-02-23 17:55:21 +00003466/************************************************************************
3467 * *
3468 * Routines to handle XPath contexts *
3469 * *
3470 ************************************************************************/
3471
3472/**
3473 * xmlXPathNewContext:
3474 * @doc: the XML document
3475 *
3476 * Create a new xmlXPathContext
3477 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003478 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003479 */
3480xmlXPathContextPtr
3481xmlXPathNewContext(xmlDocPtr doc) {
3482 xmlXPathContextPtr ret;
3483
3484 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3485 if (ret == NULL) {
3486 xmlGenericError(xmlGenericErrorContext,
3487 "xmlXPathNewContext: out of memory\n");
3488 return(NULL);
3489 }
3490 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3491 ret->doc = doc;
3492 ret->node = NULL;
3493
3494 ret->varHash = NULL;
3495
3496 ret->nb_types = 0;
3497 ret->max_types = 0;
3498 ret->types = NULL;
3499
3500 ret->funcHash = xmlHashCreate(0);
3501
3502 ret->nb_axis = 0;
3503 ret->max_axis = 0;
3504 ret->axis = NULL;
3505
3506 ret->nsHash = NULL;
3507 ret->user = NULL;
3508
3509 ret->contextSize = -1;
3510 ret->proximityPosition = -1;
3511
3512 xmlXPathRegisterAllFunctions(ret);
3513
3514 return(ret);
3515}
3516
3517/**
3518 * xmlXPathFreeContext:
3519 * @ctxt: the context to free
3520 *
3521 * Free up an xmlXPathContext
3522 */
3523void
3524xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3525 xmlXPathRegisteredNsCleanup(ctxt);
3526 xmlXPathRegisteredFuncsCleanup(ctxt);
3527 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003528 xmlFree(ctxt);
3529}
3530
3531/************************************************************************
3532 * *
3533 * Routines to handle XPath parser contexts *
3534 * *
3535 ************************************************************************/
3536
3537#define CHECK_CTXT(ctxt) \
3538 if (ctxt == NULL) { \
3539 xmlGenericError(xmlGenericErrorContext, \
3540 "%s:%d Internal error: ctxt == NULL\n", \
3541 __FILE__, __LINE__); \
3542 } \
3543
3544
3545#define CHECK_CONTEXT(ctxt) \
3546 if (ctxt == NULL) { \
3547 xmlGenericError(xmlGenericErrorContext, \
3548 "%s:%d Internal error: no context\n", \
3549 __FILE__, __LINE__); \
3550 } \
3551 else if (ctxt->doc == NULL) { \
3552 xmlGenericError(xmlGenericErrorContext, \
3553 "%s:%d Internal error: no document\n", \
3554 __FILE__, __LINE__); \
3555 } \
3556 else if (ctxt->doc->children == NULL) { \
3557 xmlGenericError(xmlGenericErrorContext, \
3558 "%s:%d Internal error: document without root\n", \
3559 __FILE__, __LINE__); \
3560 } \
3561
3562
3563/**
3564 * xmlXPathNewParserContext:
3565 * @str: the XPath expression
3566 * @ctxt: the XPath context
3567 *
3568 * Create a new xmlXPathParserContext
3569 *
3570 * Returns the xmlXPathParserContext just allocated.
3571 */
3572xmlXPathParserContextPtr
3573xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3574 xmlXPathParserContextPtr ret;
3575
3576 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3577 if (ret == NULL) {
3578 xmlGenericError(xmlGenericErrorContext,
3579 "xmlXPathNewParserContext: out of memory\n");
3580 return(NULL);
3581 }
3582 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3583 ret->cur = ret->base = str;
3584 ret->context = ctxt;
3585
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003586 ret->comp = xmlXPathNewCompExpr();
3587 if (ret->comp == NULL) {
3588 xmlFree(ret->valueTab);
3589 xmlFree(ret);
3590 return(NULL);
3591 }
3592
3593 return(ret);
3594}
3595
3596/**
3597 * xmlXPathCompParserContext:
3598 * @comp: the XPath compiled expression
3599 * @ctxt: the XPath context
3600 *
3601 * Create a new xmlXPathParserContext when processing a compiled expression
3602 *
3603 * Returns the xmlXPathParserContext just allocated.
3604 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003605static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003606xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3607 xmlXPathParserContextPtr ret;
3608
3609 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3610 if (ret == NULL) {
3611 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003612 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003613 return(NULL);
3614 }
3615 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3616
Owen Taylor3473f882001-02-23 17:55:21 +00003617 /* Allocate the value stack */
3618 ret->valueTab = (xmlXPathObjectPtr *)
3619 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003620 if (ret->valueTab == NULL) {
3621 xmlFree(ret);
3622 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003623 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003624 return(NULL);
3625 }
Owen Taylor3473f882001-02-23 17:55:21 +00003626 ret->valueNr = 0;
3627 ret->valueMax = 10;
3628 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003629
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003630 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003631 ret->comp = comp;
3632
Owen Taylor3473f882001-02-23 17:55:21 +00003633 return(ret);
3634}
3635
3636/**
3637 * xmlXPathFreeParserContext:
3638 * @ctxt: the context to free
3639 *
3640 * Free up an xmlXPathParserContext
3641 */
3642void
3643xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3644 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003645 xmlFree(ctxt->valueTab);
3646 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003647 if (ctxt->comp)
3648 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003649 xmlFree(ctxt);
3650}
3651
3652/************************************************************************
3653 * *
3654 * The implicit core function library *
3655 * *
3656 ************************************************************************/
3657
Owen Taylor3473f882001-02-23 17:55:21 +00003658/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003659 * xmlXPathNodeStringHash:
3660 * @node: a node pointer
3661 *
3662 * Function computing the beginning of the string value of the node,
3663 * used to speed up comparisons
3664 *
3665 * Returns an int usable as a hash
3666 */
3667static unsigned int
3668xmlXPathNodeValHash(xmlNodePtr node) {
3669 int len = 2;
3670 const xmlChar * string = NULL;
3671 xmlNodePtr tmp = NULL;
3672 unsigned int ret = 0;
3673
3674 if (node == NULL)
3675 return(0);
3676
3677
3678 switch (node->type) {
3679 case XML_COMMENT_NODE:
3680 case XML_PI_NODE:
3681 case XML_CDATA_SECTION_NODE:
3682 case XML_TEXT_NODE:
3683 string = node->content;
3684 if (string == NULL)
3685 return(0);
3686 if (string[0] == 0)
3687 return(0);
3688 return(((unsigned int) string[0]) +
3689 (((unsigned int) string[1]) << 8));
3690 case XML_NAMESPACE_DECL:
3691 string = ((xmlNsPtr)node)->href;
3692 if (string == NULL)
3693 return(0);
3694 if (string[0] == 0)
3695 return(0);
3696 return(((unsigned int) string[0]) +
3697 (((unsigned int) string[1]) << 8));
3698 case XML_ATTRIBUTE_NODE:
3699 tmp = ((xmlAttrPtr) node)->children;
3700 break;
3701 case XML_ELEMENT_NODE:
3702 tmp = node->children;
3703 break;
3704 default:
3705 return(0);
3706 }
3707 while (tmp != NULL) {
3708 switch (tmp->type) {
3709 case XML_COMMENT_NODE:
3710 case XML_PI_NODE:
3711 case XML_CDATA_SECTION_NODE:
3712 case XML_TEXT_NODE:
3713 string = tmp->content;
3714 break;
3715 case XML_NAMESPACE_DECL:
3716 string = ((xmlNsPtr)tmp)->href;
3717 break;
3718 default:
3719 break;
3720 }
3721 if ((string != NULL) && (string[0] != 0)) {
3722 if (string[0] == 0)
3723 return(0);
3724 if (len == 1) {
3725 return(ret + (((unsigned int) string[0]) << 8));
3726 }
3727 if (string[1] == 0) {
3728 len = 1;
3729 ret = (unsigned int) string[0];
3730 } else {
3731 return(((unsigned int) string[0]) +
3732 (((unsigned int) string[1]) << 8));
3733 }
3734 }
3735 /*
3736 * Skip to next node
3737 */
3738 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3739 if (tmp->children->type != XML_ENTITY_DECL) {
3740 tmp = tmp->children;
3741 continue;
3742 }
3743 }
3744 if (tmp == node)
3745 break;
3746
3747 if (tmp->next != NULL) {
3748 tmp = tmp->next;
3749 continue;
3750 }
3751
3752 do {
3753 tmp = tmp->parent;
3754 if (tmp == NULL)
3755 break;
3756 if (tmp == node) {
3757 tmp = NULL;
3758 break;
3759 }
3760 if (tmp->next != NULL) {
3761 tmp = tmp->next;
3762 break;
3763 }
3764 } while (tmp != NULL);
3765 }
3766 return(ret);
3767}
3768
3769/**
3770 * xmlXPathStringHash:
3771 * @string: a string
3772 *
3773 * Function computing the beginning of the string value of the node,
3774 * used to speed up comparisons
3775 *
3776 * Returns an int usable as a hash
3777 */
3778static unsigned int
3779xmlXPathStringHash(const xmlChar * string) {
3780 if (string == NULL)
3781 return((unsigned int) 0);
3782 if (string[0] == 0)
3783 return(0);
3784 return(((unsigned int) string[0]) +
3785 (((unsigned int) string[1]) << 8));
3786}
3787
3788/**
Owen Taylor3473f882001-02-23 17:55:21 +00003789 * xmlXPathCompareNodeSetFloat:
3790 * @ctxt: the XPath Parser context
3791 * @inf: less than (1) or greater than (0)
3792 * @strict: is the comparison strict
3793 * @arg: the node set
3794 * @f: the value
3795 *
3796 * Implement the compare operation between a nodeset and a number
3797 * @ns < @val (1, 1, ...
3798 * @ns <= @val (1, 0, ...
3799 * @ns > @val (0, 1, ...
3800 * @ns >= @val (0, 0, ...
3801 *
3802 * If one object to be compared is a node-set and the other is a number,
3803 * then the comparison will be true if and only if there is a node in the
3804 * node-set such that the result of performing the comparison on the number
3805 * to be compared and on the result of converting the string-value of that
3806 * node to a number using the number function is true.
3807 *
3808 * Returns 0 or 1 depending on the results of the test.
3809 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003810static int
Owen Taylor3473f882001-02-23 17:55:21 +00003811xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3812 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3813 int i, ret = 0;
3814 xmlNodeSetPtr ns;
3815 xmlChar *str2;
3816
3817 if ((f == NULL) || (arg == NULL) ||
3818 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3819 xmlXPathFreeObject(arg);
3820 xmlXPathFreeObject(f);
3821 return(0);
3822 }
3823 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003824 if (ns != NULL) {
3825 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003826 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003827 if (str2 != NULL) {
3828 valuePush(ctxt,
3829 xmlXPathNewString(str2));
3830 xmlFree(str2);
3831 xmlXPathNumberFunction(ctxt, 1);
3832 valuePush(ctxt, xmlXPathObjectCopy(f));
3833 ret = xmlXPathCompareValues(ctxt, inf, strict);
3834 if (ret)
3835 break;
3836 }
3837 }
Owen Taylor3473f882001-02-23 17:55:21 +00003838 }
3839 xmlXPathFreeObject(arg);
3840 xmlXPathFreeObject(f);
3841 return(ret);
3842}
3843
3844/**
3845 * xmlXPathCompareNodeSetString:
3846 * @ctxt: the XPath Parser context
3847 * @inf: less than (1) or greater than (0)
3848 * @strict: is the comparison strict
3849 * @arg: the node set
3850 * @s: the value
3851 *
3852 * Implement the compare operation between a nodeset and a string
3853 * @ns < @val (1, 1, ...
3854 * @ns <= @val (1, 0, ...
3855 * @ns > @val (0, 1, ...
3856 * @ns >= @val (0, 0, ...
3857 *
3858 * If one object to be compared is a node-set and the other is a string,
3859 * then the comparison will be true if and only if there is a node in
3860 * the node-set such that the result of performing the comparison on the
3861 * string-value of the node and the other string is true.
3862 *
3863 * Returns 0 or 1 depending on the results of the test.
3864 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003865static int
Owen Taylor3473f882001-02-23 17:55:21 +00003866xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3867 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3868 int i, ret = 0;
3869 xmlNodeSetPtr ns;
3870 xmlChar *str2;
3871
3872 if ((s == NULL) || (arg == NULL) ||
3873 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3874 xmlXPathFreeObject(arg);
3875 xmlXPathFreeObject(s);
3876 return(0);
3877 }
3878 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003879 if (ns != NULL) {
3880 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003881 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003882 if (str2 != NULL) {
3883 valuePush(ctxt,
3884 xmlXPathNewString(str2));
3885 xmlFree(str2);
3886 valuePush(ctxt, xmlXPathObjectCopy(s));
3887 ret = xmlXPathCompareValues(ctxt, inf, strict);
3888 if (ret)
3889 break;
3890 }
3891 }
Owen Taylor3473f882001-02-23 17:55:21 +00003892 }
3893 xmlXPathFreeObject(arg);
3894 xmlXPathFreeObject(s);
3895 return(ret);
3896}
3897
3898/**
3899 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003900 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003901 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003902 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00003903 * @arg2: the second node set object
3904 *
3905 * Implement the compare operation on nodesets:
3906 *
3907 * If both objects to be compared are node-sets, then the comparison
3908 * will be true if and only if there is a node in the first node-set
3909 * and a node in the second node-set such that the result of performing
3910 * the comparison on the string-values of the two nodes is true.
3911 * ....
3912 * When neither object to be compared is a node-set and the operator
3913 * is <=, <, >= or >, then the objects are compared by converting both
3914 * objects to numbers and comparing the numbers according to IEEE 754.
3915 * ....
3916 * The number function converts its argument to a number as follows:
3917 * - a string that consists of optional whitespace followed by an
3918 * optional minus sign followed by a Number followed by whitespace
3919 * is converted to the IEEE 754 number that is nearest (according
3920 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3921 * represented by the string; any other string is converted to NaN
3922 *
3923 * Conclusion all nodes need to be converted first to their string value
3924 * and then the comparison must be done when possible
3925 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003926static int
3927xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003928 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3929 int i, j, init = 0;
3930 double val1;
3931 double *values2;
3932 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003933 xmlNodeSetPtr ns1;
3934 xmlNodeSetPtr ns2;
3935
3936 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003937 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3938 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003939 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003940 }
Owen Taylor3473f882001-02-23 17:55:21 +00003941 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003942 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3943 xmlXPathFreeObject(arg1);
3944 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003945 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003946 }
Owen Taylor3473f882001-02-23 17:55:21 +00003947
3948 ns1 = arg1->nodesetval;
3949 ns2 = arg2->nodesetval;
3950
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003951 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003952 xmlXPathFreeObject(arg1);
3953 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003954 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003955 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003956 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003957 xmlXPathFreeObject(arg1);
3958 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003959 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003960 }
Owen Taylor3473f882001-02-23 17:55:21 +00003961
3962 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3963 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003964 xmlXPathFreeObject(arg1);
3965 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003966 return(0);
3967 }
3968 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003969 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00003970 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003971 continue;
3972 for (j = 0;j < ns2->nodeNr;j++) {
3973 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003974 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003975 }
Daniel Veillardcda96922001-08-21 10:56:31 +00003976 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003977 continue;
3978 if (inf && strict)
3979 ret = (val1 < values2[j]);
3980 else if (inf && !strict)
3981 ret = (val1 <= values2[j]);
3982 else if (!inf && strict)
3983 ret = (val1 > values2[j]);
3984 else if (!inf && !strict)
3985 ret = (val1 >= values2[j]);
3986 if (ret)
3987 break;
3988 }
3989 if (ret)
3990 break;
3991 init = 1;
3992 }
3993 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003994 xmlXPathFreeObject(arg1);
3995 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003996 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003997}
3998
3999/**
4000 * xmlXPathCompareNodeSetValue:
4001 * @ctxt: the XPath Parser context
4002 * @inf: less than (1) or greater than (0)
4003 * @strict: is the comparison strict
4004 * @arg: the node set
4005 * @val: the value
4006 *
4007 * Implement the compare operation between a nodeset and a value
4008 * @ns < @val (1, 1, ...
4009 * @ns <= @val (1, 0, ...
4010 * @ns > @val (0, 1, ...
4011 * @ns >= @val (0, 0, ...
4012 *
4013 * If one object to be compared is a node-set and the other is a boolean,
4014 * then the comparison will be true if and only if the result of performing
4015 * the comparison on the boolean and on the result of converting
4016 * the node-set to a boolean using the boolean function is true.
4017 *
4018 * Returns 0 or 1 depending on the results of the test.
4019 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004020static int
Owen Taylor3473f882001-02-23 17:55:21 +00004021xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4022 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4023 if ((val == NULL) || (arg == NULL) ||
4024 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4025 return(0);
4026
4027 switch(val->type) {
4028 case XPATH_NUMBER:
4029 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4030 case XPATH_NODESET:
4031 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004032 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004033 case XPATH_STRING:
4034 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4035 case XPATH_BOOLEAN:
4036 valuePush(ctxt, arg);
4037 xmlXPathBooleanFunction(ctxt, 1);
4038 valuePush(ctxt, val);
4039 return(xmlXPathCompareValues(ctxt, inf, strict));
4040 default:
4041 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004042 }
4043 return(0);
4044}
4045
4046/**
4047 * xmlXPathEqualNodeSetString
4048 * @arg: the nodeset object argument
4049 * @str: the string to compare to.
4050 *
4051 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4052 * If one object to be compared is a node-set and the other is a string,
4053 * then the comparison will be true if and only if there is a node in
4054 * the node-set such that the result of performing the comparison on the
4055 * string-value of the node and the other string is true.
4056 *
4057 * Returns 0 or 1 depending on the results of the test.
4058 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004059static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00004060xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
4061{
Owen Taylor3473f882001-02-23 17:55:21 +00004062 int i;
4063 xmlNodeSetPtr ns;
4064 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004065 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004066
4067 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004068 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4069 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004070 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004071 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004072 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004073 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004074 if (ns->nodeNr <= 0) {
4075 if (hash == 0)
4076 return(1);
4077 return(0);
4078 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004079 for (i = 0; i < ns->nodeNr; i++) {
4080 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4081 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4082 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4083 xmlFree(str2);
4084 return (1);
4085 }
4086 if (str2 != NULL)
4087 xmlFree(str2);
4088 }
Owen Taylor3473f882001-02-23 17:55:21 +00004089 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004090 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004091}
4092
4093/**
4094 * xmlXPathEqualNodeSetFloat
4095 * @arg: the nodeset object argument
4096 * @f: the float to compare to
4097 *
4098 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4099 * If one object to be compared is a node-set and the other is a number,
4100 * then the comparison will be true if and only if there is a node in
4101 * the node-set such that the result of performing the comparison on the
4102 * number to be compared and on the result of converting the string-value
4103 * of that node to a number using the number function is true.
4104 *
4105 * Returns 0 or 1 depending on the results of the test.
4106 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004107static int
Owen Taylor3473f882001-02-23 17:55:21 +00004108xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
4109 char buf[100] = "";
4110
4111 if ((arg == NULL) ||
4112 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4113 return(0);
4114
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004115 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00004116 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
4117}
4118
4119
4120/**
4121 * xmlXPathEqualNodeSets
4122 * @arg1: first nodeset object argument
4123 * @arg2: second nodeset object argument
4124 *
4125 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
4126 * If both objects to be compared are node-sets, then the comparison
4127 * will be true if and only if there is a node in the first node-set and
4128 * a node in the second node-set such that the result of performing the
4129 * comparison on the string-values of the two nodes is true.
4130 *
4131 * (needless to say, this is a costly operation)
4132 *
4133 * Returns 0 or 1 depending on the results of the test.
4134 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004135static int
Owen Taylor3473f882001-02-23 17:55:21 +00004136xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4137 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004138 unsigned int *hashs1;
4139 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004140 xmlChar **values1;
4141 xmlChar **values2;
4142 int ret = 0;
4143 xmlNodeSetPtr ns1;
4144 xmlNodeSetPtr ns2;
4145
4146 if ((arg1 == NULL) ||
4147 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4148 return(0);
4149 if ((arg2 == NULL) ||
4150 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4151 return(0);
4152
4153 ns1 = arg1->nodesetval;
4154 ns2 = arg2->nodesetval;
4155
Daniel Veillard911f49a2001-04-07 15:39:35 +00004156 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004157 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004158 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004159 return(0);
4160
4161 /*
4162 * check if there is a node pertaining to both sets
4163 */
4164 for (i = 0;i < ns1->nodeNr;i++)
4165 for (j = 0;j < ns2->nodeNr;j++)
4166 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4167 return(1);
4168
4169 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4170 if (values1 == NULL)
4171 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004172 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4173 if (hashs1 == NULL) {
4174 xmlFree(values1);
4175 return(0);
4176 }
Owen Taylor3473f882001-02-23 17:55:21 +00004177 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4178 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4179 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004180 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004181 xmlFree(values1);
4182 return(0);
4183 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004184 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4185 if (hashs2 == NULL) {
4186 xmlFree(hashs1);
4187 xmlFree(values1);
4188 xmlFree(values2);
4189 return(0);
4190 }
Owen Taylor3473f882001-02-23 17:55:21 +00004191 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4192 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004193 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004194 for (j = 0;j < ns2->nodeNr;j++) {
4195 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004196 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4197 if (hashs1[i] == hashs2[j]) {
4198 if (values1[i] == NULL)
4199 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4200 if (values2[j] == NULL)
4201 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4202 ret = xmlStrEqual(values1[i], values2[j]);
4203 if (ret)
4204 break;
4205 }
Owen Taylor3473f882001-02-23 17:55:21 +00004206 }
4207 if (ret)
4208 break;
4209 }
4210 for (i = 0;i < ns1->nodeNr;i++)
4211 if (values1[i] != NULL)
4212 xmlFree(values1[i]);
4213 for (j = 0;j < ns2->nodeNr;j++)
4214 if (values2[j] != NULL)
4215 xmlFree(values2[j]);
4216 xmlFree(values1);
4217 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004218 xmlFree(hashs1);
4219 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004220 return(ret);
4221}
4222
4223/**
4224 * xmlXPathEqualValues:
4225 * @ctxt: the XPath Parser context
4226 *
4227 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4228 *
4229 * Returns 0 or 1 depending on the results of the test.
4230 */
4231int
4232xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4233 xmlXPathObjectPtr arg1, arg2;
4234 int ret = 0;
4235
4236 arg1 = valuePop(ctxt);
4237 if (arg1 == NULL)
4238 XP_ERROR0(XPATH_INVALID_OPERAND);
4239
4240 arg2 = valuePop(ctxt);
4241 if (arg2 == NULL) {
4242 xmlXPathFreeObject(arg1);
4243 XP_ERROR0(XPATH_INVALID_OPERAND);
4244 }
4245
4246 if (arg1 == arg2) {
4247#ifdef DEBUG_EXPR
4248 xmlGenericError(xmlGenericErrorContext,
4249 "Equal: by pointer\n");
4250#endif
4251 return(1);
4252 }
4253
4254 switch (arg1->type) {
4255 case XPATH_UNDEFINED:
4256#ifdef DEBUG_EXPR
4257 xmlGenericError(xmlGenericErrorContext,
4258 "Equal: undefined\n");
4259#endif
4260 break;
4261 case XPATH_XSLT_TREE:
4262 case XPATH_NODESET:
4263 switch (arg2->type) {
4264 case XPATH_UNDEFINED:
4265#ifdef DEBUG_EXPR
4266 xmlGenericError(xmlGenericErrorContext,
4267 "Equal: undefined\n");
4268#endif
4269 break;
4270 case XPATH_XSLT_TREE:
4271 case XPATH_NODESET:
4272 ret = xmlXPathEqualNodeSets(arg1, arg2);
4273 break;
4274 case XPATH_BOOLEAN:
4275 if ((arg1->nodesetval == NULL) ||
4276 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4277 else
4278 ret = 1;
4279 ret = (ret == arg2->boolval);
4280 break;
4281 case XPATH_NUMBER:
4282 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4283 break;
4284 case XPATH_STRING:
4285 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4286 break;
4287 case XPATH_USERS:
4288 case XPATH_POINT:
4289 case XPATH_RANGE:
4290 case XPATH_LOCATIONSET:
4291 TODO
4292 break;
4293 }
4294 break;
4295 case XPATH_BOOLEAN:
4296 switch (arg2->type) {
4297 case XPATH_UNDEFINED:
4298#ifdef DEBUG_EXPR
4299 xmlGenericError(xmlGenericErrorContext,
4300 "Equal: undefined\n");
4301#endif
4302 break;
4303 case XPATH_NODESET:
4304 case XPATH_XSLT_TREE:
4305 if ((arg2->nodesetval == NULL) ||
4306 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4307 else
4308 ret = 1;
4309 break;
4310 case XPATH_BOOLEAN:
4311#ifdef DEBUG_EXPR
4312 xmlGenericError(xmlGenericErrorContext,
4313 "Equal: %d boolean %d \n",
4314 arg1->boolval, arg2->boolval);
4315#endif
4316 ret = (arg1->boolval == arg2->boolval);
4317 break;
4318 case XPATH_NUMBER:
4319 if (arg2->floatval) ret = 1;
4320 else ret = 0;
4321 ret = (arg1->boolval == ret);
4322 break;
4323 case XPATH_STRING:
4324 if ((arg2->stringval == NULL) ||
4325 (arg2->stringval[0] == 0)) ret = 0;
4326 else
4327 ret = 1;
4328 ret = (arg1->boolval == ret);
4329 break;
4330 case XPATH_USERS:
4331 case XPATH_POINT:
4332 case XPATH_RANGE:
4333 case XPATH_LOCATIONSET:
4334 TODO
4335 break;
4336 }
4337 break;
4338 case XPATH_NUMBER:
4339 switch (arg2->type) {
4340 case XPATH_UNDEFINED:
4341#ifdef DEBUG_EXPR
4342 xmlGenericError(xmlGenericErrorContext,
4343 "Equal: undefined\n");
4344#endif
4345 break;
4346 case XPATH_NODESET:
4347 case XPATH_XSLT_TREE:
4348 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4349 break;
4350 case XPATH_BOOLEAN:
4351 if (arg1->floatval) ret = 1;
4352 else ret = 0;
4353 ret = (arg2->boolval == ret);
4354 break;
4355 case XPATH_STRING:
4356 valuePush(ctxt, arg2);
4357 xmlXPathNumberFunction(ctxt, 1);
4358 arg2 = valuePop(ctxt);
4359 /* no break on purpose */
4360 case XPATH_NUMBER:
4361 ret = (arg1->floatval == arg2->floatval);
4362 break;
4363 case XPATH_USERS:
4364 case XPATH_POINT:
4365 case XPATH_RANGE:
4366 case XPATH_LOCATIONSET:
4367 TODO
4368 break;
4369 }
4370 break;
4371 case XPATH_STRING:
4372 switch (arg2->type) {
4373 case XPATH_UNDEFINED:
4374#ifdef DEBUG_EXPR
4375 xmlGenericError(xmlGenericErrorContext,
4376 "Equal: undefined\n");
4377#endif
4378 break;
4379 case XPATH_NODESET:
4380 case XPATH_XSLT_TREE:
4381 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4382 break;
4383 case XPATH_BOOLEAN:
4384 if ((arg1->stringval == NULL) ||
4385 (arg1->stringval[0] == 0)) ret = 0;
4386 else
4387 ret = 1;
4388 ret = (arg2->boolval == ret);
4389 break;
4390 case XPATH_STRING:
4391 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4392 break;
4393 case XPATH_NUMBER:
4394 valuePush(ctxt, arg1);
4395 xmlXPathNumberFunction(ctxt, 1);
4396 arg1 = valuePop(ctxt);
4397 ret = (arg1->floatval == arg2->floatval);
4398 break;
4399 case XPATH_USERS:
4400 case XPATH_POINT:
4401 case XPATH_RANGE:
4402 case XPATH_LOCATIONSET:
4403 TODO
4404 break;
4405 }
4406 break;
4407 case XPATH_USERS:
4408 case XPATH_POINT:
4409 case XPATH_RANGE:
4410 case XPATH_LOCATIONSET:
4411 TODO
4412 break;
4413 }
4414 xmlXPathFreeObject(arg1);
4415 xmlXPathFreeObject(arg2);
4416 return(ret);
4417}
4418
4419
4420/**
4421 * xmlXPathCompareValues:
4422 * @ctxt: the XPath Parser context
4423 * @inf: less than (1) or greater than (0)
4424 * @strict: is the comparison strict
4425 *
4426 * Implement the compare operation on XPath objects:
4427 * @arg1 < @arg2 (1, 1, ...
4428 * @arg1 <= @arg2 (1, 0, ...
4429 * @arg1 > @arg2 (0, 1, ...
4430 * @arg1 >= @arg2 (0, 0, ...
4431 *
4432 * When neither object to be compared is a node-set and the operator is
4433 * <=, <, >=, >, then the objects are compared by converted both objects
4434 * to numbers and comparing the numbers according to IEEE 754. The <
4435 * comparison will be true if and only if the first number is less than the
4436 * second number. The <= comparison will be true if and only if the first
4437 * number is less than or equal to the second number. The > comparison
4438 * will be true if and only if the first number is greater than the second
4439 * number. The >= comparison will be true if and only if the first number
4440 * is greater than or equal to the second number.
4441 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004442 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004443 */
4444int
4445xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4446 int ret = 0;
4447 xmlXPathObjectPtr arg1, arg2;
4448
4449 arg2 = valuePop(ctxt);
4450 if (arg2 == NULL) {
4451 XP_ERROR0(XPATH_INVALID_OPERAND);
4452 }
4453
4454 arg1 = valuePop(ctxt);
4455 if (arg1 == NULL) {
4456 xmlXPathFreeObject(arg2);
4457 XP_ERROR0(XPATH_INVALID_OPERAND);
4458 }
4459
4460 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4461 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004462 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004463 } else {
4464 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004465 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4466 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004467 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004468 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4469 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004470 }
4471 }
4472 return(ret);
4473 }
4474
4475 if (arg1->type != XPATH_NUMBER) {
4476 valuePush(ctxt, arg1);
4477 xmlXPathNumberFunction(ctxt, 1);
4478 arg1 = valuePop(ctxt);
4479 }
4480 if (arg1->type != XPATH_NUMBER) {
4481 xmlXPathFreeObject(arg1);
4482 xmlXPathFreeObject(arg2);
4483 XP_ERROR0(XPATH_INVALID_OPERAND);
4484 }
4485 if (arg2->type != XPATH_NUMBER) {
4486 valuePush(ctxt, arg2);
4487 xmlXPathNumberFunction(ctxt, 1);
4488 arg2 = valuePop(ctxt);
4489 }
4490 if (arg2->type != XPATH_NUMBER) {
4491 xmlXPathFreeObject(arg1);
4492 xmlXPathFreeObject(arg2);
4493 XP_ERROR0(XPATH_INVALID_OPERAND);
4494 }
4495 /*
4496 * Add tests for infinity and nan
4497 * => feedback on 3.4 for Inf and NaN
4498 */
4499 if (inf && strict)
4500 ret = (arg1->floatval < arg2->floatval);
4501 else if (inf && !strict)
4502 ret = (arg1->floatval <= arg2->floatval);
4503 else if (!inf && strict)
4504 ret = (arg1->floatval > arg2->floatval);
4505 else if (!inf && !strict)
4506 ret = (arg1->floatval >= arg2->floatval);
4507 xmlXPathFreeObject(arg1);
4508 xmlXPathFreeObject(arg2);
4509 return(ret);
4510}
4511
4512/**
4513 * xmlXPathValueFlipSign:
4514 * @ctxt: the XPath Parser context
4515 *
4516 * Implement the unary - operation on an XPath object
4517 * The numeric operators convert their operands to numbers as if
4518 * by calling the number function.
4519 */
4520void
4521xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004522 CAST_TO_NUMBER;
4523 CHECK_TYPE(XPATH_NUMBER);
4524 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004525}
4526
4527/**
4528 * xmlXPathAddValues:
4529 * @ctxt: the XPath Parser context
4530 *
4531 * Implement the add operation on XPath objects:
4532 * The numeric operators convert their operands to numbers as if
4533 * by calling the number function.
4534 */
4535void
4536xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4537 xmlXPathObjectPtr arg;
4538 double val;
4539
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004540 arg = valuePop(ctxt);
4541 if (arg == NULL)
4542 XP_ERROR(XPATH_INVALID_OPERAND);
4543 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004544 xmlXPathFreeObject(arg);
4545
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004546 CAST_TO_NUMBER;
4547 CHECK_TYPE(XPATH_NUMBER);
4548 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004549}
4550
4551/**
4552 * xmlXPathSubValues:
4553 * @ctxt: the XPath Parser context
4554 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004555 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004556 * The numeric operators convert their operands to numbers as if
4557 * by calling the number function.
4558 */
4559void
4560xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4561 xmlXPathObjectPtr arg;
4562 double val;
4563
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004564 arg = valuePop(ctxt);
4565 if (arg == NULL)
4566 XP_ERROR(XPATH_INVALID_OPERAND);
4567 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004568 xmlXPathFreeObject(arg);
4569
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004570 CAST_TO_NUMBER;
4571 CHECK_TYPE(XPATH_NUMBER);
4572 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004573}
4574
4575/**
4576 * xmlXPathMultValues:
4577 * @ctxt: the XPath Parser context
4578 *
4579 * Implement the multiply operation on XPath objects:
4580 * The numeric operators convert their operands to numbers as if
4581 * by calling the number function.
4582 */
4583void
4584xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4585 xmlXPathObjectPtr arg;
4586 double val;
4587
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004588 arg = valuePop(ctxt);
4589 if (arg == NULL)
4590 XP_ERROR(XPATH_INVALID_OPERAND);
4591 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004592 xmlXPathFreeObject(arg);
4593
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004594 CAST_TO_NUMBER;
4595 CHECK_TYPE(XPATH_NUMBER);
4596 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004597}
4598
4599/**
4600 * xmlXPathDivValues:
4601 * @ctxt: the XPath Parser context
4602 *
4603 * Implement the div operation on XPath objects @arg1 / @arg2:
4604 * The numeric operators convert their operands to numbers as if
4605 * by calling the number function.
4606 */
4607void
4608xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4609 xmlXPathObjectPtr arg;
4610 double val;
4611
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004612 arg = valuePop(ctxt);
4613 if (arg == NULL)
4614 XP_ERROR(XPATH_INVALID_OPERAND);
4615 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004616 xmlXPathFreeObject(arg);
4617
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004618 CAST_TO_NUMBER;
4619 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004620 if (val == 0) {
4621 if (ctxt->value->floatval == 0)
4622 ctxt->value->floatval = xmlXPathNAN;
4623 else if (ctxt->value->floatval > 0)
4624 ctxt->value->floatval = xmlXPathPINF;
4625 else if (ctxt->value->floatval < 0)
4626 ctxt->value->floatval = xmlXPathNINF;
4627 } else
4628 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004629}
4630
4631/**
4632 * xmlXPathModValues:
4633 * @ctxt: the XPath Parser context
4634 *
4635 * Implement the mod operation on XPath objects: @arg1 / @arg2
4636 * The numeric operators convert their operands to numbers as if
4637 * by calling the number function.
4638 */
4639void
4640xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4641 xmlXPathObjectPtr arg;
4642 int arg1, arg2;
4643
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004644 arg = valuePop(ctxt);
4645 if (arg == NULL)
4646 XP_ERROR(XPATH_INVALID_OPERAND);
4647 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004648 xmlXPathFreeObject(arg);
4649
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004650 CAST_TO_NUMBER;
4651 CHECK_TYPE(XPATH_NUMBER);
4652 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004653 if (arg2 == 0)
4654 ctxt->value->floatval = xmlXPathNAN;
4655 else
4656 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004657}
4658
4659/************************************************************************
4660 * *
4661 * The traversal functions *
4662 * *
4663 ************************************************************************/
4664
Owen Taylor3473f882001-02-23 17:55:21 +00004665/*
4666 * A traversal function enumerates nodes along an axis.
4667 * Initially it must be called with NULL, and it indicates
4668 * termination on the axis by returning NULL.
4669 */
4670typedef xmlNodePtr (*xmlXPathTraversalFunction)
4671 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4672
4673/**
4674 * xmlXPathNextSelf:
4675 * @ctxt: the XPath Parser context
4676 * @cur: the current node in the traversal
4677 *
4678 * Traversal function for the "self" direction
4679 * The self axis contains just the context node itself
4680 *
4681 * Returns the next element following that axis
4682 */
4683xmlNodePtr
4684xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4685 if (cur == NULL)
4686 return(ctxt->context->node);
4687 return(NULL);
4688}
4689
4690/**
4691 * xmlXPathNextChild:
4692 * @ctxt: the XPath Parser context
4693 * @cur: the current node in the traversal
4694 *
4695 * Traversal function for the "child" direction
4696 * The child axis contains the children of the context node in document order.
4697 *
4698 * Returns the next element following that axis
4699 */
4700xmlNodePtr
4701xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4702 if (cur == NULL) {
4703 if (ctxt->context->node == NULL) return(NULL);
4704 switch (ctxt->context->node->type) {
4705 case XML_ELEMENT_NODE:
4706 case XML_TEXT_NODE:
4707 case XML_CDATA_SECTION_NODE:
4708 case XML_ENTITY_REF_NODE:
4709 case XML_ENTITY_NODE:
4710 case XML_PI_NODE:
4711 case XML_COMMENT_NODE:
4712 case XML_NOTATION_NODE:
4713 case XML_DTD_NODE:
4714 return(ctxt->context->node->children);
4715 case XML_DOCUMENT_NODE:
4716 case XML_DOCUMENT_TYPE_NODE:
4717 case XML_DOCUMENT_FRAG_NODE:
4718 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004719#ifdef LIBXML_DOCB_ENABLED
4720 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004721#endif
4722 return(((xmlDocPtr) ctxt->context->node)->children);
4723 case XML_ELEMENT_DECL:
4724 case XML_ATTRIBUTE_DECL:
4725 case XML_ENTITY_DECL:
4726 case XML_ATTRIBUTE_NODE:
4727 case XML_NAMESPACE_DECL:
4728 case XML_XINCLUDE_START:
4729 case XML_XINCLUDE_END:
4730 return(NULL);
4731 }
4732 return(NULL);
4733 }
4734 if ((cur->type == XML_DOCUMENT_NODE) ||
4735 (cur->type == XML_HTML_DOCUMENT_NODE))
4736 return(NULL);
4737 return(cur->next);
4738}
4739
4740/**
4741 * xmlXPathNextDescendant:
4742 * @ctxt: the XPath Parser context
4743 * @cur: the current node in the traversal
4744 *
4745 * Traversal function for the "descendant" direction
4746 * the descendant axis contains the descendants of the context node in document
4747 * order; a descendant is a child or a child of a child and so on.
4748 *
4749 * Returns the next element following that axis
4750 */
4751xmlNodePtr
4752xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4753 if (cur == NULL) {
4754 if (ctxt->context->node == NULL)
4755 return(NULL);
4756 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4757 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4758 return(NULL);
4759
4760 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4761 return(ctxt->context->doc->children);
4762 return(ctxt->context->node->children);
4763 }
4764
Daniel Veillard567e1b42001-08-01 15:53:47 +00004765 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004766 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004767 return(cur->children);
4768 }
4769
4770 if (cur == ctxt->context->node) return(NULL);
4771
Owen Taylor3473f882001-02-23 17:55:21 +00004772 if (cur->next != NULL) return(cur->next);
4773
4774 do {
4775 cur = cur->parent;
4776 if (cur == NULL) return(NULL);
4777 if (cur == ctxt->context->node) return(NULL);
4778 if (cur->next != NULL) {
4779 cur = cur->next;
4780 return(cur);
4781 }
4782 } while (cur != NULL);
4783 return(cur);
4784}
4785
4786/**
4787 * xmlXPathNextDescendantOrSelf:
4788 * @ctxt: the XPath Parser context
4789 * @cur: the current node in the traversal
4790 *
4791 * Traversal function for the "descendant-or-self" direction
4792 * the descendant-or-self axis contains the context node and the descendants
4793 * of the context node in document order; thus the context node is the first
4794 * node on the axis, and the first child of the context node is the second node
4795 * on the axis
4796 *
4797 * Returns the next element following that axis
4798 */
4799xmlNodePtr
4800xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4801 if (cur == NULL) {
4802 if (ctxt->context->node == NULL)
4803 return(NULL);
4804 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4805 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4806 return(NULL);
4807 return(ctxt->context->node);
4808 }
4809
4810 return(xmlXPathNextDescendant(ctxt, cur));
4811}
4812
4813/**
4814 * xmlXPathNextParent:
4815 * @ctxt: the XPath Parser context
4816 * @cur: the current node in the traversal
4817 *
4818 * Traversal function for the "parent" direction
4819 * The parent axis contains the parent of the context node, if there is one.
4820 *
4821 * Returns the next element following that axis
4822 */
4823xmlNodePtr
4824xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4825 /*
4826 * the parent of an attribute or namespace node is the element
4827 * to which the attribute or namespace node is attached
4828 * Namespace handling !!!
4829 */
4830 if (cur == NULL) {
4831 if (ctxt->context->node == NULL) return(NULL);
4832 switch (ctxt->context->node->type) {
4833 case XML_ELEMENT_NODE:
4834 case XML_TEXT_NODE:
4835 case XML_CDATA_SECTION_NODE:
4836 case XML_ENTITY_REF_NODE:
4837 case XML_ENTITY_NODE:
4838 case XML_PI_NODE:
4839 case XML_COMMENT_NODE:
4840 case XML_NOTATION_NODE:
4841 case XML_DTD_NODE:
4842 case XML_ELEMENT_DECL:
4843 case XML_ATTRIBUTE_DECL:
4844 case XML_XINCLUDE_START:
4845 case XML_XINCLUDE_END:
4846 case XML_ENTITY_DECL:
4847 if (ctxt->context->node->parent == NULL)
4848 return((xmlNodePtr) ctxt->context->doc);
4849 return(ctxt->context->node->parent);
4850 case XML_ATTRIBUTE_NODE: {
4851 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4852
4853 return(att->parent);
4854 }
4855 case XML_DOCUMENT_NODE:
4856 case XML_DOCUMENT_TYPE_NODE:
4857 case XML_DOCUMENT_FRAG_NODE:
4858 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004859#ifdef LIBXML_DOCB_ENABLED
4860 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004861#endif
4862 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004863 case XML_NAMESPACE_DECL: {
4864 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
4865
4866 if ((ns->next != NULL) &&
4867 (ns->next->type != XML_NAMESPACE_DECL))
4868 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00004869 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004870 }
Owen Taylor3473f882001-02-23 17:55:21 +00004871 }
4872 }
4873 return(NULL);
4874}
4875
4876/**
4877 * xmlXPathNextAncestor:
4878 * @ctxt: the XPath Parser context
4879 * @cur: the current node in the traversal
4880 *
4881 * Traversal function for the "ancestor" direction
4882 * the ancestor axis contains the ancestors of the context node; the ancestors
4883 * of the context node consist of the parent of context node and the parent's
4884 * parent and so on; the nodes are ordered in reverse document order; thus the
4885 * parent is the first node on the axis, and the parent's parent is the second
4886 * node on the axis
4887 *
4888 * Returns the next element following that axis
4889 */
4890xmlNodePtr
4891xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4892 /*
4893 * the parent of an attribute or namespace node is the element
4894 * to which the attribute or namespace node is attached
4895 * !!!!!!!!!!!!!
4896 */
4897 if (cur == NULL) {
4898 if (ctxt->context->node == NULL) return(NULL);
4899 switch (ctxt->context->node->type) {
4900 case XML_ELEMENT_NODE:
4901 case XML_TEXT_NODE:
4902 case XML_CDATA_SECTION_NODE:
4903 case XML_ENTITY_REF_NODE:
4904 case XML_ENTITY_NODE:
4905 case XML_PI_NODE:
4906 case XML_COMMENT_NODE:
4907 case XML_DTD_NODE:
4908 case XML_ELEMENT_DECL:
4909 case XML_ATTRIBUTE_DECL:
4910 case XML_ENTITY_DECL:
4911 case XML_NOTATION_NODE:
4912 case XML_XINCLUDE_START:
4913 case XML_XINCLUDE_END:
4914 if (ctxt->context->node->parent == NULL)
4915 return((xmlNodePtr) ctxt->context->doc);
4916 return(ctxt->context->node->parent);
4917 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004918 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004919
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004920 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004921 }
4922 case XML_DOCUMENT_NODE:
4923 case XML_DOCUMENT_TYPE_NODE:
4924 case XML_DOCUMENT_FRAG_NODE:
4925 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004926#ifdef LIBXML_DOCB_ENABLED
4927 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004928#endif
4929 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004930 case XML_NAMESPACE_DECL: {
4931 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
4932
4933 if ((ns->next != NULL) &&
4934 (ns->next->type != XML_NAMESPACE_DECL))
4935 return((xmlNodePtr) ns->next);
4936 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00004937 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004938 }
Owen Taylor3473f882001-02-23 17:55:21 +00004939 }
4940 return(NULL);
4941 }
4942 if (cur == ctxt->context->doc->children)
4943 return((xmlNodePtr) ctxt->context->doc);
4944 if (cur == (xmlNodePtr) ctxt->context->doc)
4945 return(NULL);
4946 switch (cur->type) {
4947 case XML_ELEMENT_NODE:
4948 case XML_TEXT_NODE:
4949 case XML_CDATA_SECTION_NODE:
4950 case XML_ENTITY_REF_NODE:
4951 case XML_ENTITY_NODE:
4952 case XML_PI_NODE:
4953 case XML_COMMENT_NODE:
4954 case XML_NOTATION_NODE:
4955 case XML_DTD_NODE:
4956 case XML_ELEMENT_DECL:
4957 case XML_ATTRIBUTE_DECL:
4958 case XML_ENTITY_DECL:
4959 case XML_XINCLUDE_START:
4960 case XML_XINCLUDE_END:
4961 return(cur->parent);
4962 case XML_ATTRIBUTE_NODE: {
4963 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4964
4965 return(att->parent);
4966 }
4967 case XML_DOCUMENT_NODE:
4968 case XML_DOCUMENT_TYPE_NODE:
4969 case XML_DOCUMENT_FRAG_NODE:
4970 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004971#ifdef LIBXML_DOCB_ENABLED
4972 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004973#endif
4974 return(NULL);
4975 case XML_NAMESPACE_DECL:
4976 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004977 * this should not hapen a namespace can't be
4978 * the ancestor of another node
Owen Taylor3473f882001-02-23 17:55:21 +00004979 */
4980 return(NULL);
4981 }
4982 return(NULL);
4983}
4984
4985/**
4986 * xmlXPathNextAncestorOrSelf:
4987 * @ctxt: the XPath Parser context
4988 * @cur: the current node in the traversal
4989 *
4990 * Traversal function for the "ancestor-or-self" direction
4991 * he ancestor-or-self axis contains the context node and ancestors of
4992 * the context node in reverse document order; thus the context node is
4993 * the first node on the axis, and the context node's parent the second;
4994 * parent here is defined the same as with the parent axis.
4995 *
4996 * Returns the next element following that axis
4997 */
4998xmlNodePtr
4999xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5000 if (cur == NULL)
5001 return(ctxt->context->node);
5002 return(xmlXPathNextAncestor(ctxt, cur));
5003}
5004
5005/**
5006 * xmlXPathNextFollowingSibling:
5007 * @ctxt: the XPath Parser context
5008 * @cur: the current node in the traversal
5009 *
5010 * Traversal function for the "following-sibling" direction
5011 * The following-sibling axis contains the following siblings of the context
5012 * node in document order.
5013 *
5014 * Returns the next element following that axis
5015 */
5016xmlNodePtr
5017xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5018 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5019 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5020 return(NULL);
5021 if (cur == (xmlNodePtr) ctxt->context->doc)
5022 return(NULL);
5023 if (cur == NULL)
5024 return(ctxt->context->node->next);
5025 return(cur->next);
5026}
5027
5028/**
5029 * xmlXPathNextPrecedingSibling:
5030 * @ctxt: the XPath Parser context
5031 * @cur: the current node in the traversal
5032 *
5033 * Traversal function for the "preceding-sibling" direction
5034 * The preceding-sibling axis contains the preceding siblings of the context
5035 * node in reverse document order; the first preceding sibling is first on the
5036 * axis; the sibling preceding that node is the second on the axis and so on.
5037 *
5038 * Returns the next element following that axis
5039 */
5040xmlNodePtr
5041xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5042 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5043 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5044 return(NULL);
5045 if (cur == (xmlNodePtr) ctxt->context->doc)
5046 return(NULL);
5047 if (cur == NULL)
5048 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005049 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5050 cur = cur->prev;
5051 if (cur == NULL)
5052 return(ctxt->context->node->prev);
5053 }
Owen Taylor3473f882001-02-23 17:55:21 +00005054 return(cur->prev);
5055}
5056
5057/**
5058 * xmlXPathNextFollowing:
5059 * @ctxt: the XPath Parser context
5060 * @cur: the current node in the traversal
5061 *
5062 * Traversal function for the "following" direction
5063 * The following axis contains all nodes in the same document as the context
5064 * node that are after the context node in document order, excluding any
5065 * descendants and excluding attribute nodes and namespace nodes; the nodes
5066 * are ordered in document order
5067 *
5068 * Returns the next element following that axis
5069 */
5070xmlNodePtr
5071xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5072 if (cur != NULL && cur->children != NULL)
5073 return cur->children ;
5074 if (cur == NULL) cur = ctxt->context->node;
5075 if (cur == NULL) return(NULL) ; /* ERROR */
5076 if (cur->next != NULL) return(cur->next) ;
5077 do {
5078 cur = cur->parent;
5079 if (cur == NULL) return(NULL);
5080 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5081 if (cur->next != NULL) return(cur->next);
5082 } while (cur != NULL);
5083 return(cur);
5084}
5085
5086/*
5087 * xmlXPathIsAncestor:
5088 * @ancestor: the ancestor node
5089 * @node: the current node
5090 *
5091 * Check that @ancestor is a @node's ancestor
5092 *
5093 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5094 */
5095static int
5096xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5097 if ((ancestor == NULL) || (node == NULL)) return(0);
5098 /* nodes need to be in the same document */
5099 if (ancestor->doc != node->doc) return(0);
5100 /* avoid searching if ancestor or node is the root node */
5101 if (ancestor == (xmlNodePtr) node->doc) return(1);
5102 if (node == (xmlNodePtr) ancestor->doc) return(0);
5103 while (node->parent != NULL) {
5104 if (node->parent == ancestor)
5105 return(1);
5106 node = node->parent;
5107 }
5108 return(0);
5109}
5110
5111/**
5112 * xmlXPathNextPreceding:
5113 * @ctxt: the XPath Parser context
5114 * @cur: the current node in the traversal
5115 *
5116 * Traversal function for the "preceding" direction
5117 * the preceding axis contains all nodes in the same document as the context
5118 * node that are before the context node in document order, excluding any
5119 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5120 * ordered in reverse document order
5121 *
5122 * Returns the next element following that axis
5123 */
5124xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005125xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5126{
Owen Taylor3473f882001-02-23 17:55:21 +00005127 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005128 cur = ctxt->context->node;
5129 if (cur == NULL)
5130 return (NULL);
5131 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5132 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005133 do {
5134 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005135 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5136 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005137 }
5138
5139 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005140 if (cur == NULL)
5141 return (NULL);
5142 if (cur == ctxt->context->doc->children)
5143 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005144 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005145 return (cur);
5146}
5147
5148/**
5149 * xmlXPathNextPrecedingInternal:
5150 * @ctxt: the XPath Parser context
5151 * @cur: the current node in the traversal
5152 *
5153 * Traversal function for the "preceding" direction
5154 * the preceding axis contains all nodes in the same document as the context
5155 * node that are before the context node in document order, excluding any
5156 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5157 * ordered in reverse document order
5158 * This is a faster implementation but internal only since it requires a
5159 * state kept in the parser context: ctxt->ancestor.
5160 *
5161 * Returns the next element following that axis
5162 */
5163static xmlNodePtr
5164xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5165 xmlNodePtr cur)
5166{
5167 if (cur == NULL) {
5168 cur = ctxt->context->node;
5169 if (cur == NULL)
5170 return (NULL);
5171 ctxt->ancestor = cur->parent;
5172 }
5173 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5174 cur = cur->prev;
5175 while (cur->prev == NULL) {
5176 cur = cur->parent;
5177 if (cur == NULL)
5178 return (NULL);
5179 if (cur == ctxt->context->doc->children)
5180 return (NULL);
5181 if (cur != ctxt->ancestor)
5182 return (cur);
5183 ctxt->ancestor = cur->parent;
5184 }
5185 cur = cur->prev;
5186 while (cur->last != NULL)
5187 cur = cur->last;
5188 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005189}
5190
5191/**
5192 * xmlXPathNextNamespace:
5193 * @ctxt: the XPath Parser context
5194 * @cur: the current attribute in the traversal
5195 *
5196 * Traversal function for the "namespace" direction
5197 * the namespace axis contains the namespace nodes of the context node;
5198 * the order of nodes on this axis is implementation-defined; the axis will
5199 * be empty unless the context node is an element
5200 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005201 * We keep the XML namespace node at the end of the list.
5202 *
Owen Taylor3473f882001-02-23 17:55:21 +00005203 * Returns the next element following that axis
5204 */
5205xmlNodePtr
5206xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005207 xmlNodePtr ret;
5208
Owen Taylor3473f882001-02-23 17:55:21 +00005209 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005210 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5211 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005212 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5213 if (ctxt->context->tmpNsList != NULL)
5214 xmlFree(ctxt->context->tmpNsList);
5215 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005216 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005217 if (ctxt->context->tmpNsList == NULL) return(NULL);
5218 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005219 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005220 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5221 if (ret == NULL) {
5222 xmlFree(ctxt->context->tmpNsList);
5223 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005224 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005225 }
5226 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005227}
5228
5229/**
5230 * xmlXPathNextAttribute:
5231 * @ctxt: the XPath Parser context
5232 * @cur: the current attribute in the traversal
5233 *
5234 * Traversal function for the "attribute" direction
5235 * TODO: support DTD inherited default attributes
5236 *
5237 * Returns the next element following that axis
5238 */
5239xmlNodePtr
5240xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005241 if (ctxt->context->node == NULL)
5242 return(NULL);
5243 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5244 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005245 if (cur == NULL) {
5246 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5247 return(NULL);
5248 return((xmlNodePtr)ctxt->context->node->properties);
5249 }
5250 return((xmlNodePtr)cur->next);
5251}
5252
5253/************************************************************************
5254 * *
5255 * NodeTest Functions *
5256 * *
5257 ************************************************************************/
5258
Owen Taylor3473f882001-02-23 17:55:21 +00005259#define IS_FUNCTION 200
5260
Owen Taylor3473f882001-02-23 17:55:21 +00005261
5262/************************************************************************
5263 * *
5264 * Implicit tree core function library *
5265 * *
5266 ************************************************************************/
5267
5268/**
5269 * xmlXPathRoot:
5270 * @ctxt: the XPath Parser context
5271 *
5272 * Initialize the context to the root of the document
5273 */
5274void
5275xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5276 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5277 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5278}
5279
5280/************************************************************************
5281 * *
5282 * The explicit core function library *
5283 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5284 * *
5285 ************************************************************************/
5286
5287
5288/**
5289 * xmlXPathLastFunction:
5290 * @ctxt: the XPath Parser context
5291 * @nargs: the number of arguments
5292 *
5293 * Implement the last() XPath function
5294 * number last()
5295 * The last function returns the number of nodes in the context node list.
5296 */
5297void
5298xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5299 CHECK_ARITY(0);
5300 if (ctxt->context->contextSize >= 0) {
5301 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5302#ifdef DEBUG_EXPR
5303 xmlGenericError(xmlGenericErrorContext,
5304 "last() : %d\n", ctxt->context->contextSize);
5305#endif
5306 } else {
5307 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5308 }
5309}
5310
5311/**
5312 * xmlXPathPositionFunction:
5313 * @ctxt: the XPath Parser context
5314 * @nargs: the number of arguments
5315 *
5316 * Implement the position() XPath function
5317 * number position()
5318 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005319 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005320 * will be equal to last().
5321 */
5322void
5323xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5324 CHECK_ARITY(0);
5325 if (ctxt->context->proximityPosition >= 0) {
5326 valuePush(ctxt,
5327 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5328#ifdef DEBUG_EXPR
5329 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5330 ctxt->context->proximityPosition);
5331#endif
5332 } else {
5333 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5334 }
5335}
5336
5337/**
5338 * xmlXPathCountFunction:
5339 * @ctxt: the XPath Parser context
5340 * @nargs: the number of arguments
5341 *
5342 * Implement the count() XPath function
5343 * number count(node-set)
5344 */
5345void
5346xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5347 xmlXPathObjectPtr cur;
5348
5349 CHECK_ARITY(1);
5350 if ((ctxt->value == NULL) ||
5351 ((ctxt->value->type != XPATH_NODESET) &&
5352 (ctxt->value->type != XPATH_XSLT_TREE)))
5353 XP_ERROR(XPATH_INVALID_TYPE);
5354 cur = valuePop(ctxt);
5355
Daniel Veillard911f49a2001-04-07 15:39:35 +00005356 if ((cur == NULL) || (cur->nodesetval == NULL))
5357 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005358 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005359 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005360 } else {
5361 if ((cur->nodesetval->nodeNr != 1) ||
5362 (cur->nodesetval->nodeTab == NULL)) {
5363 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5364 } else {
5365 xmlNodePtr tmp;
5366 int i = 0;
5367
5368 tmp = cur->nodesetval->nodeTab[0];
5369 if (tmp != NULL) {
5370 tmp = tmp->children;
5371 while (tmp != NULL) {
5372 tmp = tmp->next;
5373 i++;
5374 }
5375 }
5376 valuePush(ctxt, xmlXPathNewFloat((double) i));
5377 }
5378 }
Owen Taylor3473f882001-02-23 17:55:21 +00005379 xmlXPathFreeObject(cur);
5380}
5381
5382/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005383 * xmlXPathGetElementsByIds:
5384 * @doc: the document
5385 * @ids: a whitespace separated list of IDs
5386 *
5387 * Selects elements by their unique ID.
5388 *
5389 * Returns a node-set of selected elements.
5390 */
5391static xmlNodeSetPtr
5392xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5393 xmlNodeSetPtr ret;
5394 const xmlChar *cur = ids;
5395 xmlChar *ID;
5396 xmlAttrPtr attr;
5397 xmlNodePtr elem = NULL;
5398
5399 ret = xmlXPathNodeSetCreate(NULL);
5400
5401 while (IS_BLANK(*cur)) cur++;
5402 while (*cur != 0) {
5403 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5404 (*cur == '.') || (*cur == '-') ||
5405 (*cur == '_') || (*cur == ':') ||
5406 (IS_COMBINING(*cur)) ||
5407 (IS_EXTENDER(*cur)))
5408 cur++;
5409
5410 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5411
5412 ID = xmlStrndup(ids, cur - ids);
5413 attr = xmlGetID(doc, ID);
5414 if (attr != NULL) {
5415 elem = attr->parent;
5416 xmlXPathNodeSetAdd(ret, elem);
5417 }
5418 if (ID != NULL)
5419 xmlFree(ID);
5420
5421 while (IS_BLANK(*cur)) cur++;
5422 ids = cur;
5423 }
5424 return(ret);
5425}
5426
5427/**
Owen Taylor3473f882001-02-23 17:55:21 +00005428 * xmlXPathIdFunction:
5429 * @ctxt: the XPath Parser context
5430 * @nargs: the number of arguments
5431 *
5432 * Implement the id() XPath function
5433 * node-set id(object)
5434 * The id function selects elements by their unique ID
5435 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5436 * then the result is the union of the result of applying id to the
5437 * string value of each of the nodes in the argument node-set. When the
5438 * argument to id is of any other type, the argument is converted to a
5439 * string as if by a call to the string function; the string is split
5440 * into a whitespace-separated list of tokens (whitespace is any sequence
5441 * of characters matching the production S); the result is a node-set
5442 * containing the elements in the same document as the context node that
5443 * have a unique ID equal to any of the tokens in the list.
5444 */
5445void
5446xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005447 xmlChar *tokens;
5448 xmlNodeSetPtr ret;
5449 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005450
5451 CHECK_ARITY(1);
5452 obj = valuePop(ctxt);
5453 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5454 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005455 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005456 int i;
5457
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005458 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005459
Daniel Veillard911f49a2001-04-07 15:39:35 +00005460 if (obj->nodesetval != NULL) {
5461 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005462 tokens =
5463 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5464 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5465 ret = xmlXPathNodeSetMerge(ret, ns);
5466 xmlXPathFreeNodeSet(ns);
5467 if (tokens != NULL)
5468 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005469 }
Owen Taylor3473f882001-02-23 17:55:21 +00005470 }
5471
5472 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005473 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005474 return;
5475 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005476 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005477
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005478 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5479 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005480
Owen Taylor3473f882001-02-23 17:55:21 +00005481 xmlXPathFreeObject(obj);
5482 return;
5483}
5484
5485/**
5486 * xmlXPathLocalNameFunction:
5487 * @ctxt: the XPath Parser context
5488 * @nargs: the number of arguments
5489 *
5490 * Implement the local-name() XPath function
5491 * string local-name(node-set?)
5492 * The local-name function returns a string containing the local part
5493 * of the name of the node in the argument node-set that is first in
5494 * document order. If the node-set is empty or the first node has no
5495 * name, an empty string is returned. If the argument is omitted it
5496 * defaults to the context node.
5497 */
5498void
5499xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5500 xmlXPathObjectPtr cur;
5501
5502 if (nargs == 0) {
5503 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5504 nargs = 1;
5505 }
5506
5507 CHECK_ARITY(1);
5508 if ((ctxt->value == NULL) ||
5509 ((ctxt->value->type != XPATH_NODESET) &&
5510 (ctxt->value->type != XPATH_XSLT_TREE)))
5511 XP_ERROR(XPATH_INVALID_TYPE);
5512 cur = valuePop(ctxt);
5513
Daniel Veillard911f49a2001-04-07 15:39:35 +00005514 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005515 valuePush(ctxt, xmlXPathNewCString(""));
5516 } else {
5517 int i = 0; /* Should be first in document order !!!!! */
5518 switch (cur->nodesetval->nodeTab[i]->type) {
5519 case XML_ELEMENT_NODE:
5520 case XML_ATTRIBUTE_NODE:
5521 case XML_PI_NODE:
5522 valuePush(ctxt,
5523 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5524 break;
5525 case XML_NAMESPACE_DECL:
5526 valuePush(ctxt, xmlXPathNewString(
5527 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5528 break;
5529 default:
5530 valuePush(ctxt, xmlXPathNewCString(""));
5531 }
5532 }
5533 xmlXPathFreeObject(cur);
5534}
5535
5536/**
5537 * xmlXPathNamespaceURIFunction:
5538 * @ctxt: the XPath Parser context
5539 * @nargs: the number of arguments
5540 *
5541 * Implement the namespace-uri() XPath function
5542 * string namespace-uri(node-set?)
5543 * The namespace-uri function returns a string containing the
5544 * namespace URI of the expanded name of the node in the argument
5545 * node-set that is first in document order. If the node-set is empty,
5546 * the first node has no name, or the expanded name has no namespace
5547 * URI, an empty string is returned. If the argument is omitted it
5548 * defaults to the context node.
5549 */
5550void
5551xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5552 xmlXPathObjectPtr cur;
5553
5554 if (nargs == 0) {
5555 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5556 nargs = 1;
5557 }
5558 CHECK_ARITY(1);
5559 if ((ctxt->value == NULL) ||
5560 ((ctxt->value->type != XPATH_NODESET) &&
5561 (ctxt->value->type != XPATH_XSLT_TREE)))
5562 XP_ERROR(XPATH_INVALID_TYPE);
5563 cur = valuePop(ctxt);
5564
Daniel Veillard911f49a2001-04-07 15:39:35 +00005565 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005566 valuePush(ctxt, xmlXPathNewCString(""));
5567 } else {
5568 int i = 0; /* Should be first in document order !!!!! */
5569 switch (cur->nodesetval->nodeTab[i]->type) {
5570 case XML_ELEMENT_NODE:
5571 case XML_ATTRIBUTE_NODE:
5572 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5573 valuePush(ctxt, xmlXPathNewCString(""));
5574 else
5575 valuePush(ctxt, xmlXPathNewString(
5576 cur->nodesetval->nodeTab[i]->ns->href));
5577 break;
5578 default:
5579 valuePush(ctxt, xmlXPathNewCString(""));
5580 }
5581 }
5582 xmlXPathFreeObject(cur);
5583}
5584
5585/**
5586 * xmlXPathNameFunction:
5587 * @ctxt: the XPath Parser context
5588 * @nargs: the number of arguments
5589 *
5590 * Implement the name() XPath function
5591 * string name(node-set?)
5592 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005593 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005594 * order. The QName must represent the name with respect to the namespace
5595 * declarations in effect on the node whose name is being represented.
5596 * Typically, this will be the form in which the name occurred in the XML
5597 * source. This need not be the case if there are namespace declarations
5598 * in effect on the node that associate multiple prefixes with the same
5599 * namespace. However, an implementation may include information about
5600 * the original prefix in its representation of nodes; in this case, an
5601 * implementation can ensure that the returned string is always the same
5602 * as the QName used in the XML source. If the argument it omitted it
5603 * defaults to the context node.
5604 * Libxml keep the original prefix so the "real qualified name" used is
5605 * returned.
5606 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005607static void
Daniel Veillard04383752001-07-08 14:27:15 +00005608xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5609{
Owen Taylor3473f882001-02-23 17:55:21 +00005610 xmlXPathObjectPtr cur;
5611
5612 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005613 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5614 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005615 }
5616
5617 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005618 if ((ctxt->value == NULL) ||
5619 ((ctxt->value->type != XPATH_NODESET) &&
5620 (ctxt->value->type != XPATH_XSLT_TREE)))
5621 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005622 cur = valuePop(ctxt);
5623
Daniel Veillard911f49a2001-04-07 15:39:35 +00005624 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005625 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005626 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005627 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005628
Daniel Veillard04383752001-07-08 14:27:15 +00005629 switch (cur->nodesetval->nodeTab[i]->type) {
5630 case XML_ELEMENT_NODE:
5631 case XML_ATTRIBUTE_NODE:
5632 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5633 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5634 valuePush(ctxt,
5635 xmlXPathNewString(cur->nodesetval->
5636 nodeTab[i]->name));
5637
5638 else {
5639 char name[2000];
5640
5641 snprintf(name, sizeof(name), "%s:%s",
5642 (char *) cur->nodesetval->nodeTab[i]->ns->
5643 prefix,
5644 (char *) cur->nodesetval->nodeTab[i]->name);
5645 name[sizeof(name) - 1] = 0;
5646 valuePush(ctxt, xmlXPathNewCString(name));
5647 }
5648 break;
5649 default:
5650 valuePush(ctxt,
5651 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5652 xmlXPathLocalNameFunction(ctxt, 1);
5653 }
Owen Taylor3473f882001-02-23 17:55:21 +00005654 }
5655 xmlXPathFreeObject(cur);
5656}
5657
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005658
5659/**
Owen Taylor3473f882001-02-23 17:55:21 +00005660 * xmlXPathStringFunction:
5661 * @ctxt: the XPath Parser context
5662 * @nargs: the number of arguments
5663 *
5664 * Implement the string() XPath function
5665 * string string(object?)
5666 * he string function converts an object to a string as follows:
5667 * - A node-set is converted to a string by returning the value of
5668 * the node in the node-set that is first in document order.
5669 * If the node-set is empty, an empty string is returned.
5670 * - A number is converted to a string as follows
5671 * + NaN is converted to the string NaN
5672 * + positive zero is converted to the string 0
5673 * + negative zero is converted to the string 0
5674 * + positive infinity is converted to the string Infinity
5675 * + negative infinity is converted to the string -Infinity
5676 * + if the number is an integer, the number is represented in
5677 * decimal form as a Number with no decimal point and no leading
5678 * zeros, preceded by a minus sign (-) if the number is negative
5679 * + otherwise, the number is represented in decimal form as a
5680 * Number including a decimal point with at least one digit
5681 * before the decimal point and at least one digit after the
5682 * decimal point, preceded by a minus sign (-) if the number
5683 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005684 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005685 * before the decimal point; beyond the one required digit
5686 * after the decimal point there must be as many, but only as
5687 * many, more digits as are needed to uniquely distinguish the
5688 * number from all other IEEE 754 numeric values.
5689 * - The boolean false value is converted to the string false.
5690 * The boolean true value is converted to the string true.
5691 *
5692 * If the argument is omitted, it defaults to a node-set with the
5693 * context node as its only member.
5694 */
5695void
5696xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5697 xmlXPathObjectPtr cur;
5698
5699 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005700 valuePush(ctxt,
5701 xmlXPathWrapString(
5702 xmlXPathCastNodeToString(ctxt->context->node)));
5703 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005704 }
5705
5706 CHECK_ARITY(1);
5707 cur = valuePop(ctxt);
5708 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005709 cur = xmlXPathConvertString(cur);
5710 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005711}
5712
5713/**
5714 * xmlXPathStringLengthFunction:
5715 * @ctxt: the XPath Parser context
5716 * @nargs: the number of arguments
5717 *
5718 * Implement the string-length() XPath function
5719 * number string-length(string?)
5720 * The string-length returns the number of characters in the string
5721 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5722 * the context node converted to a string, in other words the value
5723 * of the context node.
5724 */
5725void
5726xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5727 xmlXPathObjectPtr cur;
5728
5729 if (nargs == 0) {
5730 if (ctxt->context->node == NULL) {
5731 valuePush(ctxt, xmlXPathNewFloat(0));
5732 } else {
5733 xmlChar *content;
5734
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005735 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005736 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005737 xmlFree(content);
5738 }
5739 return;
5740 }
5741 CHECK_ARITY(1);
5742 CAST_TO_STRING;
5743 CHECK_TYPE(XPATH_STRING);
5744 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005745 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005746 xmlXPathFreeObject(cur);
5747}
5748
5749/**
5750 * xmlXPathConcatFunction:
5751 * @ctxt: the XPath Parser context
5752 * @nargs: the number of arguments
5753 *
5754 * Implement the concat() XPath function
5755 * string concat(string, string, string*)
5756 * The concat function returns the concatenation of its arguments.
5757 */
5758void
5759xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5760 xmlXPathObjectPtr cur, newobj;
5761 xmlChar *tmp;
5762
5763 if (nargs < 2) {
5764 CHECK_ARITY(2);
5765 }
5766
5767 CAST_TO_STRING;
5768 cur = valuePop(ctxt);
5769 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5770 xmlXPathFreeObject(cur);
5771 return;
5772 }
5773 nargs--;
5774
5775 while (nargs > 0) {
5776 CAST_TO_STRING;
5777 newobj = valuePop(ctxt);
5778 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5779 xmlXPathFreeObject(newobj);
5780 xmlXPathFreeObject(cur);
5781 XP_ERROR(XPATH_INVALID_TYPE);
5782 }
5783 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5784 newobj->stringval = cur->stringval;
5785 cur->stringval = tmp;
5786
5787 xmlXPathFreeObject(newobj);
5788 nargs--;
5789 }
5790 valuePush(ctxt, cur);
5791}
5792
5793/**
5794 * xmlXPathContainsFunction:
5795 * @ctxt: the XPath Parser context
5796 * @nargs: the number of arguments
5797 *
5798 * Implement the contains() XPath function
5799 * boolean contains(string, string)
5800 * The contains function returns true if the first argument string
5801 * contains the second argument string, and otherwise returns false.
5802 */
5803void
5804xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5805 xmlXPathObjectPtr hay, needle;
5806
5807 CHECK_ARITY(2);
5808 CAST_TO_STRING;
5809 CHECK_TYPE(XPATH_STRING);
5810 needle = valuePop(ctxt);
5811 CAST_TO_STRING;
5812 hay = valuePop(ctxt);
5813 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5814 xmlXPathFreeObject(hay);
5815 xmlXPathFreeObject(needle);
5816 XP_ERROR(XPATH_INVALID_TYPE);
5817 }
5818 if (xmlStrstr(hay->stringval, needle->stringval))
5819 valuePush(ctxt, xmlXPathNewBoolean(1));
5820 else
5821 valuePush(ctxt, xmlXPathNewBoolean(0));
5822 xmlXPathFreeObject(hay);
5823 xmlXPathFreeObject(needle);
5824}
5825
5826/**
5827 * xmlXPathStartsWithFunction:
5828 * @ctxt: the XPath Parser context
5829 * @nargs: the number of arguments
5830 *
5831 * Implement the starts-with() XPath function
5832 * boolean starts-with(string, string)
5833 * The starts-with function returns true if the first argument string
5834 * starts with the second argument string, and otherwise returns false.
5835 */
5836void
5837xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5838 xmlXPathObjectPtr hay, needle;
5839 int n;
5840
5841 CHECK_ARITY(2);
5842 CAST_TO_STRING;
5843 CHECK_TYPE(XPATH_STRING);
5844 needle = valuePop(ctxt);
5845 CAST_TO_STRING;
5846 hay = valuePop(ctxt);
5847 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5848 xmlXPathFreeObject(hay);
5849 xmlXPathFreeObject(needle);
5850 XP_ERROR(XPATH_INVALID_TYPE);
5851 }
5852 n = xmlStrlen(needle->stringval);
5853 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5854 valuePush(ctxt, xmlXPathNewBoolean(0));
5855 else
5856 valuePush(ctxt, xmlXPathNewBoolean(1));
5857 xmlXPathFreeObject(hay);
5858 xmlXPathFreeObject(needle);
5859}
5860
5861/**
5862 * xmlXPathSubstringFunction:
5863 * @ctxt: the XPath Parser context
5864 * @nargs: the number of arguments
5865 *
5866 * Implement the substring() XPath function
5867 * string substring(string, number, number?)
5868 * The substring function returns the substring of the first argument
5869 * starting at the position specified in the second argument with
5870 * length specified in the third argument. For example,
5871 * substring("12345",2,3) returns "234". If the third argument is not
5872 * specified, it returns the substring starting at the position specified
5873 * in the second argument and continuing to the end of the string. For
5874 * example, substring("12345",2) returns "2345". More precisely, each
5875 * character in the string (see [3.6 Strings]) is considered to have a
5876 * numeric position: the position of the first character is 1, the position
5877 * of the second character is 2 and so on. The returned substring contains
5878 * those characters for which the position of the character is greater than
5879 * or equal to the second argument and, if the third argument is specified,
5880 * less than the sum of the second and third arguments; the comparisons
5881 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5882 * - substring("12345", 1.5, 2.6) returns "234"
5883 * - substring("12345", 0, 3) returns "12"
5884 * - substring("12345", 0 div 0, 3) returns ""
5885 * - substring("12345", 1, 0 div 0) returns ""
5886 * - substring("12345", -42, 1 div 0) returns "12345"
5887 * - substring("12345", -1 div 0, 1 div 0) returns ""
5888 */
5889void
5890xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5891 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005892 double le=0, in;
5893 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005894 xmlChar *ret;
5895
Owen Taylor3473f882001-02-23 17:55:21 +00005896 if (nargs < 2) {
5897 CHECK_ARITY(2);
5898 }
5899 if (nargs > 3) {
5900 CHECK_ARITY(3);
5901 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005902 /*
5903 * take care of possible last (position) argument
5904 */
Owen Taylor3473f882001-02-23 17:55:21 +00005905 if (nargs == 3) {
5906 CAST_TO_NUMBER;
5907 CHECK_TYPE(XPATH_NUMBER);
5908 len = valuePop(ctxt);
5909 le = len->floatval;
5910 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005911 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005912
Owen Taylor3473f882001-02-23 17:55:21 +00005913 CAST_TO_NUMBER;
5914 CHECK_TYPE(XPATH_NUMBER);
5915 start = valuePop(ctxt);
5916 in = start->floatval;
5917 xmlXPathFreeObject(start);
5918 CAST_TO_STRING;
5919 CHECK_TYPE(XPATH_STRING);
5920 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005921 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005922
Daniel Veillard97ac1312001-05-30 19:14:17 +00005923 /*
5924 * If last pos not present, calculate last position
5925 */
5926 if (nargs != 3)
5927 le = m;
5928
5929 /*
5930 * To meet our requirements, initial index calculations
5931 * must be done before we convert to integer format
5932 *
5933 * First we normalize indices
5934 */
5935 in -= 1.0;
5936 le += in;
5937 if (in < 0.0)
5938 in = 0.0;
5939 if (le > (double)m)
5940 le = (double)m;
5941
5942 /*
5943 * Now we go to integer form, rounding up
5944 */
Owen Taylor3473f882001-02-23 17:55:21 +00005945 i = (int) in;
5946 if (((double)i) != in) i++;
5947
Owen Taylor3473f882001-02-23 17:55:21 +00005948 l = (int) le;
5949 if (((double)l) != le) l++;
5950
Daniel Veillard97ac1312001-05-30 19:14:17 +00005951 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005952
5953 /* number of chars to copy */
5954 l -= i;
5955
Daniel Veillard97ac1312001-05-30 19:14:17 +00005956 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005957 if (ret == NULL)
5958 valuePush(ctxt, xmlXPathNewCString(""));
5959 else {
5960 valuePush(ctxt, xmlXPathNewString(ret));
5961 xmlFree(ret);
5962 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005963
Owen Taylor3473f882001-02-23 17:55:21 +00005964 xmlXPathFreeObject(str);
5965}
5966
5967/**
5968 * xmlXPathSubstringBeforeFunction:
5969 * @ctxt: the XPath Parser context
5970 * @nargs: the number of arguments
5971 *
5972 * Implement the substring-before() XPath function
5973 * string substring-before(string, string)
5974 * The substring-before function returns the substring of the first
5975 * argument string that precedes the first occurrence of the second
5976 * argument string in the first argument string, or the empty string
5977 * if the first argument string does not contain the second argument
5978 * string. For example, substring-before("1999/04/01","/") returns 1999.
5979 */
5980void
5981xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5982 xmlXPathObjectPtr str;
5983 xmlXPathObjectPtr find;
5984 xmlBufferPtr target;
5985 const xmlChar *point;
5986 int offset;
5987
5988 CHECK_ARITY(2);
5989 CAST_TO_STRING;
5990 find = valuePop(ctxt);
5991 CAST_TO_STRING;
5992 str = valuePop(ctxt);
5993
5994 target = xmlBufferCreate();
5995 if (target) {
5996 point = xmlStrstr(str->stringval, find->stringval);
5997 if (point) {
5998 offset = (int)(point - str->stringval);
5999 xmlBufferAdd(target, str->stringval, offset);
6000 }
6001 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6002 xmlBufferFree(target);
6003 }
6004
6005 xmlXPathFreeObject(str);
6006 xmlXPathFreeObject(find);
6007}
6008
6009/**
6010 * xmlXPathSubstringAfterFunction:
6011 * @ctxt: the XPath Parser context
6012 * @nargs: the number of arguments
6013 *
6014 * Implement the substring-after() XPath function
6015 * string substring-after(string, string)
6016 * The substring-after function returns the substring of the first
6017 * argument string that follows the first occurrence of the second
6018 * argument string in the first argument string, or the empty stringi
6019 * if the first argument string does not contain the second argument
6020 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6021 * and substring-after("1999/04/01","19") returns 99/04/01.
6022 */
6023void
6024xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6025 xmlXPathObjectPtr str;
6026 xmlXPathObjectPtr find;
6027 xmlBufferPtr target;
6028 const xmlChar *point;
6029 int offset;
6030
6031 CHECK_ARITY(2);
6032 CAST_TO_STRING;
6033 find = valuePop(ctxt);
6034 CAST_TO_STRING;
6035 str = valuePop(ctxt);
6036
6037 target = xmlBufferCreate();
6038 if (target) {
6039 point = xmlStrstr(str->stringval, find->stringval);
6040 if (point) {
6041 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6042 xmlBufferAdd(target, &str->stringval[offset],
6043 xmlStrlen(str->stringval) - offset);
6044 }
6045 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6046 xmlBufferFree(target);
6047 }
6048
6049 xmlXPathFreeObject(str);
6050 xmlXPathFreeObject(find);
6051}
6052
6053/**
6054 * xmlXPathNormalizeFunction:
6055 * @ctxt: the XPath Parser context
6056 * @nargs: the number of arguments
6057 *
6058 * Implement the normalize-space() XPath function
6059 * string normalize-space(string?)
6060 * The normalize-space function returns the argument string with white
6061 * space normalized by stripping leading and trailing whitespace
6062 * and replacing sequences of whitespace characters by a single
6063 * space. Whitespace characters are the same allowed by the S production
6064 * in XML. If the argument is omitted, it defaults to the context
6065 * node converted to a string, in other words the value of the context node.
6066 */
6067void
6068xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6069 xmlXPathObjectPtr obj = NULL;
6070 xmlChar *source = NULL;
6071 xmlBufferPtr target;
6072 xmlChar blank;
6073
6074 if (nargs == 0) {
6075 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006076 valuePush(ctxt,
6077 xmlXPathWrapString(
6078 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006079 nargs = 1;
6080 }
6081
6082 CHECK_ARITY(1);
6083 CAST_TO_STRING;
6084 CHECK_TYPE(XPATH_STRING);
6085 obj = valuePop(ctxt);
6086 source = obj->stringval;
6087
6088 target = xmlBufferCreate();
6089 if (target && source) {
6090
6091 /* Skip leading whitespaces */
6092 while (IS_BLANK(*source))
6093 source++;
6094
6095 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6096 blank = 0;
6097 while (*source) {
6098 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006099 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006100 } else {
6101 if (blank) {
6102 xmlBufferAdd(target, &blank, 1);
6103 blank = 0;
6104 }
6105 xmlBufferAdd(target, source, 1);
6106 }
6107 source++;
6108 }
6109
6110 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6111 xmlBufferFree(target);
6112 }
6113 xmlXPathFreeObject(obj);
6114}
6115
6116/**
6117 * xmlXPathTranslateFunction:
6118 * @ctxt: the XPath Parser context
6119 * @nargs: the number of arguments
6120 *
6121 * Implement the translate() XPath function
6122 * string translate(string, string, string)
6123 * The translate function returns the first argument string with
6124 * occurrences of characters in the second argument string replaced
6125 * by the character at the corresponding position in the third argument
6126 * string. For example, translate("bar","abc","ABC") returns the string
6127 * BAr. If there is a character in the second argument string with no
6128 * character at a corresponding position in the third argument string
6129 * (because the second argument string is longer than the third argument
6130 * string), then occurrences of that character in the first argument
6131 * string are removed. For example, translate("--aaa--","abc-","ABC")
6132 * returns "AAA". If a character occurs more than once in second
6133 * argument string, then the first occurrence determines the replacement
6134 * character. If the third argument string is longer than the second
6135 * argument string, then excess characters are ignored.
6136 */
6137void
6138xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006139 xmlXPathObjectPtr str;
6140 xmlXPathObjectPtr from;
6141 xmlXPathObjectPtr to;
6142 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006143 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006144 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006145 xmlChar *point;
6146 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006147
Daniel Veillarde043ee12001-04-16 14:08:07 +00006148 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006149
Daniel Veillarde043ee12001-04-16 14:08:07 +00006150 CAST_TO_STRING;
6151 to = valuePop(ctxt);
6152 CAST_TO_STRING;
6153 from = valuePop(ctxt);
6154 CAST_TO_STRING;
6155 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006156
Daniel Veillarde043ee12001-04-16 14:08:07 +00006157 target = xmlBufferCreate();
6158 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006159 max = xmlUTF8Strlen(to->stringval);
6160 for (cptr = str->stringval; (ch=*cptr); ) {
6161 offset = xmlUTF8Strloc(from->stringval, cptr);
6162 if (offset >= 0) {
6163 if (offset < max) {
6164 point = xmlUTF8Strpos(to->stringval, offset);
6165 if (point)
6166 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6167 }
6168 } else
6169 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6170
6171 /* Step to next character in input */
6172 cptr++;
6173 if ( ch & 0x80 ) {
6174 /* if not simple ascii, verify proper format */
6175 if ( (ch & 0xc0) != 0xc0 ) {
6176 xmlGenericError(xmlGenericErrorContext,
6177 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6178 break;
6179 }
6180 /* then skip over remaining bytes for this char */
6181 while ( (ch <<= 1) & 0x80 )
6182 if ( (*cptr++ & 0xc0) != 0x80 ) {
6183 xmlGenericError(xmlGenericErrorContext,
6184 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6185 break;
6186 }
6187 if (ch & 0x80) /* must have had error encountered */
6188 break;
6189 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006190 }
Owen Taylor3473f882001-02-23 17:55:21 +00006191 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006192 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6193 xmlBufferFree(target);
6194 xmlXPathFreeObject(str);
6195 xmlXPathFreeObject(from);
6196 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006197}
6198
6199/**
6200 * xmlXPathBooleanFunction:
6201 * @ctxt: the XPath Parser context
6202 * @nargs: the number of arguments
6203 *
6204 * Implement the boolean() XPath function
6205 * boolean boolean(object)
6206 * he boolean function converts its argument to a boolean as follows:
6207 * - a number is true if and only if it is neither positive or
6208 * negative zero nor NaN
6209 * - a node-set is true if and only if it is non-empty
6210 * - a string is true if and only if its length is non-zero
6211 */
6212void
6213xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6214 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006215
6216 CHECK_ARITY(1);
6217 cur = valuePop(ctxt);
6218 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006219 cur = xmlXPathConvertBoolean(cur);
6220 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006221}
6222
6223/**
6224 * xmlXPathNotFunction:
6225 * @ctxt: the XPath Parser context
6226 * @nargs: the number of arguments
6227 *
6228 * Implement the not() XPath function
6229 * boolean not(boolean)
6230 * The not function returns true if its argument is false,
6231 * and false otherwise.
6232 */
6233void
6234xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6235 CHECK_ARITY(1);
6236 CAST_TO_BOOLEAN;
6237 CHECK_TYPE(XPATH_BOOLEAN);
6238 ctxt->value->boolval = ! ctxt->value->boolval;
6239}
6240
6241/**
6242 * xmlXPathTrueFunction:
6243 * @ctxt: the XPath Parser context
6244 * @nargs: the number of arguments
6245 *
6246 * Implement the true() XPath function
6247 * boolean true()
6248 */
6249void
6250xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6251 CHECK_ARITY(0);
6252 valuePush(ctxt, xmlXPathNewBoolean(1));
6253}
6254
6255/**
6256 * xmlXPathFalseFunction:
6257 * @ctxt: the XPath Parser context
6258 * @nargs: the number of arguments
6259 *
6260 * Implement the false() XPath function
6261 * boolean false()
6262 */
6263void
6264xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6265 CHECK_ARITY(0);
6266 valuePush(ctxt, xmlXPathNewBoolean(0));
6267}
6268
6269/**
6270 * xmlXPathLangFunction:
6271 * @ctxt: the XPath Parser context
6272 * @nargs: the number of arguments
6273 *
6274 * Implement the lang() XPath function
6275 * boolean lang(string)
6276 * The lang function returns true or false depending on whether the
6277 * language of the context node as specified by xml:lang attributes
6278 * is the same as or is a sublanguage of the language specified by
6279 * the argument string. The language of the context node is determined
6280 * by the value of the xml:lang attribute on the context node, or, if
6281 * the context node has no xml:lang attribute, by the value of the
6282 * xml:lang attribute on the nearest ancestor of the context node that
6283 * has an xml:lang attribute. If there is no such attribute, then lang
6284 * returns false. If there is such an attribute, then lang returns
6285 * true if the attribute value is equal to the argument ignoring case,
6286 * or if there is some suffix starting with - such that the attribute
6287 * value is equal to the argument ignoring that suffix of the attribute
6288 * value and ignoring case.
6289 */
6290void
6291xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6292 xmlXPathObjectPtr val;
6293 const xmlChar *theLang;
6294 const xmlChar *lang;
6295 int ret = 0;
6296 int i;
6297
6298 CHECK_ARITY(1);
6299 CAST_TO_STRING;
6300 CHECK_TYPE(XPATH_STRING);
6301 val = valuePop(ctxt);
6302 lang = val->stringval;
6303 theLang = xmlNodeGetLang(ctxt->context->node);
6304 if ((theLang != NULL) && (lang != NULL)) {
6305 for (i = 0;lang[i] != 0;i++)
6306 if (toupper(lang[i]) != toupper(theLang[i]))
6307 goto not_equal;
6308 ret = 1;
6309 }
6310not_equal:
6311 xmlXPathFreeObject(val);
6312 valuePush(ctxt, xmlXPathNewBoolean(ret));
6313}
6314
6315/**
6316 * xmlXPathNumberFunction:
6317 * @ctxt: the XPath Parser context
6318 * @nargs: the number of arguments
6319 *
6320 * Implement the number() XPath function
6321 * number number(object?)
6322 */
6323void
6324xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6325 xmlXPathObjectPtr cur;
6326 double res;
6327
6328 if (nargs == 0) {
6329 if (ctxt->context->node == NULL) {
6330 valuePush(ctxt, xmlXPathNewFloat(0.0));
6331 } else {
6332 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6333
6334 res = xmlXPathStringEvalNumber(content);
6335 valuePush(ctxt, xmlXPathNewFloat(res));
6336 xmlFree(content);
6337 }
6338 return;
6339 }
6340
6341 CHECK_ARITY(1);
6342 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006343 cur = xmlXPathConvertNumber(cur);
6344 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006345}
6346
6347/**
6348 * xmlXPathSumFunction:
6349 * @ctxt: the XPath Parser context
6350 * @nargs: the number of arguments
6351 *
6352 * Implement the sum() XPath function
6353 * number sum(node-set)
6354 * The sum function returns the sum of the values of the nodes in
6355 * the argument node-set.
6356 */
6357void
6358xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6359 xmlXPathObjectPtr cur;
6360 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006361 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006362
6363 CHECK_ARITY(1);
6364 if ((ctxt->value == NULL) ||
6365 ((ctxt->value->type != XPATH_NODESET) &&
6366 (ctxt->value->type != XPATH_XSLT_TREE)))
6367 XP_ERROR(XPATH_INVALID_TYPE);
6368 cur = valuePop(ctxt);
6369
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006370 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006371 valuePush(ctxt, xmlXPathNewFloat(0.0));
6372 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006373 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6374 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006375 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006376 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006377 }
6378 xmlXPathFreeObject(cur);
6379}
6380
6381/**
6382 * xmlXPathFloorFunction:
6383 * @ctxt: the XPath Parser context
6384 * @nargs: the number of arguments
6385 *
6386 * Implement the floor() XPath function
6387 * number floor(number)
6388 * The floor function returns the largest (closest to positive infinity)
6389 * number that is not greater than the argument and that is an integer.
6390 */
6391void
6392xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6393 CHECK_ARITY(1);
6394 CAST_TO_NUMBER;
6395 CHECK_TYPE(XPATH_NUMBER);
6396#if 0
6397 ctxt->value->floatval = floor(ctxt->value->floatval);
6398#else
6399 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6400 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6401#endif
6402}
6403
6404/**
6405 * xmlXPathCeilingFunction:
6406 * @ctxt: the XPath Parser context
6407 * @nargs: the number of arguments
6408 *
6409 * Implement the ceiling() XPath function
6410 * number ceiling(number)
6411 * The ceiling function returns the smallest (closest to negative infinity)
6412 * number that is not less than the argument and that is an integer.
6413 */
6414void
6415xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6416 double f;
6417
6418 CHECK_ARITY(1);
6419 CAST_TO_NUMBER;
6420 CHECK_TYPE(XPATH_NUMBER);
6421
6422#if 0
6423 ctxt->value->floatval = ceil(ctxt->value->floatval);
6424#else
6425 f = (double)((int) ctxt->value->floatval);
6426 if (f != ctxt->value->floatval)
6427 ctxt->value->floatval = f + 1;
6428#endif
6429}
6430
6431/**
6432 * xmlXPathRoundFunction:
6433 * @ctxt: the XPath Parser context
6434 * @nargs: the number of arguments
6435 *
6436 * Implement the round() XPath function
6437 * number round(number)
6438 * The round function returns the number that is closest to the
6439 * argument and that is an integer. If there are two such numbers,
6440 * then the one that is even is returned.
6441 */
6442void
6443xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6444 double f;
6445
6446 CHECK_ARITY(1);
6447 CAST_TO_NUMBER;
6448 CHECK_TYPE(XPATH_NUMBER);
6449
Daniel Veillardcda96922001-08-21 10:56:31 +00006450 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6451 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6452 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006453 (ctxt->value->floatval == 0.0))
6454 return;
6455
6456#if 0
6457 f = floor(ctxt->value->floatval);
6458#else
6459 f = (double)((int) ctxt->value->floatval);
6460#endif
6461 if (ctxt->value->floatval < f + 0.5)
6462 ctxt->value->floatval = f;
6463 else
6464 ctxt->value->floatval = f + 1;
6465}
6466
6467/************************************************************************
6468 * *
6469 * The Parser *
6470 * *
6471 ************************************************************************/
6472
6473/*
6474 * a couple of forward declarations since we use a recursive call based
6475 * implementation.
6476 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006477static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006478static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006479static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006480#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006481static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6482#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006483#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006484static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006485#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006486static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6487 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006488
6489/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006490 * xmlXPathCurrentChar:
6491 * @ctxt: the XPath parser context
6492 * @cur: pointer to the beginning of the char
6493 * @len: pointer to the length of the char read
6494 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006495 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006496 * bytes in the input buffer.
6497 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006498 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006499 */
6500
6501static int
6502xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6503 unsigned char c;
6504 unsigned int val;
6505 const xmlChar *cur;
6506
6507 if (ctxt == NULL)
6508 return(0);
6509 cur = ctxt->cur;
6510
6511 /*
6512 * We are supposed to handle UTF8, check it's valid
6513 * From rfc2044: encoding of the Unicode values on UTF-8:
6514 *
6515 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6516 * 0000 0000-0000 007F 0xxxxxxx
6517 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6518 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6519 *
6520 * Check for the 0x110000 limit too
6521 */
6522 c = *cur;
6523 if (c & 0x80) {
6524 if ((cur[1] & 0xc0) != 0x80)
6525 goto encoding_error;
6526 if ((c & 0xe0) == 0xe0) {
6527
6528 if ((cur[2] & 0xc0) != 0x80)
6529 goto encoding_error;
6530 if ((c & 0xf0) == 0xf0) {
6531 if (((c & 0xf8) != 0xf0) ||
6532 ((cur[3] & 0xc0) != 0x80))
6533 goto encoding_error;
6534 /* 4-byte code */
6535 *len = 4;
6536 val = (cur[0] & 0x7) << 18;
6537 val |= (cur[1] & 0x3f) << 12;
6538 val |= (cur[2] & 0x3f) << 6;
6539 val |= cur[3] & 0x3f;
6540 } else {
6541 /* 3-byte code */
6542 *len = 3;
6543 val = (cur[0] & 0xf) << 12;
6544 val |= (cur[1] & 0x3f) << 6;
6545 val |= cur[2] & 0x3f;
6546 }
6547 } else {
6548 /* 2-byte code */
6549 *len = 2;
6550 val = (cur[0] & 0x1f) << 6;
6551 val |= cur[1] & 0x3f;
6552 }
6553 if (!IS_CHAR(val)) {
6554 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6555 }
6556 return(val);
6557 } else {
6558 /* 1-byte code */
6559 *len = 1;
6560 return((int) *cur);
6561 }
6562encoding_error:
6563 /*
6564 * If we detect an UTF8 error that probably mean that the
6565 * input encoding didn't get properly advertized in the
6566 * declaration header. Report the error and switch the encoding
6567 * to ISO-Latin-1 (if you don't like this policy, just declare the
6568 * encoding !)
6569 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006570 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006571 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006572}
6573
6574/**
Owen Taylor3473f882001-02-23 17:55:21 +00006575 * xmlXPathParseNCName:
6576 * @ctxt: the XPath Parser context
6577 *
6578 * parse an XML namespace non qualified name.
6579 *
6580 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6581 *
6582 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6583 * CombiningChar | Extender
6584 *
6585 * Returns the namespace name or NULL
6586 */
6587
6588xmlChar *
6589xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006590 const xmlChar *in;
6591 xmlChar *ret;
6592 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006593
Daniel Veillard2156a562001-04-28 12:24:34 +00006594 /*
6595 * Accelerator for simple ASCII names
6596 */
6597 in = ctxt->cur;
6598 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6599 ((*in >= 0x41) && (*in <= 0x5A)) ||
6600 (*in == '_')) {
6601 in++;
6602 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6603 ((*in >= 0x41) && (*in <= 0x5A)) ||
6604 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006605 (*in == '_') || (*in == '.') ||
6606 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006607 in++;
6608 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6609 (*in == '[') || (*in == ']') || (*in == ':') ||
6610 (*in == '@') || (*in == '*')) {
6611 count = in - ctxt->cur;
6612 if (count == 0)
6613 return(NULL);
6614 ret = xmlStrndup(ctxt->cur, count);
6615 ctxt->cur = in;
6616 return(ret);
6617 }
6618 }
6619 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006620}
6621
Daniel Veillard2156a562001-04-28 12:24:34 +00006622
Owen Taylor3473f882001-02-23 17:55:21 +00006623/**
6624 * xmlXPathParseQName:
6625 * @ctxt: the XPath Parser context
6626 * @prefix: a xmlChar **
6627 *
6628 * parse an XML qualified name
6629 *
6630 * [NS 5] QName ::= (Prefix ':')? LocalPart
6631 *
6632 * [NS 6] Prefix ::= NCName
6633 *
6634 * [NS 7] LocalPart ::= NCName
6635 *
6636 * Returns the function returns the local part, and prefix is updated
6637 * to get the Prefix if any.
6638 */
6639
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006640static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006641xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6642 xmlChar *ret = NULL;
6643
6644 *prefix = NULL;
6645 ret = xmlXPathParseNCName(ctxt);
6646 if (CUR == ':') {
6647 *prefix = ret;
6648 NEXT;
6649 ret = xmlXPathParseNCName(ctxt);
6650 }
6651 return(ret);
6652}
6653
6654/**
6655 * xmlXPathParseName:
6656 * @ctxt: the XPath Parser context
6657 *
6658 * parse an XML name
6659 *
6660 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6661 * CombiningChar | Extender
6662 *
6663 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6664 *
6665 * Returns the namespace name or NULL
6666 */
6667
6668xmlChar *
6669xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006670 const xmlChar *in;
6671 xmlChar *ret;
6672 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006673
Daniel Veillard61d80a22001-04-27 17:13:01 +00006674 /*
6675 * Accelerator for simple ASCII names
6676 */
6677 in = ctxt->cur;
6678 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6679 ((*in >= 0x41) && (*in <= 0x5A)) ||
6680 (*in == '_') || (*in == ':')) {
6681 in++;
6682 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6683 ((*in >= 0x41) && (*in <= 0x5A)) ||
6684 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006685 (*in == '_') || (*in == '-') ||
6686 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006687 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006688 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006689 count = in - ctxt->cur;
6690 ret = xmlStrndup(ctxt->cur, count);
6691 ctxt->cur = in;
6692 return(ret);
6693 }
6694 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006695 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006696}
6697
Daniel Veillard61d80a22001-04-27 17:13:01 +00006698static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006699xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006700 xmlChar buf[XML_MAX_NAMELEN + 5];
6701 int len = 0, l;
6702 int c;
6703
6704 /*
6705 * Handler for more complex cases
6706 */
6707 c = CUR_CHAR(l);
6708 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006709 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6710 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006711 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006712 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006713 return(NULL);
6714 }
6715
6716 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6717 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6718 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006719 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006720 (IS_COMBINING(c)) ||
6721 (IS_EXTENDER(c)))) {
6722 COPY_BUF(l,buf,len,c);
6723 NEXTL(l);
6724 c = CUR_CHAR(l);
6725 if (len >= XML_MAX_NAMELEN) {
6726 /*
6727 * Okay someone managed to make a huge name, so he's ready to pay
6728 * for the processing speed.
6729 */
6730 xmlChar *buffer;
6731 int max = len * 2;
6732
6733 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6734 if (buffer == NULL) {
6735 XP_ERROR0(XPATH_MEMORY_ERROR);
6736 }
6737 memcpy(buffer, buf, len);
6738 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6739 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006740 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006741 (IS_COMBINING(c)) ||
6742 (IS_EXTENDER(c))) {
6743 if (len + 10 > max) {
6744 max *= 2;
6745 buffer = (xmlChar *) xmlRealloc(buffer,
6746 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006747 if (buffer == NULL) {
6748 XP_ERROR0(XPATH_MEMORY_ERROR);
6749 }
6750 }
6751 COPY_BUF(l,buffer,len,c);
6752 NEXTL(l);
6753 c = CUR_CHAR(l);
6754 }
6755 buffer[len] = 0;
6756 return(buffer);
6757 }
6758 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006759 if (len == 0)
6760 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006761 return(xmlStrndup(buf, len));
6762}
Owen Taylor3473f882001-02-23 17:55:21 +00006763/**
6764 * xmlXPathStringEvalNumber:
6765 * @str: A string to scan
6766 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006767 * [30a] Float ::= Number ('e' Digits?)?
6768 *
Owen Taylor3473f882001-02-23 17:55:21 +00006769 * [30] Number ::= Digits ('.' Digits?)?
6770 * | '.' Digits
6771 * [31] Digits ::= [0-9]+
6772 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006773 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006774 * In complement of the Number expression, this function also handles
6775 * negative values : '-' Number.
6776 *
6777 * Returns the double value.
6778 */
6779double
6780xmlXPathStringEvalNumber(const xmlChar *str) {
6781 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00006782 double ret;
Owen Taylor3473f882001-02-23 17:55:21 +00006783 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006784 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006785 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006786 int exponent = 0;
6787 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006788#ifdef __GNUC__
6789 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006790 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006791#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006792
Owen Taylor3473f882001-02-23 17:55:21 +00006793 while (IS_BLANK(*cur)) cur++;
6794 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6795 return(xmlXPathNAN);
6796 }
6797 if (*cur == '-') {
6798 isneg = 1;
6799 cur++;
6800 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006801
6802#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006803 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006804 * tmp/temp is a workaround against a gcc compiler bug
6805 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006806 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006807 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006808 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006809 ret = ret * 10;
6810 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006811 ok = 1;
6812 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00006813 temp = (double) tmp;
6814 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006815 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006816#else
Daniel Veillard7b416132002-03-07 08:36:03 +00006817 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006818 while ((*cur >= '0') && (*cur <= '9')) {
6819 ret = ret * 10 + (*cur - '0');
6820 ok = 1;
6821 cur++;
6822 }
6823#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006824
Owen Taylor3473f882001-02-23 17:55:21 +00006825 if (*cur == '.') {
6826 cur++;
6827 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6828 return(xmlXPathNAN);
6829 }
6830 while ((*cur >= '0') && (*cur <= '9')) {
6831 mult /= 10;
6832 ret = ret + (*cur - '0') * mult;
6833 cur++;
6834 }
6835 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006836 if ((*cur == 'e') || (*cur == 'E')) {
6837 cur++;
6838 if (*cur == '-') {
6839 is_exponent_negative = 1;
6840 cur++;
6841 }
6842 while ((*cur >= '0') && (*cur <= '9')) {
6843 exponent = exponent * 10 + (*cur - '0');
6844 cur++;
6845 }
6846 }
Owen Taylor3473f882001-02-23 17:55:21 +00006847 while (IS_BLANK(*cur)) cur++;
6848 if (*cur != 0) return(xmlXPathNAN);
6849 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006850 if (is_exponent_negative) exponent = -exponent;
6851 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006852 return(ret);
6853}
6854
6855/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006856 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006857 * @ctxt: the XPath Parser context
6858 *
6859 * [30] Number ::= Digits ('.' Digits?)?
6860 * | '.' Digits
6861 * [31] Digits ::= [0-9]+
6862 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006863 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006864 *
6865 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006866static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006867xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6868{
Owen Taylor3473f882001-02-23 17:55:21 +00006869 double ret = 0.0;
6870 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00006871 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006872 int exponent = 0;
6873 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006874#ifdef __GNUC__
6875 unsigned long tmp = 0;
6876 double temp;
6877#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006878
6879 CHECK_ERROR;
6880 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6881 XP_ERROR(XPATH_NUMBER_ERROR);
6882 }
Daniel Veillard7b416132002-03-07 08:36:03 +00006883#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006884 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006885 * tmp/temp is a workaround against a gcc compiler bug
6886 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006887 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006888 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006889 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006890 ret = ret * 10;
6891 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006892 ok = 1;
6893 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00006894 temp = (double) tmp;
6895 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006896 }
Daniel Veillard7b416132002-03-07 08:36:03 +00006897#else
6898 ret = 0;
6899 while ((CUR >= '0') && (CUR <= '9')) {
6900 ret = ret * 10 + (CUR - '0');
6901 ok = 1;
6902 NEXT;
6903 }
6904#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006905 if (CUR == '.') {
6906 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006907 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6908 XP_ERROR(XPATH_NUMBER_ERROR);
6909 }
6910 while ((CUR >= '0') && (CUR <= '9')) {
6911 mult /= 10;
6912 ret = ret + (CUR - '0') * mult;
6913 NEXT;
6914 }
Owen Taylor3473f882001-02-23 17:55:21 +00006915 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006916 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006917 NEXT;
6918 if (CUR == '-') {
6919 is_exponent_negative = 1;
6920 NEXT;
6921 }
6922 while ((CUR >= '0') && (CUR <= '9')) {
6923 exponent = exponent * 10 + (CUR - '0');
6924 NEXT;
6925 }
6926 if (is_exponent_negative)
6927 exponent = -exponent;
6928 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006929 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006930 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006931 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006932}
6933
6934/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006935 * xmlXPathParseLiteral:
6936 * @ctxt: the XPath Parser context
6937 *
6938 * Parse a Literal
6939 *
6940 * [29] Literal ::= '"' [^"]* '"'
6941 * | "'" [^']* "'"
6942 *
6943 * Returns the value found or NULL in case of error
6944 */
6945static xmlChar *
6946xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6947 const xmlChar *q;
6948 xmlChar *ret = NULL;
6949
6950 if (CUR == '"') {
6951 NEXT;
6952 q = CUR_PTR;
6953 while ((IS_CHAR(CUR)) && (CUR != '"'))
6954 NEXT;
6955 if (!IS_CHAR(CUR)) {
6956 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6957 } else {
6958 ret = xmlStrndup(q, CUR_PTR - q);
6959 NEXT;
6960 }
6961 } else if (CUR == '\'') {
6962 NEXT;
6963 q = CUR_PTR;
6964 while ((IS_CHAR(CUR)) && (CUR != '\''))
6965 NEXT;
6966 if (!IS_CHAR(CUR)) {
6967 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6968 } else {
6969 ret = xmlStrndup(q, CUR_PTR - q);
6970 NEXT;
6971 }
6972 } else {
6973 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6974 }
6975 return(ret);
6976}
6977
6978/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006979 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006980 * @ctxt: the XPath Parser context
6981 *
6982 * Parse a Literal and push it on the stack.
6983 *
6984 * [29] Literal ::= '"' [^"]* '"'
6985 * | "'" [^']* "'"
6986 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006987 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006988 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006989static void
6990xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006991 const xmlChar *q;
6992 xmlChar *ret = NULL;
6993
6994 if (CUR == '"') {
6995 NEXT;
6996 q = CUR_PTR;
6997 while ((IS_CHAR(CUR)) && (CUR != '"'))
6998 NEXT;
6999 if (!IS_CHAR(CUR)) {
7000 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7001 } else {
7002 ret = xmlStrndup(q, CUR_PTR - q);
7003 NEXT;
7004 }
7005 } else if (CUR == '\'') {
7006 NEXT;
7007 q = CUR_PTR;
7008 while ((IS_CHAR(CUR)) && (CUR != '\''))
7009 NEXT;
7010 if (!IS_CHAR(CUR)) {
7011 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7012 } else {
7013 ret = xmlStrndup(q, CUR_PTR - q);
7014 NEXT;
7015 }
7016 } else {
7017 XP_ERROR(XPATH_START_LITERAL_ERROR);
7018 }
7019 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007020 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7021 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007022 xmlFree(ret);
7023}
7024
7025/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007026 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007027 * @ctxt: the XPath Parser context
7028 *
7029 * Parse a VariableReference, evaluate it and push it on the stack.
7030 *
7031 * The variable bindings consist of a mapping from variable names
7032 * to variable values. The value of a variable is an object, which
7033 * of any of the types that are possible for the value of an expression,
7034 * and may also be of additional types not specified here.
7035 *
7036 * Early evaluation is possible since:
7037 * The variable bindings [...] used to evaluate a subexpression are
7038 * always the same as those used to evaluate the containing expression.
7039 *
7040 * [36] VariableReference ::= '$' QName
7041 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007042static void
7043xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007044 xmlChar *name;
7045 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007046
7047 SKIP_BLANKS;
7048 if (CUR != '$') {
7049 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7050 }
7051 NEXT;
7052 name = xmlXPathParseQName(ctxt, &prefix);
7053 if (name == NULL) {
7054 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7055 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007056 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007057 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7058 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007059 SKIP_BLANKS;
7060}
7061
7062/**
7063 * xmlXPathIsNodeType:
7064 * @ctxt: the XPath Parser context
7065 * @name: a name string
7066 *
7067 * Is the name given a NodeType one.
7068 *
7069 * [38] NodeType ::= 'comment'
7070 * | 'text'
7071 * | 'processing-instruction'
7072 * | 'node'
7073 *
7074 * Returns 1 if true 0 otherwise
7075 */
7076int
7077xmlXPathIsNodeType(const xmlChar *name) {
7078 if (name == NULL)
7079 return(0);
7080
Daniel Veillard1971ee22002-01-31 20:29:19 +00007081 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007082 return(1);
7083 if (xmlStrEqual(name, BAD_CAST "text"))
7084 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007085 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007086 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007087 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007088 return(1);
7089 return(0);
7090}
7091
7092/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007093 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007094 * @ctxt: the XPath Parser context
7095 *
7096 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7097 * [17] Argument ::= Expr
7098 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007099 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007100 * pushed on the stack
7101 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007102static void
7103xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007104 xmlChar *name;
7105 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007106 int nbargs = 0;
7107
7108 name = xmlXPathParseQName(ctxt, &prefix);
7109 if (name == NULL) {
7110 XP_ERROR(XPATH_EXPR_ERROR);
7111 }
7112 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007113#ifdef DEBUG_EXPR
7114 if (prefix == NULL)
7115 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7116 name);
7117 else
7118 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7119 prefix, name);
7120#endif
7121
Owen Taylor3473f882001-02-23 17:55:21 +00007122 if (CUR != '(') {
7123 XP_ERROR(XPATH_EXPR_ERROR);
7124 }
7125 NEXT;
7126 SKIP_BLANKS;
7127
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007128 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007129 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007130 int op1 = ctxt->comp->last;
7131 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007132 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007133 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007134 nbargs++;
7135 if (CUR == ')') break;
7136 if (CUR != ',') {
7137 XP_ERROR(XPATH_EXPR_ERROR);
7138 }
7139 NEXT;
7140 SKIP_BLANKS;
7141 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007142 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7143 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007144 NEXT;
7145 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007146}
7147
7148/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007149 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007150 * @ctxt: the XPath Parser context
7151 *
7152 * [15] PrimaryExpr ::= VariableReference
7153 * | '(' Expr ')'
7154 * | Literal
7155 * | Number
7156 * | FunctionCall
7157 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007158 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007159 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007160static void
7161xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007162 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007163 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007164 else if (CUR == '(') {
7165 NEXT;
7166 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007167 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007168 if (CUR != ')') {
7169 XP_ERROR(XPATH_EXPR_ERROR);
7170 }
7171 NEXT;
7172 SKIP_BLANKS;
7173 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007174 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007175 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007176 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007177 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007178 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007179 }
7180 SKIP_BLANKS;
7181}
7182
7183/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007184 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007185 * @ctxt: the XPath Parser context
7186 *
7187 * [20] FilterExpr ::= PrimaryExpr
7188 * | FilterExpr Predicate
7189 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007190 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007191 * Square brackets are used to filter expressions in the same way that
7192 * they are used in location paths. It is an error if the expression to
7193 * be filtered does not evaluate to a node-set. The context node list
7194 * used for evaluating the expression in square brackets is the node-set
7195 * to be filtered listed in document order.
7196 */
7197
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007198static void
7199xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7200 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007201 CHECK_ERROR;
7202 SKIP_BLANKS;
7203
7204 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007205 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007206 SKIP_BLANKS;
7207 }
7208
7209
7210}
7211
7212/**
7213 * xmlXPathScanName:
7214 * @ctxt: the XPath Parser context
7215 *
7216 * Trickery: parse an XML name but without consuming the input flow
7217 * Needed to avoid insanity in the parser state.
7218 *
7219 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7220 * CombiningChar | Extender
7221 *
7222 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7223 *
7224 * [6] Names ::= Name (S Name)*
7225 *
7226 * Returns the Name parsed or NULL
7227 */
7228
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007229static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007230xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7231 xmlChar buf[XML_MAX_NAMELEN];
7232 int len = 0;
7233
7234 SKIP_BLANKS;
7235 if (!IS_LETTER(CUR) && (CUR != '_') &&
7236 (CUR != ':')) {
7237 return(NULL);
7238 }
7239
7240 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7241 (NXT(len) == '.') || (NXT(len) == '-') ||
7242 (NXT(len) == '_') || (NXT(len) == ':') ||
7243 (IS_COMBINING(NXT(len))) ||
7244 (IS_EXTENDER(NXT(len)))) {
7245 buf[len] = NXT(len);
7246 len++;
7247 if (len >= XML_MAX_NAMELEN) {
7248 xmlGenericError(xmlGenericErrorContext,
7249 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7250 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7251 (NXT(len) == '.') || (NXT(len) == '-') ||
7252 (NXT(len) == '_') || (NXT(len) == ':') ||
7253 (IS_COMBINING(NXT(len))) ||
7254 (IS_EXTENDER(NXT(len))))
7255 len++;
7256 break;
7257 }
7258 }
7259 return(xmlStrndup(buf, len));
7260}
7261
7262/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007263 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007264 * @ctxt: the XPath Parser context
7265 *
7266 * [19] PathExpr ::= LocationPath
7267 * | FilterExpr
7268 * | FilterExpr '/' RelativeLocationPath
7269 * | FilterExpr '//' RelativeLocationPath
7270 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007271 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007272 * The / operator and // operators combine an arbitrary expression
7273 * and a relative location path. It is an error if the expression
7274 * does not evaluate to a node-set.
7275 * The / operator does composition in the same way as when / is
7276 * used in a location path. As in location paths, // is short for
7277 * /descendant-or-self::node()/.
7278 */
7279
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007280static void
7281xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007282 int lc = 1; /* Should we branch to LocationPath ? */
7283 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7284
7285 SKIP_BLANKS;
7286 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7287 (CUR == '\'') || (CUR == '"')) {
7288 lc = 0;
7289 } else if (CUR == '*') {
7290 /* relative or absolute location path */
7291 lc = 1;
7292 } else if (CUR == '/') {
7293 /* relative or absolute location path */
7294 lc = 1;
7295 } else if (CUR == '@') {
7296 /* relative abbreviated attribute location path */
7297 lc = 1;
7298 } else if (CUR == '.') {
7299 /* relative abbreviated attribute location path */
7300 lc = 1;
7301 } else {
7302 /*
7303 * Problem is finding if we have a name here whether it's:
7304 * - a nodetype
7305 * - a function call in which case it's followed by '('
7306 * - an axis in which case it's followed by ':'
7307 * - a element name
7308 * We do an a priori analysis here rather than having to
7309 * maintain parsed token content through the recursive function
7310 * calls. This looks uglier but makes the code quite easier to
7311 * read/write/debug.
7312 */
7313 SKIP_BLANKS;
7314 name = xmlXPathScanName(ctxt);
7315 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7316#ifdef DEBUG_STEP
7317 xmlGenericError(xmlGenericErrorContext,
7318 "PathExpr: Axis\n");
7319#endif
7320 lc = 1;
7321 xmlFree(name);
7322 } else if (name != NULL) {
7323 int len =xmlStrlen(name);
7324 int blank = 0;
7325
7326
7327 while (NXT(len) != 0) {
7328 if (NXT(len) == '/') {
7329 /* element name */
7330#ifdef DEBUG_STEP
7331 xmlGenericError(xmlGenericErrorContext,
7332 "PathExpr: AbbrRelLocation\n");
7333#endif
7334 lc = 1;
7335 break;
7336 } else if (IS_BLANK(NXT(len))) {
7337 /* skip to next */
7338 blank = 1;
7339 } else if (NXT(len) == ':') {
7340#ifdef DEBUG_STEP
7341 xmlGenericError(xmlGenericErrorContext,
7342 "PathExpr: AbbrRelLocation\n");
7343#endif
7344 lc = 1;
7345 break;
7346 } else if ((NXT(len) == '(')) {
7347 /* Note Type or Function */
7348 if (xmlXPathIsNodeType(name)) {
7349#ifdef DEBUG_STEP
7350 xmlGenericError(xmlGenericErrorContext,
7351 "PathExpr: Type search\n");
7352#endif
7353 lc = 1;
7354 } else {
7355#ifdef DEBUG_STEP
7356 xmlGenericError(xmlGenericErrorContext,
7357 "PathExpr: function call\n");
7358#endif
7359 lc = 0;
7360 }
7361 break;
7362 } else if ((NXT(len) == '[')) {
7363 /* element name */
7364#ifdef DEBUG_STEP
7365 xmlGenericError(xmlGenericErrorContext,
7366 "PathExpr: AbbrRelLocation\n");
7367#endif
7368 lc = 1;
7369 break;
7370 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7371 (NXT(len) == '=')) {
7372 lc = 1;
7373 break;
7374 } else {
7375 lc = 1;
7376 break;
7377 }
7378 len++;
7379 }
7380 if (NXT(len) == 0) {
7381#ifdef DEBUG_STEP
7382 xmlGenericError(xmlGenericErrorContext,
7383 "PathExpr: AbbrRelLocation\n");
7384#endif
7385 /* element name */
7386 lc = 1;
7387 }
7388 xmlFree(name);
7389 } else {
7390 /* make sure all cases are covered explicitely */
7391 XP_ERROR(XPATH_EXPR_ERROR);
7392 }
7393 }
7394
7395 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007396 if (CUR == '/') {
7397 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7398 } else {
7399 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007400 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007401 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007402 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007403 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007404 CHECK_ERROR;
7405 if ((CUR == '/') && (NXT(1) == '/')) {
7406 SKIP(2);
7407 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007408
7409 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7410 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7411 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7412
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007413 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007414 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007415 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007416 }
7417 }
7418 SKIP_BLANKS;
7419}
7420
7421/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007422 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007423 * @ctxt: the XPath Parser context
7424 *
7425 * [18] UnionExpr ::= PathExpr
7426 * | UnionExpr '|' PathExpr
7427 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007428 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007429 */
7430
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007431static void
7432xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7433 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007434 CHECK_ERROR;
7435 SKIP_BLANKS;
7436 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007437 int op1 = ctxt->comp->last;
7438 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007439
7440 NEXT;
7441 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007442 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007443
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007444 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7445
Owen Taylor3473f882001-02-23 17:55:21 +00007446 SKIP_BLANKS;
7447 }
Owen Taylor3473f882001-02-23 17:55:21 +00007448}
7449
7450/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007451 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007452 * @ctxt: the XPath Parser context
7453 *
7454 * [27] UnaryExpr ::= UnionExpr
7455 * | '-' UnaryExpr
7456 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007457 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007458 */
7459
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007460static void
7461xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007462 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007463 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007464
7465 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007466 while (CUR == '-') {
7467 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007468 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007469 NEXT;
7470 SKIP_BLANKS;
7471 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007472
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007473 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007474 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007475 if (found) {
7476 if (minus)
7477 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7478 else
7479 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007480 }
7481}
7482
7483/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007484 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007485 * @ctxt: the XPath Parser context
7486 *
7487 * [26] MultiplicativeExpr ::= UnaryExpr
7488 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7489 * | MultiplicativeExpr 'div' UnaryExpr
7490 * | MultiplicativeExpr 'mod' UnaryExpr
7491 * [34] MultiplyOperator ::= '*'
7492 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007493 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007494 */
7495
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007496static void
7497xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7498 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007499 CHECK_ERROR;
7500 SKIP_BLANKS;
7501 while ((CUR == '*') ||
7502 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7503 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7504 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007505 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007506
7507 if (CUR == '*') {
7508 op = 0;
7509 NEXT;
7510 } else if (CUR == 'd') {
7511 op = 1;
7512 SKIP(3);
7513 } else if (CUR == 'm') {
7514 op = 2;
7515 SKIP(3);
7516 }
7517 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007518 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007519 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007520 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007521 SKIP_BLANKS;
7522 }
7523}
7524
7525/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007526 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007527 * @ctxt: the XPath Parser context
7528 *
7529 * [25] AdditiveExpr ::= MultiplicativeExpr
7530 * | AdditiveExpr '+' MultiplicativeExpr
7531 * | AdditiveExpr '-' MultiplicativeExpr
7532 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007533 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007534 */
7535
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007536static void
7537xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007538
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007539 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007540 CHECK_ERROR;
7541 SKIP_BLANKS;
7542 while ((CUR == '+') || (CUR == '-')) {
7543 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007544 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007545
7546 if (CUR == '+') plus = 1;
7547 else plus = 0;
7548 NEXT;
7549 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007550 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007551 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007552 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007553 SKIP_BLANKS;
7554 }
7555}
7556
7557/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007558 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007559 * @ctxt: the XPath Parser context
7560 *
7561 * [24] RelationalExpr ::= AdditiveExpr
7562 * | RelationalExpr '<' AdditiveExpr
7563 * | RelationalExpr '>' AdditiveExpr
7564 * | RelationalExpr '<=' AdditiveExpr
7565 * | RelationalExpr '>=' AdditiveExpr
7566 *
7567 * A <= B > C is allowed ? Answer from James, yes with
7568 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7569 * which is basically what got implemented.
7570 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007571 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007572 * on the stack
7573 */
7574
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007575static void
7576xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7577 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007578 CHECK_ERROR;
7579 SKIP_BLANKS;
7580 while ((CUR == '<') ||
7581 (CUR == '>') ||
7582 ((CUR == '<') && (NXT(1) == '=')) ||
7583 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007584 int inf, strict;
7585 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007586
7587 if (CUR == '<') inf = 1;
7588 else inf = 0;
7589 if (NXT(1) == '=') strict = 0;
7590 else strict = 1;
7591 NEXT;
7592 if (!strict) NEXT;
7593 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007594 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007595 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007596 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007597 SKIP_BLANKS;
7598 }
7599}
7600
7601/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007602 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007603 * @ctxt: the XPath Parser context
7604 *
7605 * [23] EqualityExpr ::= RelationalExpr
7606 * | EqualityExpr '=' RelationalExpr
7607 * | EqualityExpr '!=' RelationalExpr
7608 *
7609 * A != B != C is allowed ? Answer from James, yes with
7610 * (RelationalExpr = RelationalExpr) = RelationalExpr
7611 * (RelationalExpr != RelationalExpr) != RelationalExpr
7612 * which is basically what got implemented.
7613 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007614 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007615 *
7616 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007617static void
7618xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7619 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007620 CHECK_ERROR;
7621 SKIP_BLANKS;
7622 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007623 int eq;
7624 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007625
7626 if (CUR == '=') eq = 1;
7627 else eq = 0;
7628 NEXT;
7629 if (!eq) NEXT;
7630 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007631 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007632 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007633 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007634 SKIP_BLANKS;
7635 }
7636}
7637
7638/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007639 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007640 * @ctxt: the XPath Parser context
7641 *
7642 * [22] AndExpr ::= EqualityExpr
7643 * | AndExpr 'and' EqualityExpr
7644 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007646 *
7647 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007648static void
7649xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7650 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007651 CHECK_ERROR;
7652 SKIP_BLANKS;
7653 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007654 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007655 SKIP(3);
7656 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007657 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007658 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007659 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007660 SKIP_BLANKS;
7661 }
7662}
7663
7664/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007665 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007666 * @ctxt: the XPath Parser context
7667 *
7668 * [14] Expr ::= OrExpr
7669 * [21] OrExpr ::= AndExpr
7670 * | OrExpr 'or' AndExpr
7671 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007672 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007673 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007674static void
7675xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7676 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007677 CHECK_ERROR;
7678 SKIP_BLANKS;
7679 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007680 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007681 SKIP(2);
7682 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007683 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007684 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007685 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7686 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007687 SKIP_BLANKS;
7688 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007689 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7690 /* more ops could be optimized too */
7691 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7692 }
Owen Taylor3473f882001-02-23 17:55:21 +00007693}
7694
7695/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007696 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007697 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007698 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007699 *
7700 * [8] Predicate ::= '[' PredicateExpr ']'
7701 * [9] PredicateExpr ::= Expr
7702 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007703 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007704 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007705static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007706xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007707 int op1 = ctxt->comp->last;
7708
7709 SKIP_BLANKS;
7710 if (CUR != '[') {
7711 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7712 }
7713 NEXT;
7714 SKIP_BLANKS;
7715
7716 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007717 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007718 CHECK_ERROR;
7719
7720 if (CUR != ']') {
7721 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7722 }
7723
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007724 if (filter)
7725 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7726 else
7727 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007728
7729 NEXT;
7730 SKIP_BLANKS;
7731}
7732
7733/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007734 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007735 * @ctxt: the XPath Parser context
7736 * @test: pointer to a xmlXPathTestVal
7737 * @type: pointer to a xmlXPathTypeVal
7738 * @prefix: placeholder for a possible name prefix
7739 *
7740 * [7] NodeTest ::= NameTest
7741 * | NodeType '(' ')'
7742 * | 'processing-instruction' '(' Literal ')'
7743 *
7744 * [37] NameTest ::= '*'
7745 * | NCName ':' '*'
7746 * | QName
7747 * [38] NodeType ::= 'comment'
7748 * | 'text'
7749 * | 'processing-instruction'
7750 * | 'node'
7751 *
7752 * Returns the name found and update @test, @type and @prefix appropriately
7753 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007754static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007755xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7756 xmlXPathTypeVal *type, const xmlChar **prefix,
7757 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007758 int blanks;
7759
7760 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7761 STRANGE;
7762 return(NULL);
7763 }
7764 *type = 0;
7765 *test = 0;
7766 *prefix = NULL;
7767 SKIP_BLANKS;
7768
7769 if ((name == NULL) && (CUR == '*')) {
7770 /*
7771 * All elements
7772 */
7773 NEXT;
7774 *test = NODE_TEST_ALL;
7775 return(NULL);
7776 }
7777
7778 if (name == NULL)
7779 name = xmlXPathParseNCName(ctxt);
7780 if (name == NULL) {
7781 XP_ERROR0(XPATH_EXPR_ERROR);
7782 }
7783
7784 blanks = IS_BLANK(CUR);
7785 SKIP_BLANKS;
7786 if (CUR == '(') {
7787 NEXT;
7788 /*
7789 * NodeType or PI search
7790 */
7791 if (xmlStrEqual(name, BAD_CAST "comment"))
7792 *type = NODE_TYPE_COMMENT;
7793 else if (xmlStrEqual(name, BAD_CAST "node"))
7794 *type = NODE_TYPE_NODE;
7795 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7796 *type = NODE_TYPE_PI;
7797 else if (xmlStrEqual(name, BAD_CAST "text"))
7798 *type = NODE_TYPE_TEXT;
7799 else {
7800 if (name != NULL)
7801 xmlFree(name);
7802 XP_ERROR0(XPATH_EXPR_ERROR);
7803 }
7804
7805 *test = NODE_TEST_TYPE;
7806
7807 SKIP_BLANKS;
7808 if (*type == NODE_TYPE_PI) {
7809 /*
7810 * Specific case: search a PI by name.
7811 */
Owen Taylor3473f882001-02-23 17:55:21 +00007812 if (name != NULL)
7813 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007814 name = NULL;
7815 if (CUR != ')') {
7816 name = xmlXPathParseLiteral(ctxt);
7817 CHECK_ERROR 0;
7818 SKIP_BLANKS;
7819 }
Owen Taylor3473f882001-02-23 17:55:21 +00007820 }
7821 if (CUR != ')') {
7822 if (name != NULL)
7823 xmlFree(name);
7824 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7825 }
7826 NEXT;
7827 return(name);
7828 }
7829 *test = NODE_TEST_NAME;
7830 if ((!blanks) && (CUR == ':')) {
7831 NEXT;
7832
7833 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007834 * Since currently the parser context don't have a
7835 * namespace list associated:
7836 * The namespace name for this prefix can be computed
7837 * only at evaluation time. The compilation is done
7838 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007839 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007840#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007841 *prefix = xmlXPathNsLookup(ctxt->context, name);
7842 if (name != NULL)
7843 xmlFree(name);
7844 if (*prefix == NULL) {
7845 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7846 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007847#else
7848 *prefix = name;
7849#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007850
7851 if (CUR == '*') {
7852 /*
7853 * All elements
7854 */
7855 NEXT;
7856 *test = NODE_TEST_ALL;
7857 return(NULL);
7858 }
7859
7860 name = xmlXPathParseNCName(ctxt);
7861 if (name == NULL) {
7862 XP_ERROR0(XPATH_EXPR_ERROR);
7863 }
7864 }
7865 return(name);
7866}
7867
7868/**
7869 * xmlXPathIsAxisName:
7870 * @name: a preparsed name token
7871 *
7872 * [6] AxisName ::= 'ancestor'
7873 * | 'ancestor-or-self'
7874 * | 'attribute'
7875 * | 'child'
7876 * | 'descendant'
7877 * | 'descendant-or-self'
7878 * | 'following'
7879 * | 'following-sibling'
7880 * | 'namespace'
7881 * | 'parent'
7882 * | 'preceding'
7883 * | 'preceding-sibling'
7884 * | 'self'
7885 *
7886 * Returns the axis or 0
7887 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007888static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007889xmlXPathIsAxisName(const xmlChar *name) {
7890 xmlXPathAxisVal ret = 0;
7891 switch (name[0]) {
7892 case 'a':
7893 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7894 ret = AXIS_ANCESTOR;
7895 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7896 ret = AXIS_ANCESTOR_OR_SELF;
7897 if (xmlStrEqual(name, BAD_CAST "attribute"))
7898 ret = AXIS_ATTRIBUTE;
7899 break;
7900 case 'c':
7901 if (xmlStrEqual(name, BAD_CAST "child"))
7902 ret = AXIS_CHILD;
7903 break;
7904 case 'd':
7905 if (xmlStrEqual(name, BAD_CAST "descendant"))
7906 ret = AXIS_DESCENDANT;
7907 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7908 ret = AXIS_DESCENDANT_OR_SELF;
7909 break;
7910 case 'f':
7911 if (xmlStrEqual(name, BAD_CAST "following"))
7912 ret = AXIS_FOLLOWING;
7913 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7914 ret = AXIS_FOLLOWING_SIBLING;
7915 break;
7916 case 'n':
7917 if (xmlStrEqual(name, BAD_CAST "namespace"))
7918 ret = AXIS_NAMESPACE;
7919 break;
7920 case 'p':
7921 if (xmlStrEqual(name, BAD_CAST "parent"))
7922 ret = AXIS_PARENT;
7923 if (xmlStrEqual(name, BAD_CAST "preceding"))
7924 ret = AXIS_PRECEDING;
7925 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7926 ret = AXIS_PRECEDING_SIBLING;
7927 break;
7928 case 's':
7929 if (xmlStrEqual(name, BAD_CAST "self"))
7930 ret = AXIS_SELF;
7931 break;
7932 }
7933 return(ret);
7934}
7935
7936/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007937 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007938 * @ctxt: the XPath Parser context
7939 *
7940 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7941 * | AbbreviatedStep
7942 *
7943 * [12] AbbreviatedStep ::= '.' | '..'
7944 *
7945 * [5] AxisSpecifier ::= AxisName '::'
7946 * | AbbreviatedAxisSpecifier
7947 *
7948 * [13] AbbreviatedAxisSpecifier ::= '@'?
7949 *
7950 * Modified for XPtr range support as:
7951 *
7952 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7953 * | AbbreviatedStep
7954 * | 'range-to' '(' Expr ')' Predicate*
7955 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007956 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007957 * A location step of . is short for self::node(). This is
7958 * particularly useful in conjunction with //. For example, the
7959 * location path .//para is short for
7960 * self::node()/descendant-or-self::node()/child::para
7961 * and so will select all para descendant elements of the context
7962 * node.
7963 * Similarly, a location step of .. is short for parent::node().
7964 * For example, ../title is short for parent::node()/child::title
7965 * and so will select the title children of the parent of the context
7966 * node.
7967 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007968static void
7969xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007970#ifdef LIBXML_XPTR_ENABLED
7971 int rangeto = 0;
7972 int op2 = -1;
7973#endif
7974
Owen Taylor3473f882001-02-23 17:55:21 +00007975 SKIP_BLANKS;
7976 if ((CUR == '.') && (NXT(1) == '.')) {
7977 SKIP(2);
7978 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007979 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7980 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007981 } else if (CUR == '.') {
7982 NEXT;
7983 SKIP_BLANKS;
7984 } else {
7985 xmlChar *name = NULL;
7986 const xmlChar *prefix = NULL;
7987 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007988 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007989 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007990 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007991
7992 /*
7993 * The modification needed for XPointer change to the production
7994 */
7995#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007996 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007997 name = xmlXPathParseNCName(ctxt);
7998 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007999 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008000 xmlFree(name);
8001 SKIP_BLANKS;
8002 if (CUR != '(') {
8003 XP_ERROR(XPATH_EXPR_ERROR);
8004 }
8005 NEXT;
8006 SKIP_BLANKS;
8007
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008008 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008009 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008010 CHECK_ERROR;
8011
8012 SKIP_BLANKS;
8013 if (CUR != ')') {
8014 XP_ERROR(XPATH_EXPR_ERROR);
8015 }
8016 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008017 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008018 goto eval_predicates;
8019 }
8020 }
8021#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008022 if (CUR == '*') {
8023 axis = AXIS_CHILD;
8024 } else {
8025 if (name == NULL)
8026 name = xmlXPathParseNCName(ctxt);
8027 if (name != NULL) {
8028 axis = xmlXPathIsAxisName(name);
8029 if (axis != 0) {
8030 SKIP_BLANKS;
8031 if ((CUR == ':') && (NXT(1) == ':')) {
8032 SKIP(2);
8033 xmlFree(name);
8034 name = NULL;
8035 } else {
8036 /* an element name can conflict with an axis one :-\ */
8037 axis = AXIS_CHILD;
8038 }
Owen Taylor3473f882001-02-23 17:55:21 +00008039 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008040 axis = AXIS_CHILD;
8041 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008042 } else if (CUR == '@') {
8043 NEXT;
8044 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008045 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008046 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008047 }
Owen Taylor3473f882001-02-23 17:55:21 +00008048 }
8049
8050 CHECK_ERROR;
8051
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008052 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008053 if (test == 0)
8054 return;
8055
8056#ifdef DEBUG_STEP
8057 xmlGenericError(xmlGenericErrorContext,
8058 "Basis : computing new set\n");
8059#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008060
Owen Taylor3473f882001-02-23 17:55:21 +00008061#ifdef DEBUG_STEP
8062 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008063 if (ctxt->value == NULL)
8064 xmlGenericError(xmlGenericErrorContext, "no value\n");
8065 else if (ctxt->value->nodesetval == NULL)
8066 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8067 else
8068 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008069#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008070
8071eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008072 op1 = ctxt->comp->last;
8073 ctxt->comp->last = -1;
8074
Owen Taylor3473f882001-02-23 17:55:21 +00008075 SKIP_BLANKS;
8076 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008077 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008078 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008079
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008080#ifdef LIBXML_XPTR_ENABLED
8081 if (rangeto) {
8082 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8083 } else
8084#endif
8085 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8086 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008087
Owen Taylor3473f882001-02-23 17:55:21 +00008088 }
8089#ifdef DEBUG_STEP
8090 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008091 if (ctxt->value == NULL)
8092 xmlGenericError(xmlGenericErrorContext, "no value\n");
8093 else if (ctxt->value->nodesetval == NULL)
8094 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8095 else
8096 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8097 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008098#endif
8099}
8100
8101/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008102 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008103 * @ctxt: the XPath Parser context
8104 *
8105 * [3] RelativeLocationPath ::= Step
8106 * | RelativeLocationPath '/' Step
8107 * | AbbreviatedRelativeLocationPath
8108 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8109 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008110 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008111 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008112static void
Owen Taylor3473f882001-02-23 17:55:21 +00008113#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008114xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008115#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008116xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008117#endif
8118(xmlXPathParserContextPtr ctxt) {
8119 SKIP_BLANKS;
8120 if ((CUR == '/') && (NXT(1) == '/')) {
8121 SKIP(2);
8122 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008123 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8124 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008125 } else if (CUR == '/') {
8126 NEXT;
8127 SKIP_BLANKS;
8128 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008129 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008130 SKIP_BLANKS;
8131 while (CUR == '/') {
8132 if ((CUR == '/') && (NXT(1) == '/')) {
8133 SKIP(2);
8134 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008135 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008136 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008137 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008138 } else if (CUR == '/') {
8139 NEXT;
8140 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008141 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008142 }
8143 SKIP_BLANKS;
8144 }
8145}
8146
8147/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008148 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008149 * @ctxt: the XPath Parser context
8150 *
8151 * [1] LocationPath ::= RelativeLocationPath
8152 * | AbsoluteLocationPath
8153 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8154 * | AbbreviatedAbsoluteLocationPath
8155 * [10] AbbreviatedAbsoluteLocationPath ::=
8156 * '//' RelativeLocationPath
8157 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008158 * Compile a location path
8159 *
Owen Taylor3473f882001-02-23 17:55:21 +00008160 * // is short for /descendant-or-self::node()/. For example,
8161 * //para is short for /descendant-or-self::node()/child::para and
8162 * so will select any para element in the document (even a para element
8163 * that is a document element will be selected by //para since the
8164 * document element node is a child of the root node); div//para is
8165 * short for div/descendant-or-self::node()/child::para and so will
8166 * select all para descendants of div children.
8167 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008168static void
8169xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008170 SKIP_BLANKS;
8171 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008172 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008173 } else {
8174 while (CUR == '/') {
8175 if ((CUR == '/') && (NXT(1) == '/')) {
8176 SKIP(2);
8177 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008178 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8179 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008180 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008181 } else if (CUR == '/') {
8182 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008183 SKIP_BLANKS;
8184 if ((CUR != 0 ) &&
8185 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8186 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008187 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008188 }
8189 }
8190 }
8191}
8192
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008193/************************************************************************
8194 * *
8195 * XPath precompiled expression evaluation *
8196 * *
8197 ************************************************************************/
8198
Daniel Veillardf06307e2001-07-03 10:35:50 +00008199static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008200xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8201
8202/**
8203 * xmlXPathNodeCollectAndTest:
8204 * @ctxt: the XPath Parser context
8205 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008206 * @first: pointer to the first element in document order
8207 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008208 *
8209 * This is the function implementing a step: based on the current list
8210 * of nodes, it builds up a new list, looking at all nodes under that
8211 * axis and selecting them it also do the predicate filtering
8212 *
8213 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008214 *
8215 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008216 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008217static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008218xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008219 xmlXPathStepOpPtr op,
8220 xmlNodePtr * first, xmlNodePtr * last)
8221{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008222 xmlXPathAxisVal axis = op->value;
8223 xmlXPathTestVal test = op->value2;
8224 xmlXPathTypeVal type = op->value3;
8225 const xmlChar *prefix = op->value4;
8226 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008227 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008228
8229#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008230 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008231#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008232 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008233 xmlNodeSetPtr ret, list;
8234 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008235 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008236 xmlNodePtr cur = NULL;
8237 xmlXPathObjectPtr obj;
8238 xmlNodeSetPtr nodelist;
8239 xmlNodePtr tmp;
8240
Daniel Veillardf06307e2001-07-03 10:35:50 +00008241 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008242 obj = valuePop(ctxt);
8243 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008244 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008245 URI = xmlXPathNsLookup(ctxt->context, prefix);
8246 if (URI == NULL)
8247 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008248 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008249#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008250 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008251#endif
8252 switch (axis) {
8253 case AXIS_ANCESTOR:
8254#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008255 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008256#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008257 first = NULL;
8258 next = xmlXPathNextAncestor;
8259 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008260 case AXIS_ANCESTOR_OR_SELF:
8261#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008262 xmlGenericError(xmlGenericErrorContext,
8263 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008264#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008265 first = NULL;
8266 next = xmlXPathNextAncestorOrSelf;
8267 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008268 case AXIS_ATTRIBUTE:
8269#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008270 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008271#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008272 first = NULL;
8273 last = NULL;
8274 next = xmlXPathNextAttribute;
8275 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008276 case AXIS_CHILD:
8277#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008278 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008279#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008280 last = NULL;
8281 next = xmlXPathNextChild;
8282 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008283 case AXIS_DESCENDANT:
8284#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008285 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008286#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008287 last = NULL;
8288 next = xmlXPathNextDescendant;
8289 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008290 case AXIS_DESCENDANT_OR_SELF:
8291#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008292 xmlGenericError(xmlGenericErrorContext,
8293 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008294#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008295 last = NULL;
8296 next = xmlXPathNextDescendantOrSelf;
8297 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008298 case AXIS_FOLLOWING:
8299#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008300 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008301#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008302 last = NULL;
8303 next = xmlXPathNextFollowing;
8304 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008305 case AXIS_FOLLOWING_SIBLING:
8306#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008307 xmlGenericError(xmlGenericErrorContext,
8308 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008309#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008310 last = NULL;
8311 next = xmlXPathNextFollowingSibling;
8312 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008313 case AXIS_NAMESPACE:
8314#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008315 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008316#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008317 first = NULL;
8318 last = NULL;
8319 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8320 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008321 case AXIS_PARENT:
8322#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008323 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008324#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008325 first = NULL;
8326 next = xmlXPathNextParent;
8327 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008328 case AXIS_PRECEDING:
8329#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008330 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008331#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008332 first = NULL;
8333 next = xmlXPathNextPrecedingInternal;
8334 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008335 case AXIS_PRECEDING_SIBLING:
8336#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008337 xmlGenericError(xmlGenericErrorContext,
8338 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008339#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008340 first = NULL;
8341 next = xmlXPathNextPrecedingSibling;
8342 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008343 case AXIS_SELF:
8344#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008345 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008346#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008347 first = NULL;
8348 last = NULL;
8349 next = xmlXPathNextSelf;
8350 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008351 }
8352 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008353 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008354
8355 nodelist = obj->nodesetval;
8356 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008357 xmlXPathFreeObject(obj);
8358 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8359 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008360 }
8361 addNode = xmlXPathNodeSetAddUnique;
8362 ret = NULL;
8363#ifdef DEBUG_STEP
8364 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008365 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008366 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008367 case NODE_TEST_NONE:
8368 xmlGenericError(xmlGenericErrorContext,
8369 " searching for none !!!\n");
8370 break;
8371 case NODE_TEST_TYPE:
8372 xmlGenericError(xmlGenericErrorContext,
8373 " searching for type %d\n", type);
8374 break;
8375 case NODE_TEST_PI:
8376 xmlGenericError(xmlGenericErrorContext,
8377 " searching for PI !!!\n");
8378 break;
8379 case NODE_TEST_ALL:
8380 xmlGenericError(xmlGenericErrorContext,
8381 " searching for *\n");
8382 break;
8383 case NODE_TEST_NS:
8384 xmlGenericError(xmlGenericErrorContext,
8385 " searching for namespace %s\n",
8386 prefix);
8387 break;
8388 case NODE_TEST_NAME:
8389 xmlGenericError(xmlGenericErrorContext,
8390 " searching for name %s\n", name);
8391 if (prefix != NULL)
8392 xmlGenericError(xmlGenericErrorContext,
8393 " with namespace %s\n", prefix);
8394 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008395 }
8396 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8397#endif
8398 /*
8399 * 2.3 Node Tests
8400 * - For the attribute axis, the principal node type is attribute.
8401 * - For the namespace axis, the principal node type is namespace.
8402 * - For other axes, the principal node type is element.
8403 *
8404 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008405 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008406 * select all element children of the context node
8407 */
8408 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008409 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008410 ctxt->context->node = nodelist->nodeTab[i];
8411
Daniel Veillardf06307e2001-07-03 10:35:50 +00008412 cur = NULL;
8413 list = xmlXPathNodeSetCreate(NULL);
8414 do {
8415 cur = next(ctxt, cur);
8416 if (cur == NULL)
8417 break;
8418 if ((first != NULL) && (*first == cur))
8419 break;
8420 if (((t % 256) == 0) &&
8421 (first != NULL) && (*first != NULL) &&
8422 (xmlXPathCmpNodes(*first, cur) >= 0))
8423 break;
8424 if ((last != NULL) && (*last == cur))
8425 break;
8426 if (((t % 256) == 0) &&
8427 (last != NULL) && (*last != NULL) &&
8428 (xmlXPathCmpNodes(cur, *last) >= 0))
8429 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008430 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008431#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008432 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8433#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008434 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008435 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008436 ctxt->context->node = tmp;
8437 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008438 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008439 if ((cur->type == type) ||
8440 ((type == NODE_TYPE_NODE) &&
8441 ((cur->type == XML_DOCUMENT_NODE) ||
8442 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8443 (cur->type == XML_ELEMENT_NODE) ||
8444 (cur->type == XML_PI_NODE) ||
8445 (cur->type == XML_COMMENT_NODE) ||
8446 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008447 (cur->type == XML_TEXT_NODE))) ||
8448 ((type == NODE_TYPE_TEXT) &&
8449 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008450#ifdef DEBUG_STEP
8451 n++;
8452#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008453 addNode(list, cur);
8454 }
8455 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008456 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008457 if (cur->type == XML_PI_NODE) {
8458 if ((name != NULL) &&
8459 (!xmlStrEqual(name, cur->name)))
8460 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008461#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008462 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008463#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008464 addNode(list, cur);
8465 }
8466 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008467 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008468 if (axis == AXIS_ATTRIBUTE) {
8469 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008470#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008471 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008472#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008473 addNode(list, cur);
8474 }
8475 } else if (axis == AXIS_NAMESPACE) {
8476 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008477#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008478 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008479#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008480 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8481 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008482 }
8483 } else {
8484 if (cur->type == XML_ELEMENT_NODE) {
8485 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008486#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008487 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008488#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008489 addNode(list, cur);
8490 } else if ((cur->ns != NULL) &&
8491 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008492#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008493 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008494#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008495 addNode(list, cur);
8496 }
8497 }
8498 }
8499 break;
8500 case NODE_TEST_NS:{
8501 TODO;
8502 break;
8503 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008504 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008505 switch (cur->type) {
8506 case XML_ELEMENT_NODE:
8507 if (xmlStrEqual(name, cur->name)) {
8508 if (prefix == NULL) {
8509 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008510#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008511 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008512#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008513 addNode(list, cur);
8514 }
8515 } else {
8516 if ((cur->ns != NULL) &&
8517 (xmlStrEqual(URI,
8518 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008519#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008520 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008521#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008522 addNode(list, cur);
8523 }
8524 }
8525 }
8526 break;
8527 case XML_ATTRIBUTE_NODE:{
8528 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008529
Daniel Veillardf06307e2001-07-03 10:35:50 +00008530 if (xmlStrEqual(name, attr->name)) {
8531 if (prefix == NULL) {
8532 if ((attr->ns == NULL) ||
8533 (attr->ns->prefix == NULL)) {
8534#ifdef DEBUG_STEP
8535 n++;
8536#endif
8537 addNode(list,
8538 (xmlNodePtr) attr);
8539 }
8540 } else {
8541 if ((attr->ns != NULL) &&
8542 (xmlStrEqual(URI,
8543 attr->ns->
8544 href))) {
8545#ifdef DEBUG_STEP
8546 n++;
8547#endif
8548 addNode(list,
8549 (xmlNodePtr) attr);
8550 }
8551 }
8552 }
8553 break;
8554 }
8555 case XML_NAMESPACE_DECL:
8556 if (cur->type == XML_NAMESPACE_DECL) {
8557 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008558
Daniel Veillardf06307e2001-07-03 10:35:50 +00008559 if ((ns->prefix != NULL) && (name != NULL)
8560 && (xmlStrEqual(ns->prefix, name))) {
8561#ifdef DEBUG_STEP
8562 n++;
8563#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008564 xmlXPathNodeSetAddNs(list,
8565 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008566 }
8567 }
8568 break;
8569 default:
8570 break;
8571 }
8572 break;
8573 break;
8574 }
8575 } while (cur != NULL);
8576
8577 /*
8578 * If there is some predicate filtering do it now
8579 */
8580 if (op->ch2 != -1) {
8581 xmlXPathObjectPtr obj2;
8582
8583 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8584 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8585 CHECK_TYPE0(XPATH_NODESET);
8586 obj2 = valuePop(ctxt);
8587 list = obj2->nodesetval;
8588 obj2->nodesetval = NULL;
8589 xmlXPathFreeObject(obj2);
8590 }
8591 if (ret == NULL) {
8592 ret = list;
8593 } else {
8594 ret = xmlXPathNodeSetMerge(ret, list);
8595 xmlXPathFreeNodeSet(list);
8596 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008597 }
8598 ctxt->context->node = tmp;
8599#ifdef DEBUG_STEP
8600 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008601 "\nExamined %d nodes, found %d nodes at that step\n",
8602 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008603#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008604 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008605 if ((obj->boolval) && (obj->user != NULL)) {
8606 ctxt->value->boolval = 1;
8607 ctxt->value->user = obj->user;
8608 obj->user = NULL;
8609 obj->boolval = 0;
8610 }
8611 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008612 return(t);
8613}
8614
8615/**
8616 * xmlXPathNodeCollectAndTestNth:
8617 * @ctxt: the XPath Parser context
8618 * @op: the XPath precompiled step operation
8619 * @indx: the index to collect
8620 * @first: pointer to the first element in document order
8621 * @last: pointer to the last element in document order
8622 *
8623 * This is the function implementing a step: based on the current list
8624 * of nodes, it builds up a new list, looking at all nodes under that
8625 * axis and selecting them it also do the predicate filtering
8626 *
8627 * Pushes the new NodeSet resulting from the search.
8628 * Returns the number of node traversed
8629 */
8630static int
8631xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8632 xmlXPathStepOpPtr op, int indx,
8633 xmlNodePtr * first, xmlNodePtr * last)
8634{
8635 xmlXPathAxisVal axis = op->value;
8636 xmlXPathTestVal test = op->value2;
8637 xmlXPathTypeVal type = op->value3;
8638 const xmlChar *prefix = op->value4;
8639 const xmlChar *name = op->value5;
8640 const xmlChar *URI = NULL;
8641 int n = 0, t = 0;
8642
8643 int i;
8644 xmlNodeSetPtr list;
8645 xmlXPathTraversalFunction next = NULL;
8646 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8647 xmlNodePtr cur = NULL;
8648 xmlXPathObjectPtr obj;
8649 xmlNodeSetPtr nodelist;
8650 xmlNodePtr tmp;
8651
8652 CHECK_TYPE0(XPATH_NODESET);
8653 obj = valuePop(ctxt);
8654 addNode = xmlXPathNodeSetAdd;
8655 if (prefix != NULL) {
8656 URI = xmlXPathNsLookup(ctxt->context, prefix);
8657 if (URI == NULL)
8658 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8659 }
8660#ifdef DEBUG_STEP_NTH
8661 xmlGenericError(xmlGenericErrorContext, "new step : ");
8662 if (first != NULL) {
8663 if (*first != NULL)
8664 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8665 (*first)->name);
8666 else
8667 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8668 }
8669 if (last != NULL) {
8670 if (*last != NULL)
8671 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8672 (*last)->name);
8673 else
8674 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8675 }
8676#endif
8677 switch (axis) {
8678 case AXIS_ANCESTOR:
8679#ifdef DEBUG_STEP_NTH
8680 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8681#endif
8682 first = NULL;
8683 next = xmlXPathNextAncestor;
8684 break;
8685 case AXIS_ANCESTOR_OR_SELF:
8686#ifdef DEBUG_STEP_NTH
8687 xmlGenericError(xmlGenericErrorContext,
8688 "axis 'ancestors-or-self' ");
8689#endif
8690 first = NULL;
8691 next = xmlXPathNextAncestorOrSelf;
8692 break;
8693 case AXIS_ATTRIBUTE:
8694#ifdef DEBUG_STEP_NTH
8695 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8696#endif
8697 first = NULL;
8698 last = NULL;
8699 next = xmlXPathNextAttribute;
8700 break;
8701 case AXIS_CHILD:
8702#ifdef DEBUG_STEP_NTH
8703 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8704#endif
8705 last = NULL;
8706 next = xmlXPathNextChild;
8707 break;
8708 case AXIS_DESCENDANT:
8709#ifdef DEBUG_STEP_NTH
8710 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8711#endif
8712 last = NULL;
8713 next = xmlXPathNextDescendant;
8714 break;
8715 case AXIS_DESCENDANT_OR_SELF:
8716#ifdef DEBUG_STEP_NTH
8717 xmlGenericError(xmlGenericErrorContext,
8718 "axis 'descendant-or-self' ");
8719#endif
8720 last = NULL;
8721 next = xmlXPathNextDescendantOrSelf;
8722 break;
8723 case AXIS_FOLLOWING:
8724#ifdef DEBUG_STEP_NTH
8725 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8726#endif
8727 last = NULL;
8728 next = xmlXPathNextFollowing;
8729 break;
8730 case AXIS_FOLLOWING_SIBLING:
8731#ifdef DEBUG_STEP_NTH
8732 xmlGenericError(xmlGenericErrorContext,
8733 "axis 'following-siblings' ");
8734#endif
8735 last = NULL;
8736 next = xmlXPathNextFollowingSibling;
8737 break;
8738 case AXIS_NAMESPACE:
8739#ifdef DEBUG_STEP_NTH
8740 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8741#endif
8742 last = NULL;
8743 first = NULL;
8744 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8745 break;
8746 case AXIS_PARENT:
8747#ifdef DEBUG_STEP_NTH
8748 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8749#endif
8750 first = NULL;
8751 next = xmlXPathNextParent;
8752 break;
8753 case AXIS_PRECEDING:
8754#ifdef DEBUG_STEP_NTH
8755 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8756#endif
8757 first = NULL;
8758 next = xmlXPathNextPrecedingInternal;
8759 break;
8760 case AXIS_PRECEDING_SIBLING:
8761#ifdef DEBUG_STEP_NTH
8762 xmlGenericError(xmlGenericErrorContext,
8763 "axis 'preceding-sibling' ");
8764#endif
8765 first = NULL;
8766 next = xmlXPathNextPrecedingSibling;
8767 break;
8768 case AXIS_SELF:
8769#ifdef DEBUG_STEP_NTH
8770 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8771#endif
8772 first = NULL;
8773 last = NULL;
8774 next = xmlXPathNextSelf;
8775 break;
8776 }
8777 if (next == NULL)
8778 return(0);
8779
8780 nodelist = obj->nodesetval;
8781 if (nodelist == NULL) {
8782 xmlXPathFreeObject(obj);
8783 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8784 return(0);
8785 }
8786 addNode = xmlXPathNodeSetAddUnique;
8787#ifdef DEBUG_STEP_NTH
8788 xmlGenericError(xmlGenericErrorContext,
8789 " context contains %d nodes\n", nodelist->nodeNr);
8790 switch (test) {
8791 case NODE_TEST_NONE:
8792 xmlGenericError(xmlGenericErrorContext,
8793 " searching for none !!!\n");
8794 break;
8795 case NODE_TEST_TYPE:
8796 xmlGenericError(xmlGenericErrorContext,
8797 " searching for type %d\n", type);
8798 break;
8799 case NODE_TEST_PI:
8800 xmlGenericError(xmlGenericErrorContext,
8801 " searching for PI !!!\n");
8802 break;
8803 case NODE_TEST_ALL:
8804 xmlGenericError(xmlGenericErrorContext,
8805 " searching for *\n");
8806 break;
8807 case NODE_TEST_NS:
8808 xmlGenericError(xmlGenericErrorContext,
8809 " searching for namespace %s\n",
8810 prefix);
8811 break;
8812 case NODE_TEST_NAME:
8813 xmlGenericError(xmlGenericErrorContext,
8814 " searching for name %s\n", name);
8815 if (prefix != NULL)
8816 xmlGenericError(xmlGenericErrorContext,
8817 " with namespace %s\n", prefix);
8818 break;
8819 }
8820 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8821#endif
8822 /*
8823 * 2.3 Node Tests
8824 * - For the attribute axis, the principal node type is attribute.
8825 * - For the namespace axis, the principal node type is namespace.
8826 * - For other axes, the principal node type is element.
8827 *
8828 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008829 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008830 * select all element children of the context node
8831 */
8832 tmp = ctxt->context->node;
8833 list = xmlXPathNodeSetCreate(NULL);
8834 for (i = 0; i < nodelist->nodeNr; i++) {
8835 ctxt->context->node = nodelist->nodeTab[i];
8836
8837 cur = NULL;
8838 n = 0;
8839 do {
8840 cur = next(ctxt, cur);
8841 if (cur == NULL)
8842 break;
8843 if ((first != NULL) && (*first == cur))
8844 break;
8845 if (((t % 256) == 0) &&
8846 (first != NULL) && (*first != NULL) &&
8847 (xmlXPathCmpNodes(*first, cur) >= 0))
8848 break;
8849 if ((last != NULL) && (*last == cur))
8850 break;
8851 if (((t % 256) == 0) &&
8852 (last != NULL) && (*last != NULL) &&
8853 (xmlXPathCmpNodes(cur, *last) >= 0))
8854 break;
8855 t++;
8856 switch (test) {
8857 case NODE_TEST_NONE:
8858 ctxt->context->node = tmp;
8859 STRANGE return(0);
8860 case NODE_TEST_TYPE:
8861 if ((cur->type == type) ||
8862 ((type == NODE_TYPE_NODE) &&
8863 ((cur->type == XML_DOCUMENT_NODE) ||
8864 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8865 (cur->type == XML_ELEMENT_NODE) ||
8866 (cur->type == XML_PI_NODE) ||
8867 (cur->type == XML_COMMENT_NODE) ||
8868 (cur->type == XML_CDATA_SECTION_NODE) ||
8869 (cur->type == XML_TEXT_NODE)))) {
8870 n++;
8871 if (n == indx)
8872 addNode(list, cur);
8873 }
8874 break;
8875 case NODE_TEST_PI:
8876 if (cur->type == XML_PI_NODE) {
8877 if ((name != NULL) &&
8878 (!xmlStrEqual(name, cur->name)))
8879 break;
8880 n++;
8881 if (n == indx)
8882 addNode(list, cur);
8883 }
8884 break;
8885 case NODE_TEST_ALL:
8886 if (axis == AXIS_ATTRIBUTE) {
8887 if (cur->type == XML_ATTRIBUTE_NODE) {
8888 n++;
8889 if (n == indx)
8890 addNode(list, cur);
8891 }
8892 } else if (axis == AXIS_NAMESPACE) {
8893 if (cur->type == XML_NAMESPACE_DECL) {
8894 n++;
8895 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008896 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8897 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008898 }
8899 } else {
8900 if (cur->type == XML_ELEMENT_NODE) {
8901 if (prefix == NULL) {
8902 n++;
8903 if (n == indx)
8904 addNode(list, cur);
8905 } else if ((cur->ns != NULL) &&
8906 (xmlStrEqual(URI, cur->ns->href))) {
8907 n++;
8908 if (n == indx)
8909 addNode(list, cur);
8910 }
8911 }
8912 }
8913 break;
8914 case NODE_TEST_NS:{
8915 TODO;
8916 break;
8917 }
8918 case NODE_TEST_NAME:
8919 switch (cur->type) {
8920 case XML_ELEMENT_NODE:
8921 if (xmlStrEqual(name, cur->name)) {
8922 if (prefix == NULL) {
8923 if (cur->ns == NULL) {
8924 n++;
8925 if (n == indx)
8926 addNode(list, cur);
8927 }
8928 } else {
8929 if ((cur->ns != NULL) &&
8930 (xmlStrEqual(URI,
8931 cur->ns->href))) {
8932 n++;
8933 if (n == indx)
8934 addNode(list, cur);
8935 }
8936 }
8937 }
8938 break;
8939 case XML_ATTRIBUTE_NODE:{
8940 xmlAttrPtr attr = (xmlAttrPtr) cur;
8941
8942 if (xmlStrEqual(name, attr->name)) {
8943 if (prefix == NULL) {
8944 if ((attr->ns == NULL) ||
8945 (attr->ns->prefix == NULL)) {
8946 n++;
8947 if (n == indx)
8948 addNode(list, cur);
8949 }
8950 } else {
8951 if ((attr->ns != NULL) &&
8952 (xmlStrEqual(URI,
8953 attr->ns->
8954 href))) {
8955 n++;
8956 if (n == indx)
8957 addNode(list, cur);
8958 }
8959 }
8960 }
8961 break;
8962 }
8963 case XML_NAMESPACE_DECL:
8964 if (cur->type == XML_NAMESPACE_DECL) {
8965 xmlNsPtr ns = (xmlNsPtr) cur;
8966
8967 if ((ns->prefix != NULL) && (name != NULL)
8968 && (xmlStrEqual(ns->prefix, name))) {
8969 n++;
8970 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008971 xmlXPathNodeSetAddNs(list,
8972 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008973 }
8974 }
8975 break;
8976 default:
8977 break;
8978 }
8979 break;
8980 break;
8981 }
8982 } while (n < indx);
8983 }
8984 ctxt->context->node = tmp;
8985#ifdef DEBUG_STEP_NTH
8986 xmlGenericError(xmlGenericErrorContext,
8987 "\nExamined %d nodes, found %d nodes at that step\n",
8988 t, list->nodeNr);
8989#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008991 if ((obj->boolval) && (obj->user != NULL)) {
8992 ctxt->value->boolval = 1;
8993 ctxt->value->user = obj->user;
8994 obj->user = NULL;
8995 obj->boolval = 0;
8996 }
8997 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008998 return(t);
8999}
9000
9001/**
9002 * xmlXPathCompOpEvalFirst:
9003 * @ctxt: the XPath parser context with the compiled expression
9004 * @op: an XPath compiled operation
9005 * @first: the first elem found so far
9006 *
9007 * Evaluate the Precompiled XPath operation searching only the first
9008 * element in document order
9009 *
9010 * Returns the number of examined objects.
9011 */
9012static int
9013xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9014 xmlXPathStepOpPtr op, xmlNodePtr * first)
9015{
9016 int total = 0, cur;
9017 xmlXPathCompExprPtr comp;
9018 xmlXPathObjectPtr arg1, arg2;
9019
Daniel Veillard556c6682001-10-06 09:59:51 +00009020 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009021 comp = ctxt->comp;
9022 switch (op->op) {
9023 case XPATH_OP_END:
9024 return (0);
9025 case XPATH_OP_UNION:
9026 total =
9027 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9028 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009029 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009030 if ((ctxt->value != NULL)
9031 && (ctxt->value->type == XPATH_NODESET)
9032 && (ctxt->value->nodesetval != NULL)
9033 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9034 /*
9035 * limit tree traversing to first node in the result
9036 */
9037 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9038 *first = ctxt->value->nodesetval->nodeTab[0];
9039 }
9040 cur =
9041 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9042 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009043 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009044 CHECK_TYPE0(XPATH_NODESET);
9045 arg2 = valuePop(ctxt);
9046
9047 CHECK_TYPE0(XPATH_NODESET);
9048 arg1 = valuePop(ctxt);
9049
9050 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9051 arg2->nodesetval);
9052 valuePush(ctxt, arg1);
9053 xmlXPathFreeObject(arg2);
9054 /* optimizer */
9055 if (total > cur)
9056 xmlXPathCompSwap(op);
9057 return (total + cur);
9058 case XPATH_OP_ROOT:
9059 xmlXPathRoot(ctxt);
9060 return (0);
9061 case XPATH_OP_NODE:
9062 if (op->ch1 != -1)
9063 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009064 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009065 if (op->ch2 != -1)
9066 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009067 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009068 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9069 return (total);
9070 case XPATH_OP_RESET:
9071 if (op->ch1 != -1)
9072 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009073 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 if (op->ch2 != -1)
9075 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009076 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009077 ctxt->context->node = NULL;
9078 return (total);
9079 case XPATH_OP_COLLECT:{
9080 if (op->ch1 == -1)
9081 return (total);
9082
9083 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009084 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085
9086 /*
9087 * Optimization for [n] selection where n is a number
9088 */
9089 if ((op->ch2 != -1) &&
9090 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9091 (comp->steps[op->ch2].ch1 == -1) &&
9092 (comp->steps[op->ch2].ch2 != -1) &&
9093 (comp->steps[comp->steps[op->ch2].ch2].op ==
9094 XPATH_OP_VALUE)) {
9095 xmlXPathObjectPtr val;
9096
9097 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9098 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9099 int indx = (int) val->floatval;
9100
9101 if (val->floatval == (float) indx) {
9102 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9103 first, NULL);
9104 return (total);
9105 }
9106 }
9107 }
9108 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9109 return (total);
9110 }
9111 case XPATH_OP_VALUE:
9112 valuePush(ctxt,
9113 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9114 return (0);
9115 case XPATH_OP_SORT:
9116 if (op->ch1 != -1)
9117 total +=
9118 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9119 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009120 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 if ((ctxt->value != NULL)
9122 && (ctxt->value->type == XPATH_NODESET)
9123 && (ctxt->value->nodesetval != NULL))
9124 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9125 return (total);
9126 default:
9127 return (xmlXPathCompOpEval(ctxt, op));
9128 }
9129}
9130
9131/**
9132 * xmlXPathCompOpEvalLast:
9133 * @ctxt: the XPath parser context with the compiled expression
9134 * @op: an XPath compiled operation
9135 * @last: the last elem found so far
9136 *
9137 * Evaluate the Precompiled XPath operation searching only the last
9138 * element in document order
9139 *
9140 * Returns the number of node traversed
9141 */
9142static int
9143xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9144 xmlNodePtr * last)
9145{
9146 int total = 0, cur;
9147 xmlXPathCompExprPtr comp;
9148 xmlXPathObjectPtr arg1, arg2;
9149
Daniel Veillard556c6682001-10-06 09:59:51 +00009150 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 comp = ctxt->comp;
9152 switch (op->op) {
9153 case XPATH_OP_END:
9154 return (0);
9155 case XPATH_OP_UNION:
9156 total =
9157 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009158 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009159 if ((ctxt->value != NULL)
9160 && (ctxt->value->type == XPATH_NODESET)
9161 && (ctxt->value->nodesetval != NULL)
9162 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9163 /*
9164 * limit tree traversing to first node in the result
9165 */
9166 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9167 *last =
9168 ctxt->value->nodesetval->nodeTab[ctxt->value->
9169 nodesetval->nodeNr -
9170 1];
9171 }
9172 cur =
9173 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009174 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 if ((ctxt->value != NULL)
9176 && (ctxt->value->type == XPATH_NODESET)
9177 && (ctxt->value->nodesetval != NULL)
9178 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9179 }
9180 CHECK_TYPE0(XPATH_NODESET);
9181 arg2 = valuePop(ctxt);
9182
9183 CHECK_TYPE0(XPATH_NODESET);
9184 arg1 = valuePop(ctxt);
9185
9186 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9187 arg2->nodesetval);
9188 valuePush(ctxt, arg1);
9189 xmlXPathFreeObject(arg2);
9190 /* optimizer */
9191 if (total > cur)
9192 xmlXPathCompSwap(op);
9193 return (total + cur);
9194 case XPATH_OP_ROOT:
9195 xmlXPathRoot(ctxt);
9196 return (0);
9197 case XPATH_OP_NODE:
9198 if (op->ch1 != -1)
9199 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009200 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009201 if (op->ch2 != -1)
9202 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009203 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009204 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9205 return (total);
9206 case XPATH_OP_RESET:
9207 if (op->ch1 != -1)
9208 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009209 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009210 if (op->ch2 != -1)
9211 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009212 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009213 ctxt->context->node = NULL;
9214 return (total);
9215 case XPATH_OP_COLLECT:{
9216 if (op->ch1 == -1)
9217 return (0);
9218
9219 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009220 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009221
9222 /*
9223 * Optimization for [n] selection where n is a number
9224 */
9225 if ((op->ch2 != -1) &&
9226 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9227 (comp->steps[op->ch2].ch1 == -1) &&
9228 (comp->steps[op->ch2].ch2 != -1) &&
9229 (comp->steps[comp->steps[op->ch2].ch2].op ==
9230 XPATH_OP_VALUE)) {
9231 xmlXPathObjectPtr val;
9232
9233 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9234 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9235 int indx = (int) val->floatval;
9236
9237 if (val->floatval == (float) indx) {
9238 total +=
9239 xmlXPathNodeCollectAndTestNth(ctxt, op,
9240 indx, NULL,
9241 last);
9242 return (total);
9243 }
9244 }
9245 }
9246 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9247 return (total);
9248 }
9249 case XPATH_OP_VALUE:
9250 valuePush(ctxt,
9251 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9252 return (0);
9253 case XPATH_OP_SORT:
9254 if (op->ch1 != -1)
9255 total +=
9256 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9257 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009258 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009259 if ((ctxt->value != NULL)
9260 && (ctxt->value->type == XPATH_NODESET)
9261 && (ctxt->value->nodesetval != NULL))
9262 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9263 return (total);
9264 default:
9265 return (xmlXPathCompOpEval(ctxt, op));
9266 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009267}
9268
Owen Taylor3473f882001-02-23 17:55:21 +00009269/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009270 * xmlXPathCompOpEval:
9271 * @ctxt: the XPath parser context with the compiled expression
9272 * @op: an XPath compiled operation
9273 *
9274 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009275 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009276 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009277static int
9278xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9279{
9280 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009281 int equal, ret;
9282 xmlXPathCompExprPtr comp;
9283 xmlXPathObjectPtr arg1, arg2;
9284
Daniel Veillard556c6682001-10-06 09:59:51 +00009285 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009286 comp = ctxt->comp;
9287 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009288 case XPATH_OP_END:
9289 return (0);
9290 case XPATH_OP_AND:
9291 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009292 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009293 xmlXPathBooleanFunction(ctxt, 1);
9294 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9295 return (total);
9296 arg2 = valuePop(ctxt);
9297 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009298 if (ctxt->error) {
9299 xmlXPathFreeObject(arg2);
9300 return(0);
9301 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009302 xmlXPathBooleanFunction(ctxt, 1);
9303 arg1 = valuePop(ctxt);
9304 arg1->boolval &= arg2->boolval;
9305 valuePush(ctxt, arg1);
9306 xmlXPathFreeObject(arg2);
9307 return (total);
9308 case XPATH_OP_OR:
9309 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009310 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009311 xmlXPathBooleanFunction(ctxt, 1);
9312 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9313 return (total);
9314 arg2 = valuePop(ctxt);
9315 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009316 if (ctxt->error) {
9317 xmlXPathFreeObject(arg2);
9318 return(0);
9319 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009320 xmlXPathBooleanFunction(ctxt, 1);
9321 arg1 = valuePop(ctxt);
9322 arg1->boolval |= arg2->boolval;
9323 valuePush(ctxt, arg1);
9324 xmlXPathFreeObject(arg2);
9325 return (total);
9326 case XPATH_OP_EQUAL:
9327 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009328 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009329 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009330 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009331 equal = xmlXPathEqualValues(ctxt);
9332 if (op->value)
9333 valuePush(ctxt, xmlXPathNewBoolean(equal));
9334 else
9335 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9336 return (total);
9337 case XPATH_OP_CMP:
9338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009339 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009340 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009341 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009342 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9343 valuePush(ctxt, xmlXPathNewBoolean(ret));
9344 return (total);
9345 case XPATH_OP_PLUS:
9346 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009347 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009348 if (op->ch2 != -1)
9349 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009350 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009351 if (op->value == 0)
9352 xmlXPathSubValues(ctxt);
9353 else if (op->value == 1)
9354 xmlXPathAddValues(ctxt);
9355 else if (op->value == 2)
9356 xmlXPathValueFlipSign(ctxt);
9357 else if (op->value == 3) {
9358 CAST_TO_NUMBER;
9359 CHECK_TYPE0(XPATH_NUMBER);
9360 }
9361 return (total);
9362 case XPATH_OP_MULT:
9363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009364 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009365 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009366 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009367 if (op->value == 0)
9368 xmlXPathMultValues(ctxt);
9369 else if (op->value == 1)
9370 xmlXPathDivValues(ctxt);
9371 else if (op->value == 2)
9372 xmlXPathModValues(ctxt);
9373 return (total);
9374 case XPATH_OP_UNION:
9375 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009376 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009377 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009378 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009379 CHECK_TYPE0(XPATH_NODESET);
9380 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009381
Daniel Veillardf06307e2001-07-03 10:35:50 +00009382 CHECK_TYPE0(XPATH_NODESET);
9383 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009384
Daniel Veillardf06307e2001-07-03 10:35:50 +00009385 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9386 arg2->nodesetval);
9387 valuePush(ctxt, arg1);
9388 xmlXPathFreeObject(arg2);
9389 return (total);
9390 case XPATH_OP_ROOT:
9391 xmlXPathRoot(ctxt);
9392 return (total);
9393 case XPATH_OP_NODE:
9394 if (op->ch1 != -1)
9395 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009396 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009397 if (op->ch2 != -1)
9398 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009399 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009400 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9401 return (total);
9402 case XPATH_OP_RESET:
9403 if (op->ch1 != -1)
9404 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009405 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009406 if (op->ch2 != -1)
9407 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009408 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009409 ctxt->context->node = NULL;
9410 return (total);
9411 case XPATH_OP_COLLECT:{
9412 if (op->ch1 == -1)
9413 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009414
Daniel Veillardf06307e2001-07-03 10:35:50 +00009415 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009416 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009417
Daniel Veillardf06307e2001-07-03 10:35:50 +00009418 /*
9419 * Optimization for [n] selection where n is a number
9420 */
9421 if ((op->ch2 != -1) &&
9422 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9423 (comp->steps[op->ch2].ch1 == -1) &&
9424 (comp->steps[op->ch2].ch2 != -1) &&
9425 (comp->steps[comp->steps[op->ch2].ch2].op ==
9426 XPATH_OP_VALUE)) {
9427 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009428
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9430 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9431 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009432
Daniel Veillardf06307e2001-07-03 10:35:50 +00009433 if (val->floatval == (float) indx) {
9434 total +=
9435 xmlXPathNodeCollectAndTestNth(ctxt, op,
9436 indx, NULL,
9437 NULL);
9438 return (total);
9439 }
9440 }
9441 }
9442 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9443 return (total);
9444 }
9445 case XPATH_OP_VALUE:
9446 valuePush(ctxt,
9447 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9448 return (total);
9449 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009450 xmlXPathObjectPtr val;
9451
Daniel Veillardf06307e2001-07-03 10:35:50 +00009452 if (op->ch1 != -1)
9453 total +=
9454 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009455 if (op->value5 == NULL) {
9456 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9457 if (val == NULL) {
9458 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9459 return(0);
9460 }
9461 valuePush(ctxt, val);
9462 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009463 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009464
Daniel Veillardf06307e2001-07-03 10:35:50 +00009465 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9466 if (URI == NULL) {
9467 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009468 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009469 op->value4, op->value5);
9470 return (total);
9471 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009472 val = xmlXPathVariableLookupNS(ctxt->context,
9473 op->value4, URI);
9474 if (val == NULL) {
9475 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9476 return(0);
9477 }
9478 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009479 }
9480 return (total);
9481 }
9482 case XPATH_OP_FUNCTION:{
9483 xmlXPathFunction func;
9484 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009485 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009486
9487 if (op->ch1 != -1)
9488 total +=
9489 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009490 if (ctxt->valueNr < op->value) {
9491 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009492 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009493 ctxt->error = XPATH_INVALID_OPERAND;
9494 return (total);
9495 }
9496 for (i = 0; i < op->value; i++)
9497 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9498 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009499 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009500 ctxt->error = XPATH_INVALID_OPERAND;
9501 return (total);
9502 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009503 if (op->cache != NULL)
9504 func = (xmlXPathFunction) op->cache;
9505 else {
9506 const xmlChar *URI = NULL;
9507
9508 if (op->value5 == NULL)
9509 func =
9510 xmlXPathFunctionLookup(ctxt->context,
9511 op->value4);
9512 else {
9513 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9514 if (URI == NULL) {
9515 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009516 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009517 op->value4, op->value5);
9518 return (total);
9519 }
9520 func = xmlXPathFunctionLookupNS(ctxt->context,
9521 op->value4, URI);
9522 }
9523 if (func == NULL) {
9524 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009525 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009526 op->value4);
9527 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009528 }
9529 op->cache = (void *) func;
9530 op->cacheURI = (void *) URI;
9531 }
9532 oldFunc = ctxt->context->function;
9533 oldFuncURI = ctxt->context->functionURI;
9534 ctxt->context->function = op->value4;
9535 ctxt->context->functionURI = op->cacheURI;
9536 func(ctxt, op->value);
9537 ctxt->context->function = oldFunc;
9538 ctxt->context->functionURI = oldFuncURI;
9539 return (total);
9540 }
9541 case XPATH_OP_ARG:
9542 if (op->ch1 != -1)
9543 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009544 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009545 if (op->ch2 != -1)
9546 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009547 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009548 return (total);
9549 case XPATH_OP_PREDICATE:
9550 case XPATH_OP_FILTER:{
9551 xmlXPathObjectPtr res;
9552 xmlXPathObjectPtr obj, tmp;
9553 xmlNodeSetPtr newset = NULL;
9554 xmlNodeSetPtr oldset;
9555 xmlNodePtr oldnode;
9556 int i;
9557
9558 /*
9559 * Optimization for ()[1] selection i.e. the first elem
9560 */
9561 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9562 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9563 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9564 xmlXPathObjectPtr val;
9565
9566 val = comp->steps[op->ch2].value4;
9567 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9568 (val->floatval == 1.0)) {
9569 xmlNodePtr first = NULL;
9570
9571 total +=
9572 xmlXPathCompOpEvalFirst(ctxt,
9573 &comp->steps[op->ch1],
9574 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009575 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009576 /*
9577 * The nodeset should be in document order,
9578 * Keep only the first value
9579 */
9580 if ((ctxt->value != NULL) &&
9581 (ctxt->value->type == XPATH_NODESET) &&
9582 (ctxt->value->nodesetval != NULL) &&
9583 (ctxt->value->nodesetval->nodeNr > 1))
9584 ctxt->value->nodesetval->nodeNr = 1;
9585 return (total);
9586 }
9587 }
9588 /*
9589 * Optimization for ()[last()] selection i.e. the last elem
9590 */
9591 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9592 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9593 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9594 int f = comp->steps[op->ch2].ch1;
9595
9596 if ((f != -1) &&
9597 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9598 (comp->steps[f].value5 == NULL) &&
9599 (comp->steps[f].value == 0) &&
9600 (comp->steps[f].value4 != NULL) &&
9601 (xmlStrEqual
9602 (comp->steps[f].value4, BAD_CAST "last"))) {
9603 xmlNodePtr last = NULL;
9604
9605 total +=
9606 xmlXPathCompOpEvalLast(ctxt,
9607 &comp->steps[op->ch1],
9608 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009609 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009610 /*
9611 * The nodeset should be in document order,
9612 * Keep only the last value
9613 */
9614 if ((ctxt->value != NULL) &&
9615 (ctxt->value->type == XPATH_NODESET) &&
9616 (ctxt->value->nodesetval != NULL) &&
9617 (ctxt->value->nodesetval->nodeTab != NULL) &&
9618 (ctxt->value->nodesetval->nodeNr > 1)) {
9619 ctxt->value->nodesetval->nodeTab[0] =
9620 ctxt->value->nodesetval->nodeTab[ctxt->
9621 value->
9622 nodesetval->
9623 nodeNr -
9624 1];
9625 ctxt->value->nodesetval->nodeNr = 1;
9626 }
9627 return (total);
9628 }
9629 }
9630
9631 if (op->ch1 != -1)
9632 total +=
9633 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009634 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009635 if (op->ch2 == -1)
9636 return (total);
9637 if (ctxt->value == NULL)
9638 return (total);
9639
9640 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009641
9642#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009643 /*
9644 * Hum are we filtering the result of an XPointer expression
9645 */
9646 if (ctxt->value->type == XPATH_LOCATIONSET) {
9647 xmlLocationSetPtr newlocset = NULL;
9648 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009649
Daniel Veillardf06307e2001-07-03 10:35:50 +00009650 /*
9651 * Extract the old locset, and then evaluate the result of the
9652 * expression for all the element in the locset. use it to grow
9653 * up a new locset.
9654 */
9655 CHECK_TYPE0(XPATH_LOCATIONSET);
9656 obj = valuePop(ctxt);
9657 oldlocset = obj->user;
9658 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009659
Daniel Veillardf06307e2001-07-03 10:35:50 +00009660 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9661 ctxt->context->contextSize = 0;
9662 ctxt->context->proximityPosition = 0;
9663 if (op->ch2 != -1)
9664 total +=
9665 xmlXPathCompOpEval(ctxt,
9666 &comp->steps[op->ch2]);
9667 res = valuePop(ctxt);
9668 if (res != NULL)
9669 xmlXPathFreeObject(res);
9670 valuePush(ctxt, obj);
9671 CHECK_ERROR0;
9672 return (total);
9673 }
9674 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009675
Daniel Veillardf06307e2001-07-03 10:35:50 +00009676 for (i = 0; i < oldlocset->locNr; i++) {
9677 /*
9678 * Run the evaluation with a node list made of a
9679 * single item in the nodelocset.
9680 */
9681 ctxt->context->node = oldlocset->locTab[i]->user;
9682 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9683 valuePush(ctxt, tmp);
9684 ctxt->context->contextSize = oldlocset->locNr;
9685 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009686
Daniel Veillardf06307e2001-07-03 10:35:50 +00009687 if (op->ch2 != -1)
9688 total +=
9689 xmlXPathCompOpEval(ctxt,
9690 &comp->steps[op->ch2]);
9691 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009692
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693 /*
9694 * The result of the evaluation need to be tested to
9695 * decided whether the filter succeeded or not
9696 */
9697 res = valuePop(ctxt);
9698 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9699 xmlXPtrLocationSetAdd(newlocset,
9700 xmlXPathObjectCopy
9701 (oldlocset->locTab[i]));
9702 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009703
Daniel Veillardf06307e2001-07-03 10:35:50 +00009704 /*
9705 * Cleanup
9706 */
9707 if (res != NULL)
9708 xmlXPathFreeObject(res);
9709 if (ctxt->value == tmp) {
9710 res = valuePop(ctxt);
9711 xmlXPathFreeObject(res);
9712 }
9713
9714 ctxt->context->node = NULL;
9715 }
9716
9717 /*
9718 * The result is used as the new evaluation locset.
9719 */
9720 xmlXPathFreeObject(obj);
9721 ctxt->context->node = NULL;
9722 ctxt->context->contextSize = -1;
9723 ctxt->context->proximityPosition = -1;
9724 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9725 ctxt->context->node = oldnode;
9726 return (total);
9727 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009728#endif /* LIBXML_XPTR_ENABLED */
9729
Daniel Veillardf06307e2001-07-03 10:35:50 +00009730 /*
9731 * Extract the old set, and then evaluate the result of the
9732 * expression for all the element in the set. use it to grow
9733 * up a new set.
9734 */
9735 CHECK_TYPE0(XPATH_NODESET);
9736 obj = valuePop(ctxt);
9737 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009738
Daniel Veillardf06307e2001-07-03 10:35:50 +00009739 oldnode = ctxt->context->node;
9740 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009741
Daniel Veillardf06307e2001-07-03 10:35:50 +00009742 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9743 ctxt->context->contextSize = 0;
9744 ctxt->context->proximityPosition = 0;
9745 if (op->ch2 != -1)
9746 total +=
9747 xmlXPathCompOpEval(ctxt,
9748 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009749 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009750 res = valuePop(ctxt);
9751 if (res != NULL)
9752 xmlXPathFreeObject(res);
9753 valuePush(ctxt, obj);
9754 ctxt->context->node = oldnode;
9755 CHECK_ERROR0;
9756 } else {
9757 /*
9758 * Initialize the new set.
9759 */
9760 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009761
Daniel Veillardf06307e2001-07-03 10:35:50 +00009762 for (i = 0; i < oldset->nodeNr; i++) {
9763 /*
9764 * Run the evaluation with a node list made of
9765 * a single item in the nodeset.
9766 */
9767 ctxt->context->node = oldset->nodeTab[i];
9768 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9769 valuePush(ctxt, tmp);
9770 ctxt->context->contextSize = oldset->nodeNr;
9771 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009772
Daniel Veillardf06307e2001-07-03 10:35:50 +00009773 if (op->ch2 != -1)
9774 total +=
9775 xmlXPathCompOpEval(ctxt,
9776 &comp->steps[op->ch2]);
9777 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009778
Daniel Veillardf06307e2001-07-03 10:35:50 +00009779 /*
9780 * The result of the evaluation need to be tested to
9781 * decided whether the filter succeeded or not
9782 */
9783 res = valuePop(ctxt);
9784 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9785 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9786 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009787
Daniel Veillardf06307e2001-07-03 10:35:50 +00009788 /*
9789 * Cleanup
9790 */
9791 if (res != NULL)
9792 xmlXPathFreeObject(res);
9793 if (ctxt->value == tmp) {
9794 res = valuePop(ctxt);
9795 xmlXPathFreeObject(res);
9796 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009797
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798 ctxt->context->node = NULL;
9799 }
9800
9801 /*
9802 * The result is used as the new evaluation set.
9803 */
9804 xmlXPathFreeObject(obj);
9805 ctxt->context->node = NULL;
9806 ctxt->context->contextSize = -1;
9807 ctxt->context->proximityPosition = -1;
9808 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9809 }
9810 ctxt->context->node = oldnode;
9811 return (total);
9812 }
9813 case XPATH_OP_SORT:
9814 if (op->ch1 != -1)
9815 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009816 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009817 if ((ctxt->value != NULL) &&
9818 (ctxt->value->type == XPATH_NODESET) &&
9819 (ctxt->value->nodesetval != NULL))
9820 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9821 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009822#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009823 case XPATH_OP_RANGETO:{
9824 xmlXPathObjectPtr range;
9825 xmlXPathObjectPtr res, obj;
9826 xmlXPathObjectPtr tmp;
9827 xmlLocationSetPtr newset = NULL;
9828 xmlNodeSetPtr oldset;
9829 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009830
Daniel Veillardf06307e2001-07-03 10:35:50 +00009831 if (op->ch1 != -1)
9832 total +=
9833 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9834 if (op->ch2 == -1)
9835 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009836
Daniel Veillardf06307e2001-07-03 10:35:50 +00009837 CHECK_TYPE0(XPATH_NODESET);
9838 obj = valuePop(ctxt);
9839 oldset = obj->nodesetval;
9840 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009841
Daniel Veillardf06307e2001-07-03 10:35:50 +00009842 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009843
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844 if (oldset != NULL) {
9845 for (i = 0; i < oldset->nodeNr; i++) {
9846 /*
9847 * Run the evaluation with a node list made of a single item
9848 * in the nodeset.
9849 */
9850 ctxt->context->node = oldset->nodeTab[i];
9851 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9852 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009853
Daniel Veillardf06307e2001-07-03 10:35:50 +00009854 if (op->ch2 != -1)
9855 total +=
9856 xmlXPathCompOpEval(ctxt,
9857 &comp->steps[op->ch2]);
9858 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009859
Daniel Veillardf06307e2001-07-03 10:35:50 +00009860 /*
9861 * The result of the evaluation need to be tested to
9862 * decided whether the filter succeeded or not
9863 */
9864 res = valuePop(ctxt);
9865 range =
9866 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9867 res);
9868 if (range != NULL) {
9869 xmlXPtrLocationSetAdd(newset, range);
9870 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009871
Daniel Veillardf06307e2001-07-03 10:35:50 +00009872 /*
9873 * Cleanup
9874 */
9875 if (res != NULL)
9876 xmlXPathFreeObject(res);
9877 if (ctxt->value == tmp) {
9878 res = valuePop(ctxt);
9879 xmlXPathFreeObject(res);
9880 }
9881
9882 ctxt->context->node = NULL;
9883 }
9884 }
9885
9886 /*
9887 * The result is used as the new evaluation set.
9888 */
9889 xmlXPathFreeObject(obj);
9890 ctxt->context->node = NULL;
9891 ctxt->context->contextSize = -1;
9892 ctxt->context->proximityPosition = -1;
9893 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9894 return (total);
9895 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009896#endif /* LIBXML_XPTR_ENABLED */
9897 }
9898 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009899 "XPath: unknown precompiled operation %d\n", op->op);
9900 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009901}
9902
9903/**
9904 * xmlXPathRunEval:
9905 * @ctxt: the XPath parser context with the compiled expression
9906 *
9907 * Evaluate the Precompiled XPath expression in the given context.
9908 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009909static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009910xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9911 xmlXPathCompExprPtr comp;
9912
9913 if ((ctxt == NULL) || (ctxt->comp == NULL))
9914 return;
9915
9916 if (ctxt->valueTab == NULL) {
9917 /* Allocate the value stack */
9918 ctxt->valueTab = (xmlXPathObjectPtr *)
9919 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9920 if (ctxt->valueTab == NULL) {
9921 xmlFree(ctxt);
9922 xmlGenericError(xmlGenericErrorContext,
9923 "xmlXPathRunEval: out of memory\n");
9924 return;
9925 }
9926 ctxt->valueNr = 0;
9927 ctxt->valueMax = 10;
9928 ctxt->value = NULL;
9929 }
9930 comp = ctxt->comp;
9931 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9932}
9933
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009934/************************************************************************
9935 * *
9936 * Public interfaces *
9937 * *
9938 ************************************************************************/
9939
9940/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009941 * xmlXPathEvalPredicate:
9942 * @ctxt: the XPath context
9943 * @res: the Predicate Expression evaluation result
9944 *
9945 * Evaluate a predicate result for the current node.
9946 * A PredicateExpr is evaluated by evaluating the Expr and converting
9947 * the result to a boolean. If the result is a number, the result will
9948 * be converted to true if the number is equal to the position of the
9949 * context node in the context node list (as returned by the position
9950 * function) and will be converted to false otherwise; if the result
9951 * is not a number, then the result will be converted as if by a call
9952 * to the boolean function.
9953 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009954 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009955 */
9956int
9957xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9958 if (res == NULL) return(0);
9959 switch (res->type) {
9960 case XPATH_BOOLEAN:
9961 return(res->boolval);
9962 case XPATH_NUMBER:
9963 return(res->floatval == ctxt->proximityPosition);
9964 case XPATH_NODESET:
9965 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009966 if (res->nodesetval == NULL)
9967 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009968 return(res->nodesetval->nodeNr != 0);
9969 case XPATH_STRING:
9970 return((res->stringval != NULL) &&
9971 (xmlStrlen(res->stringval) != 0));
9972 default:
9973 STRANGE
9974 }
9975 return(0);
9976}
9977
9978/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009979 * xmlXPathEvaluatePredicateResult:
9980 * @ctxt: the XPath Parser context
9981 * @res: the Predicate Expression evaluation result
9982 *
9983 * Evaluate a predicate result for the current node.
9984 * A PredicateExpr is evaluated by evaluating the Expr and converting
9985 * the result to a boolean. If the result is a number, the result will
9986 * be converted to true if the number is equal to the position of the
9987 * context node in the context node list (as returned by the position
9988 * function) and will be converted to false otherwise; if the result
9989 * is not a number, then the result will be converted as if by a call
9990 * to the boolean function.
9991 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009992 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009993 */
9994int
9995xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9996 xmlXPathObjectPtr res) {
9997 if (res == NULL) return(0);
9998 switch (res->type) {
9999 case XPATH_BOOLEAN:
10000 return(res->boolval);
10001 case XPATH_NUMBER:
10002 return(res->floatval == ctxt->context->proximityPosition);
10003 case XPATH_NODESET:
10004 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010005 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010006 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010007 return(res->nodesetval->nodeNr != 0);
10008 case XPATH_STRING:
10009 return((res->stringval != NULL) &&
10010 (xmlStrlen(res->stringval) != 0));
10011 default:
10012 STRANGE
10013 }
10014 return(0);
10015}
10016
10017/**
10018 * xmlXPathCompile:
10019 * @str: the XPath expression
10020 *
10021 * Compile an XPath expression
10022 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010023 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010024 * the caller has to free the object.
10025 */
10026xmlXPathCompExprPtr
10027xmlXPathCompile(const xmlChar *str) {
10028 xmlXPathParserContextPtr ctxt;
10029 xmlXPathCompExprPtr comp;
10030
10031 xmlXPathInit();
10032
10033 ctxt = xmlXPathNewParserContext(str, NULL);
10034 xmlXPathCompileExpr(ctxt);
10035
Daniel Veillard40af6492001-04-22 08:50:55 +000010036 if (*ctxt->cur != 0) {
10037 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10038 comp = NULL;
10039 } else {
10040 comp = ctxt->comp;
10041 ctxt->comp = NULL;
10042 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010043 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010044#ifdef DEBUG_EVAL_COUNTS
10045 if (comp != NULL) {
10046 comp->string = xmlStrdup(str);
10047 comp->nb = 0;
10048 }
10049#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010050 return(comp);
10051}
10052
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010053/**
10054 * xmlXPathCompiledEval:
10055 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010056 * @ctx: the XPath context
10057 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010058 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010059 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010060 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010061 * the caller has to free the object.
10062 */
10063xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010064xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010065 xmlXPathParserContextPtr ctxt;
10066 xmlXPathObjectPtr res, tmp, init = NULL;
10067 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010068#ifndef LIBXML_THREAD_ENABLED
10069 static int reentance = 0;
10070#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010071
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010072 if ((comp == NULL) || (ctx == NULL))
10073 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010074 xmlXPathInit();
10075
10076 CHECK_CONTEXT(ctx)
10077
Daniel Veillard81463942001-10-16 12:34:39 +000010078#ifndef LIBXML_THREAD_ENABLED
10079 reentance++;
10080 if (reentance > 1)
10081 xmlXPathDisableOptimizer = 1;
10082#endif
10083
Daniel Veillardf06307e2001-07-03 10:35:50 +000010084#ifdef DEBUG_EVAL_COUNTS
10085 comp->nb++;
10086 if ((comp->string != NULL) && (comp->nb > 100)) {
10087 fprintf(stderr, "100 x %s\n", comp->string);
10088 comp->nb = 0;
10089 }
10090#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010091 ctxt = xmlXPathCompParserContext(comp, ctx);
10092 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010093
10094 if (ctxt->value == NULL) {
10095 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010096 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010097 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010098 } else {
10099 res = valuePop(ctxt);
10100 }
10101
Daniel Veillardf06307e2001-07-03 10:35:50 +000010102
Owen Taylor3473f882001-02-23 17:55:21 +000010103 do {
10104 tmp = valuePop(ctxt);
10105 if (tmp != NULL) {
10106 if (tmp != init)
10107 stack++;
10108 xmlXPathFreeObject(tmp);
10109 }
10110 } while (tmp != NULL);
10111 if ((stack != 0) && (res != NULL)) {
10112 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010113 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010114 stack);
10115 }
10116 if (ctxt->error != XPATH_EXPRESSION_OK) {
10117 xmlXPathFreeObject(res);
10118 res = NULL;
10119 }
10120
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010121
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010122 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010123 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010124#ifndef LIBXML_THREAD_ENABLED
10125 reentance--;
10126#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010127 return(res);
10128}
10129
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010130/**
10131 * xmlXPathEvalExpr:
10132 * @ctxt: the XPath Parser context
10133 *
10134 * Parse and evaluate an XPath expression in the given context,
10135 * then push the result on the context stack
10136 */
10137void
10138xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10139 xmlXPathCompileExpr(ctxt);
10140 xmlXPathRunEval(ctxt);
10141}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010142
10143/**
10144 * xmlXPathEval:
10145 * @str: the XPath expression
10146 * @ctx: the XPath context
10147 *
10148 * Evaluate the XPath Location Path in the given context.
10149 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010150 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010151 * the caller has to free the object.
10152 */
10153xmlXPathObjectPtr
10154xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10155 xmlXPathParserContextPtr ctxt;
10156 xmlXPathObjectPtr res, tmp, init = NULL;
10157 int stack = 0;
10158
10159 xmlXPathInit();
10160
10161 CHECK_CONTEXT(ctx)
10162
10163 ctxt = xmlXPathNewParserContext(str, ctx);
10164 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010165
10166 if (ctxt->value == NULL) {
10167 xmlGenericError(xmlGenericErrorContext,
10168 "xmlXPathEval: evaluation failed\n");
10169 res = NULL;
10170 } else if (*ctxt->cur != 0) {
10171 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10172 res = NULL;
10173 } else {
10174 res = valuePop(ctxt);
10175 }
10176
10177 do {
10178 tmp = valuePop(ctxt);
10179 if (tmp != NULL) {
10180 if (tmp != init)
10181 stack++;
10182 xmlXPathFreeObject(tmp);
10183 }
10184 } while (tmp != NULL);
10185 if ((stack != 0) && (res != NULL)) {
10186 xmlGenericError(xmlGenericErrorContext,
10187 "xmlXPathEval: %d object left on the stack\n",
10188 stack);
10189 }
10190 if (ctxt->error != XPATH_EXPRESSION_OK) {
10191 xmlXPathFreeObject(res);
10192 res = NULL;
10193 }
10194
Owen Taylor3473f882001-02-23 17:55:21 +000010195 xmlXPathFreeParserContext(ctxt);
10196 return(res);
10197}
10198
10199/**
10200 * xmlXPathEvalExpression:
10201 * @str: the XPath expression
10202 * @ctxt: the XPath context
10203 *
10204 * Evaluate the XPath expression in the given context.
10205 *
10206 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10207 * the caller has to free the object.
10208 */
10209xmlXPathObjectPtr
10210xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10211 xmlXPathParserContextPtr pctxt;
10212 xmlXPathObjectPtr res, tmp;
10213 int stack = 0;
10214
10215 xmlXPathInit();
10216
10217 CHECK_CONTEXT(ctxt)
10218
10219 pctxt = xmlXPathNewParserContext(str, ctxt);
10220 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010221
10222 if (*pctxt->cur != 0) {
10223 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10224 res = NULL;
10225 } else {
10226 res = valuePop(pctxt);
10227 }
10228 do {
10229 tmp = valuePop(pctxt);
10230 if (tmp != NULL) {
10231 xmlXPathFreeObject(tmp);
10232 stack++;
10233 }
10234 } while (tmp != NULL);
10235 if ((stack != 0) && (res != NULL)) {
10236 xmlGenericError(xmlGenericErrorContext,
10237 "xmlXPathEvalExpression: %d object left on the stack\n",
10238 stack);
10239 }
10240 xmlXPathFreeParserContext(pctxt);
10241 return(res);
10242}
10243
10244/**
10245 * xmlXPathRegisterAllFunctions:
10246 * @ctxt: the XPath context
10247 *
10248 * Registers all default XPath functions in this context
10249 */
10250void
10251xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10252{
10253 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10254 xmlXPathBooleanFunction);
10255 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10256 xmlXPathCeilingFunction);
10257 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10258 xmlXPathCountFunction);
10259 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10260 xmlXPathConcatFunction);
10261 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10262 xmlXPathContainsFunction);
10263 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10264 xmlXPathIdFunction);
10265 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10266 xmlXPathFalseFunction);
10267 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10268 xmlXPathFloorFunction);
10269 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10270 xmlXPathLastFunction);
10271 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10272 xmlXPathLangFunction);
10273 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10274 xmlXPathLocalNameFunction);
10275 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10276 xmlXPathNotFunction);
10277 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10278 xmlXPathNameFunction);
10279 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10280 xmlXPathNamespaceURIFunction);
10281 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10282 xmlXPathNormalizeFunction);
10283 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10284 xmlXPathNumberFunction);
10285 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10286 xmlXPathPositionFunction);
10287 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10288 xmlXPathRoundFunction);
10289 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10290 xmlXPathStringFunction);
10291 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10292 xmlXPathStringLengthFunction);
10293 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10294 xmlXPathStartsWithFunction);
10295 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10296 xmlXPathSubstringFunction);
10297 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10298 xmlXPathSubstringBeforeFunction);
10299 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10300 xmlXPathSubstringAfterFunction);
10301 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10302 xmlXPathSumFunction);
10303 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10304 xmlXPathTrueFunction);
10305 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10306 xmlXPathTranslateFunction);
10307}
10308
10309#endif /* LIBXML_XPATH_ENABLED */