blob: 6930812b4bf4be9c085ab8b9c3be595044c2e187 [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 *
3478 * Returns the xmlXPathContext just allocated.
3479 */
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;
6782 double ret = 0.0;
6783 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;
6790#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006791
Owen Taylor3473f882001-02-23 17:55:21 +00006792 while (IS_BLANK(*cur)) cur++;
6793 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6794 return(xmlXPathNAN);
6795 }
6796 if (*cur == '-') {
6797 isneg = 1;
6798 cur++;
6799 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006800
6801#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006802 /*
Daniel Veillardb06c6142001-08-27 14:26:30 +00006803 * tmp is a workaround against a gcc compiler bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006804 */
Owen Taylor3473f882001-02-23 17:55:21 +00006805 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006806 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006807 ok = 1;
6808 cur++;
6809 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006810 ret = (double) tmp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006811#else
6812 while ((*cur >= '0') && (*cur <= '9')) {
6813 ret = ret * 10 + (*cur - '0');
6814 ok = 1;
6815 cur++;
6816 }
6817#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006818
Owen Taylor3473f882001-02-23 17:55:21 +00006819 if (*cur == '.') {
6820 cur++;
6821 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6822 return(xmlXPathNAN);
6823 }
6824 while ((*cur >= '0') && (*cur <= '9')) {
6825 mult /= 10;
6826 ret = ret + (*cur - '0') * mult;
6827 cur++;
6828 }
6829 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006830 if ((*cur == 'e') || (*cur == 'E')) {
6831 cur++;
6832 if (*cur == '-') {
6833 is_exponent_negative = 1;
6834 cur++;
6835 }
6836 while ((*cur >= '0') && (*cur <= '9')) {
6837 exponent = exponent * 10 + (*cur - '0');
6838 cur++;
6839 }
6840 }
Owen Taylor3473f882001-02-23 17:55:21 +00006841 while (IS_BLANK(*cur)) cur++;
6842 if (*cur != 0) return(xmlXPathNAN);
6843 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006844 if (is_exponent_negative) exponent = -exponent;
6845 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006846 return(ret);
6847}
6848
6849/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006850 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006851 * @ctxt: the XPath Parser context
6852 *
6853 * [30] Number ::= Digits ('.' Digits?)?
6854 * | '.' Digits
6855 * [31] Digits ::= [0-9]+
6856 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006857 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006858 *
6859 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006860static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006861xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6862{
Owen Taylor3473f882001-02-23 17:55:21 +00006863 double ret = 0.0;
6864 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006865 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006866 int exponent = 0;
6867 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006868
6869 CHECK_ERROR;
6870 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6871 XP_ERROR(XPATH_NUMBER_ERROR);
6872 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006873 /*
6874 * Try to work around a gcc optimizer bug
6875 */
Owen Taylor3473f882001-02-23 17:55:21 +00006876 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006877 tmp = tmp * 10 + (CUR - '0');
6878 ok = 1;
6879 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006880 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006881 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006882 if (CUR == '.') {
6883 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006884 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6885 XP_ERROR(XPATH_NUMBER_ERROR);
6886 }
6887 while ((CUR >= '0') && (CUR <= '9')) {
6888 mult /= 10;
6889 ret = ret + (CUR - '0') * mult;
6890 NEXT;
6891 }
Owen Taylor3473f882001-02-23 17:55:21 +00006892 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006893 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006894 NEXT;
6895 if (CUR == '-') {
6896 is_exponent_negative = 1;
6897 NEXT;
6898 }
6899 while ((CUR >= '0') && (CUR <= '9')) {
6900 exponent = exponent * 10 + (CUR - '0');
6901 NEXT;
6902 }
6903 if (is_exponent_negative)
6904 exponent = -exponent;
6905 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006906 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006907 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006908 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006909}
6910
6911/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006912 * xmlXPathParseLiteral:
6913 * @ctxt: the XPath Parser context
6914 *
6915 * Parse a Literal
6916 *
6917 * [29] Literal ::= '"' [^"]* '"'
6918 * | "'" [^']* "'"
6919 *
6920 * Returns the value found or NULL in case of error
6921 */
6922static xmlChar *
6923xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6924 const xmlChar *q;
6925 xmlChar *ret = NULL;
6926
6927 if (CUR == '"') {
6928 NEXT;
6929 q = CUR_PTR;
6930 while ((IS_CHAR(CUR)) && (CUR != '"'))
6931 NEXT;
6932 if (!IS_CHAR(CUR)) {
6933 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6934 } else {
6935 ret = xmlStrndup(q, CUR_PTR - q);
6936 NEXT;
6937 }
6938 } else if (CUR == '\'') {
6939 NEXT;
6940 q = CUR_PTR;
6941 while ((IS_CHAR(CUR)) && (CUR != '\''))
6942 NEXT;
6943 if (!IS_CHAR(CUR)) {
6944 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6945 } else {
6946 ret = xmlStrndup(q, CUR_PTR - q);
6947 NEXT;
6948 }
6949 } else {
6950 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6951 }
6952 return(ret);
6953}
6954
6955/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006956 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006957 * @ctxt: the XPath Parser context
6958 *
6959 * Parse a Literal and push it on the stack.
6960 *
6961 * [29] Literal ::= '"' [^"]* '"'
6962 * | "'" [^']* "'"
6963 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006964 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006965 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006966static void
6967xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006968 const xmlChar *q;
6969 xmlChar *ret = NULL;
6970
6971 if (CUR == '"') {
6972 NEXT;
6973 q = CUR_PTR;
6974 while ((IS_CHAR(CUR)) && (CUR != '"'))
6975 NEXT;
6976 if (!IS_CHAR(CUR)) {
6977 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6978 } else {
6979 ret = xmlStrndup(q, CUR_PTR - q);
6980 NEXT;
6981 }
6982 } else if (CUR == '\'') {
6983 NEXT;
6984 q = CUR_PTR;
6985 while ((IS_CHAR(CUR)) && (CUR != '\''))
6986 NEXT;
6987 if (!IS_CHAR(CUR)) {
6988 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6989 } else {
6990 ret = xmlStrndup(q, CUR_PTR - q);
6991 NEXT;
6992 }
6993 } else {
6994 XP_ERROR(XPATH_START_LITERAL_ERROR);
6995 }
6996 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006997 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6998 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006999 xmlFree(ret);
7000}
7001
7002/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007003 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007004 * @ctxt: the XPath Parser context
7005 *
7006 * Parse a VariableReference, evaluate it and push it on the stack.
7007 *
7008 * The variable bindings consist of a mapping from variable names
7009 * to variable values. The value of a variable is an object, which
7010 * of any of the types that are possible for the value of an expression,
7011 * and may also be of additional types not specified here.
7012 *
7013 * Early evaluation is possible since:
7014 * The variable bindings [...] used to evaluate a subexpression are
7015 * always the same as those used to evaluate the containing expression.
7016 *
7017 * [36] VariableReference ::= '$' QName
7018 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007019static void
7020xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007021 xmlChar *name;
7022 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007023
7024 SKIP_BLANKS;
7025 if (CUR != '$') {
7026 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7027 }
7028 NEXT;
7029 name = xmlXPathParseQName(ctxt, &prefix);
7030 if (name == NULL) {
7031 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7032 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007033 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007034 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7035 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007036 SKIP_BLANKS;
7037}
7038
7039/**
7040 * xmlXPathIsNodeType:
7041 * @ctxt: the XPath Parser context
7042 * @name: a name string
7043 *
7044 * Is the name given a NodeType one.
7045 *
7046 * [38] NodeType ::= 'comment'
7047 * | 'text'
7048 * | 'processing-instruction'
7049 * | 'node'
7050 *
7051 * Returns 1 if true 0 otherwise
7052 */
7053int
7054xmlXPathIsNodeType(const xmlChar *name) {
7055 if (name == NULL)
7056 return(0);
7057
Daniel Veillard1971ee22002-01-31 20:29:19 +00007058 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007059 return(1);
7060 if (xmlStrEqual(name, BAD_CAST "text"))
7061 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007062 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007063 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007064 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007065 return(1);
7066 return(0);
7067}
7068
7069/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007070 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007071 * @ctxt: the XPath Parser context
7072 *
7073 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7074 * [17] Argument ::= Expr
7075 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007076 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007077 * pushed on the stack
7078 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007079static void
7080xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007081 xmlChar *name;
7082 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007083 int nbargs = 0;
7084
7085 name = xmlXPathParseQName(ctxt, &prefix);
7086 if (name == NULL) {
7087 XP_ERROR(XPATH_EXPR_ERROR);
7088 }
7089 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007090#ifdef DEBUG_EXPR
7091 if (prefix == NULL)
7092 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7093 name);
7094 else
7095 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7096 prefix, name);
7097#endif
7098
Owen Taylor3473f882001-02-23 17:55:21 +00007099 if (CUR != '(') {
7100 XP_ERROR(XPATH_EXPR_ERROR);
7101 }
7102 NEXT;
7103 SKIP_BLANKS;
7104
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007105 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007106 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007107 int op1 = ctxt->comp->last;
7108 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007109 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007110 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007111 nbargs++;
7112 if (CUR == ')') break;
7113 if (CUR != ',') {
7114 XP_ERROR(XPATH_EXPR_ERROR);
7115 }
7116 NEXT;
7117 SKIP_BLANKS;
7118 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007119 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7120 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007121 NEXT;
7122 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007123}
7124
7125/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007126 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007127 * @ctxt: the XPath Parser context
7128 *
7129 * [15] PrimaryExpr ::= VariableReference
7130 * | '(' Expr ')'
7131 * | Literal
7132 * | Number
7133 * | FunctionCall
7134 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007135 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007136 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007137static void
7138xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007139 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007140 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007141 else if (CUR == '(') {
7142 NEXT;
7143 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007144 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007145 if (CUR != ')') {
7146 XP_ERROR(XPATH_EXPR_ERROR);
7147 }
7148 NEXT;
7149 SKIP_BLANKS;
7150 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007151 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007152 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007153 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007154 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007155 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007156 }
7157 SKIP_BLANKS;
7158}
7159
7160/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007161 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007162 * @ctxt: the XPath Parser context
7163 *
7164 * [20] FilterExpr ::= PrimaryExpr
7165 * | FilterExpr Predicate
7166 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007167 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007168 * Square brackets are used to filter expressions in the same way that
7169 * they are used in location paths. It is an error if the expression to
7170 * be filtered does not evaluate to a node-set. The context node list
7171 * used for evaluating the expression in square brackets is the node-set
7172 * to be filtered listed in document order.
7173 */
7174
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007175static void
7176xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7177 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007178 CHECK_ERROR;
7179 SKIP_BLANKS;
7180
7181 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007182 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007183 SKIP_BLANKS;
7184 }
7185
7186
7187}
7188
7189/**
7190 * xmlXPathScanName:
7191 * @ctxt: the XPath Parser context
7192 *
7193 * Trickery: parse an XML name but without consuming the input flow
7194 * Needed to avoid insanity in the parser state.
7195 *
7196 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7197 * CombiningChar | Extender
7198 *
7199 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7200 *
7201 * [6] Names ::= Name (S Name)*
7202 *
7203 * Returns the Name parsed or NULL
7204 */
7205
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007206static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007207xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7208 xmlChar buf[XML_MAX_NAMELEN];
7209 int len = 0;
7210
7211 SKIP_BLANKS;
7212 if (!IS_LETTER(CUR) && (CUR != '_') &&
7213 (CUR != ':')) {
7214 return(NULL);
7215 }
7216
7217 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7218 (NXT(len) == '.') || (NXT(len) == '-') ||
7219 (NXT(len) == '_') || (NXT(len) == ':') ||
7220 (IS_COMBINING(NXT(len))) ||
7221 (IS_EXTENDER(NXT(len)))) {
7222 buf[len] = NXT(len);
7223 len++;
7224 if (len >= XML_MAX_NAMELEN) {
7225 xmlGenericError(xmlGenericErrorContext,
7226 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7227 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7228 (NXT(len) == '.') || (NXT(len) == '-') ||
7229 (NXT(len) == '_') || (NXT(len) == ':') ||
7230 (IS_COMBINING(NXT(len))) ||
7231 (IS_EXTENDER(NXT(len))))
7232 len++;
7233 break;
7234 }
7235 }
7236 return(xmlStrndup(buf, len));
7237}
7238
7239/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007240 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007241 * @ctxt: the XPath Parser context
7242 *
7243 * [19] PathExpr ::= LocationPath
7244 * | FilterExpr
7245 * | FilterExpr '/' RelativeLocationPath
7246 * | FilterExpr '//' RelativeLocationPath
7247 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007248 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007249 * The / operator and // operators combine an arbitrary expression
7250 * and a relative location path. It is an error if the expression
7251 * does not evaluate to a node-set.
7252 * The / operator does composition in the same way as when / is
7253 * used in a location path. As in location paths, // is short for
7254 * /descendant-or-self::node()/.
7255 */
7256
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007257static void
7258xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007259 int lc = 1; /* Should we branch to LocationPath ? */
7260 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7261
7262 SKIP_BLANKS;
7263 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7264 (CUR == '\'') || (CUR == '"')) {
7265 lc = 0;
7266 } else if (CUR == '*') {
7267 /* relative or absolute location path */
7268 lc = 1;
7269 } else if (CUR == '/') {
7270 /* relative or absolute location path */
7271 lc = 1;
7272 } else if (CUR == '@') {
7273 /* relative abbreviated attribute location path */
7274 lc = 1;
7275 } else if (CUR == '.') {
7276 /* relative abbreviated attribute location path */
7277 lc = 1;
7278 } else {
7279 /*
7280 * Problem is finding if we have a name here whether it's:
7281 * - a nodetype
7282 * - a function call in which case it's followed by '('
7283 * - an axis in which case it's followed by ':'
7284 * - a element name
7285 * We do an a priori analysis here rather than having to
7286 * maintain parsed token content through the recursive function
7287 * calls. This looks uglier but makes the code quite easier to
7288 * read/write/debug.
7289 */
7290 SKIP_BLANKS;
7291 name = xmlXPathScanName(ctxt);
7292 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7293#ifdef DEBUG_STEP
7294 xmlGenericError(xmlGenericErrorContext,
7295 "PathExpr: Axis\n");
7296#endif
7297 lc = 1;
7298 xmlFree(name);
7299 } else if (name != NULL) {
7300 int len =xmlStrlen(name);
7301 int blank = 0;
7302
7303
7304 while (NXT(len) != 0) {
7305 if (NXT(len) == '/') {
7306 /* element name */
7307#ifdef DEBUG_STEP
7308 xmlGenericError(xmlGenericErrorContext,
7309 "PathExpr: AbbrRelLocation\n");
7310#endif
7311 lc = 1;
7312 break;
7313 } else if (IS_BLANK(NXT(len))) {
7314 /* skip to next */
7315 blank = 1;
7316 } else if (NXT(len) == ':') {
7317#ifdef DEBUG_STEP
7318 xmlGenericError(xmlGenericErrorContext,
7319 "PathExpr: AbbrRelLocation\n");
7320#endif
7321 lc = 1;
7322 break;
7323 } else if ((NXT(len) == '(')) {
7324 /* Note Type or Function */
7325 if (xmlXPathIsNodeType(name)) {
7326#ifdef DEBUG_STEP
7327 xmlGenericError(xmlGenericErrorContext,
7328 "PathExpr: Type search\n");
7329#endif
7330 lc = 1;
7331 } else {
7332#ifdef DEBUG_STEP
7333 xmlGenericError(xmlGenericErrorContext,
7334 "PathExpr: function call\n");
7335#endif
7336 lc = 0;
7337 }
7338 break;
7339 } else if ((NXT(len) == '[')) {
7340 /* element name */
7341#ifdef DEBUG_STEP
7342 xmlGenericError(xmlGenericErrorContext,
7343 "PathExpr: AbbrRelLocation\n");
7344#endif
7345 lc = 1;
7346 break;
7347 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7348 (NXT(len) == '=')) {
7349 lc = 1;
7350 break;
7351 } else {
7352 lc = 1;
7353 break;
7354 }
7355 len++;
7356 }
7357 if (NXT(len) == 0) {
7358#ifdef DEBUG_STEP
7359 xmlGenericError(xmlGenericErrorContext,
7360 "PathExpr: AbbrRelLocation\n");
7361#endif
7362 /* element name */
7363 lc = 1;
7364 }
7365 xmlFree(name);
7366 } else {
7367 /* make sure all cases are covered explicitely */
7368 XP_ERROR(XPATH_EXPR_ERROR);
7369 }
7370 }
7371
7372 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007373 if (CUR == '/') {
7374 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7375 } else {
7376 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007377 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007378 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007379 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007380 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007381 CHECK_ERROR;
7382 if ((CUR == '/') && (NXT(1) == '/')) {
7383 SKIP(2);
7384 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007385
7386 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7387 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7388 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7389
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007390 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007391 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007392 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007393 }
7394 }
7395 SKIP_BLANKS;
7396}
7397
7398/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007399 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007400 * @ctxt: the XPath Parser context
7401 *
7402 * [18] UnionExpr ::= PathExpr
7403 * | UnionExpr '|' PathExpr
7404 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007405 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007406 */
7407
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007408static void
7409xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7410 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007411 CHECK_ERROR;
7412 SKIP_BLANKS;
7413 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007414 int op1 = ctxt->comp->last;
7415 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007416
7417 NEXT;
7418 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007419 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007420
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007421 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7422
Owen Taylor3473f882001-02-23 17:55:21 +00007423 SKIP_BLANKS;
7424 }
Owen Taylor3473f882001-02-23 17:55:21 +00007425}
7426
7427/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007428 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007429 * @ctxt: the XPath Parser context
7430 *
7431 * [27] UnaryExpr ::= UnionExpr
7432 * | '-' UnaryExpr
7433 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007434 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007435 */
7436
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007437static void
7438xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007439 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007440 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007441
7442 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007443 while (CUR == '-') {
7444 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007445 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007446 NEXT;
7447 SKIP_BLANKS;
7448 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007449
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007450 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007451 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007452 if (found) {
7453 if (minus)
7454 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7455 else
7456 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007457 }
7458}
7459
7460/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007461 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007462 * @ctxt: the XPath Parser context
7463 *
7464 * [26] MultiplicativeExpr ::= UnaryExpr
7465 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7466 * | MultiplicativeExpr 'div' UnaryExpr
7467 * | MultiplicativeExpr 'mod' UnaryExpr
7468 * [34] MultiplyOperator ::= '*'
7469 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007470 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007471 */
7472
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007473static void
7474xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7475 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007476 CHECK_ERROR;
7477 SKIP_BLANKS;
7478 while ((CUR == '*') ||
7479 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7480 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7481 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007482 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007483
7484 if (CUR == '*') {
7485 op = 0;
7486 NEXT;
7487 } else if (CUR == 'd') {
7488 op = 1;
7489 SKIP(3);
7490 } else if (CUR == 'm') {
7491 op = 2;
7492 SKIP(3);
7493 }
7494 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007495 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007496 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007497 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007498 SKIP_BLANKS;
7499 }
7500}
7501
7502/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007503 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007504 * @ctxt: the XPath Parser context
7505 *
7506 * [25] AdditiveExpr ::= MultiplicativeExpr
7507 * | AdditiveExpr '+' MultiplicativeExpr
7508 * | AdditiveExpr '-' MultiplicativeExpr
7509 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007510 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007511 */
7512
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007513static void
7514xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007515
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007516 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007517 CHECK_ERROR;
7518 SKIP_BLANKS;
7519 while ((CUR == '+') || (CUR == '-')) {
7520 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007521 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007522
7523 if (CUR == '+') plus = 1;
7524 else plus = 0;
7525 NEXT;
7526 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007527 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007528 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007529 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007530 SKIP_BLANKS;
7531 }
7532}
7533
7534/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007535 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007536 * @ctxt: the XPath Parser context
7537 *
7538 * [24] RelationalExpr ::= AdditiveExpr
7539 * | RelationalExpr '<' AdditiveExpr
7540 * | RelationalExpr '>' AdditiveExpr
7541 * | RelationalExpr '<=' AdditiveExpr
7542 * | RelationalExpr '>=' AdditiveExpr
7543 *
7544 * A <= B > C is allowed ? Answer from James, yes with
7545 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7546 * which is basically what got implemented.
7547 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007548 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007549 * on the stack
7550 */
7551
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007552static void
7553xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7554 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007555 CHECK_ERROR;
7556 SKIP_BLANKS;
7557 while ((CUR == '<') ||
7558 (CUR == '>') ||
7559 ((CUR == '<') && (NXT(1) == '=')) ||
7560 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007561 int inf, strict;
7562 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007563
7564 if (CUR == '<') inf = 1;
7565 else inf = 0;
7566 if (NXT(1) == '=') strict = 0;
7567 else strict = 1;
7568 NEXT;
7569 if (!strict) NEXT;
7570 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007571 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007572 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007573 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007574 SKIP_BLANKS;
7575 }
7576}
7577
7578/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007579 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007580 * @ctxt: the XPath Parser context
7581 *
7582 * [23] EqualityExpr ::= RelationalExpr
7583 * | EqualityExpr '=' RelationalExpr
7584 * | EqualityExpr '!=' RelationalExpr
7585 *
7586 * A != B != C is allowed ? Answer from James, yes with
7587 * (RelationalExpr = RelationalExpr) = RelationalExpr
7588 * (RelationalExpr != RelationalExpr) != RelationalExpr
7589 * which is basically what got implemented.
7590 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007591 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007592 *
7593 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007594static void
7595xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7596 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007597 CHECK_ERROR;
7598 SKIP_BLANKS;
7599 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007600 int eq;
7601 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007602
7603 if (CUR == '=') eq = 1;
7604 else eq = 0;
7605 NEXT;
7606 if (!eq) NEXT;
7607 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007608 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007609 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007610 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007611 SKIP_BLANKS;
7612 }
7613}
7614
7615/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007616 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007617 * @ctxt: the XPath Parser context
7618 *
7619 * [22] AndExpr ::= EqualityExpr
7620 * | AndExpr 'and' EqualityExpr
7621 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007622 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007623 *
7624 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007625static void
7626xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7627 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007628 CHECK_ERROR;
7629 SKIP_BLANKS;
7630 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007631 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007632 SKIP(3);
7633 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007634 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007635 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007636 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007637 SKIP_BLANKS;
7638 }
7639}
7640
7641/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007642 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007643 * @ctxt: the XPath Parser context
7644 *
7645 * [14] Expr ::= OrExpr
7646 * [21] OrExpr ::= AndExpr
7647 * | OrExpr 'or' AndExpr
7648 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007649 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007650 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007651static void
7652xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7653 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007654 CHECK_ERROR;
7655 SKIP_BLANKS;
7656 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007657 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007658 SKIP(2);
7659 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007660 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007661 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007662 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7663 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007664 SKIP_BLANKS;
7665 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007666 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7667 /* more ops could be optimized too */
7668 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7669 }
Owen Taylor3473f882001-02-23 17:55:21 +00007670}
7671
7672/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007673 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007674 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007675 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007676 *
7677 * [8] Predicate ::= '[' PredicateExpr ']'
7678 * [9] PredicateExpr ::= Expr
7679 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007680 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007681 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007682static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007683xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007684 int op1 = ctxt->comp->last;
7685
7686 SKIP_BLANKS;
7687 if (CUR != '[') {
7688 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7689 }
7690 NEXT;
7691 SKIP_BLANKS;
7692
7693 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007694 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007695 CHECK_ERROR;
7696
7697 if (CUR != ']') {
7698 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7699 }
7700
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007701 if (filter)
7702 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7703 else
7704 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007705
7706 NEXT;
7707 SKIP_BLANKS;
7708}
7709
7710/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007711 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007712 * @ctxt: the XPath Parser context
7713 * @test: pointer to a xmlXPathTestVal
7714 * @type: pointer to a xmlXPathTypeVal
7715 * @prefix: placeholder for a possible name prefix
7716 *
7717 * [7] NodeTest ::= NameTest
7718 * | NodeType '(' ')'
7719 * | 'processing-instruction' '(' Literal ')'
7720 *
7721 * [37] NameTest ::= '*'
7722 * | NCName ':' '*'
7723 * | QName
7724 * [38] NodeType ::= 'comment'
7725 * | 'text'
7726 * | 'processing-instruction'
7727 * | 'node'
7728 *
7729 * Returns the name found and update @test, @type and @prefix appropriately
7730 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007731static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007732xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7733 xmlXPathTypeVal *type, const xmlChar **prefix,
7734 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007735 int blanks;
7736
7737 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7738 STRANGE;
7739 return(NULL);
7740 }
7741 *type = 0;
7742 *test = 0;
7743 *prefix = NULL;
7744 SKIP_BLANKS;
7745
7746 if ((name == NULL) && (CUR == '*')) {
7747 /*
7748 * All elements
7749 */
7750 NEXT;
7751 *test = NODE_TEST_ALL;
7752 return(NULL);
7753 }
7754
7755 if (name == NULL)
7756 name = xmlXPathParseNCName(ctxt);
7757 if (name == NULL) {
7758 XP_ERROR0(XPATH_EXPR_ERROR);
7759 }
7760
7761 blanks = IS_BLANK(CUR);
7762 SKIP_BLANKS;
7763 if (CUR == '(') {
7764 NEXT;
7765 /*
7766 * NodeType or PI search
7767 */
7768 if (xmlStrEqual(name, BAD_CAST "comment"))
7769 *type = NODE_TYPE_COMMENT;
7770 else if (xmlStrEqual(name, BAD_CAST "node"))
7771 *type = NODE_TYPE_NODE;
7772 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7773 *type = NODE_TYPE_PI;
7774 else if (xmlStrEqual(name, BAD_CAST "text"))
7775 *type = NODE_TYPE_TEXT;
7776 else {
7777 if (name != NULL)
7778 xmlFree(name);
7779 XP_ERROR0(XPATH_EXPR_ERROR);
7780 }
7781
7782 *test = NODE_TEST_TYPE;
7783
7784 SKIP_BLANKS;
7785 if (*type == NODE_TYPE_PI) {
7786 /*
7787 * Specific case: search a PI by name.
7788 */
Owen Taylor3473f882001-02-23 17:55:21 +00007789 if (name != NULL)
7790 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007791 name = NULL;
7792 if (CUR != ')') {
7793 name = xmlXPathParseLiteral(ctxt);
7794 CHECK_ERROR 0;
7795 SKIP_BLANKS;
7796 }
Owen Taylor3473f882001-02-23 17:55:21 +00007797 }
7798 if (CUR != ')') {
7799 if (name != NULL)
7800 xmlFree(name);
7801 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7802 }
7803 NEXT;
7804 return(name);
7805 }
7806 *test = NODE_TEST_NAME;
7807 if ((!blanks) && (CUR == ':')) {
7808 NEXT;
7809
7810 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007811 * Since currently the parser context don't have a
7812 * namespace list associated:
7813 * The namespace name for this prefix can be computed
7814 * only at evaluation time. The compilation is done
7815 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007816 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007817#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007818 *prefix = xmlXPathNsLookup(ctxt->context, name);
7819 if (name != NULL)
7820 xmlFree(name);
7821 if (*prefix == NULL) {
7822 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7823 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007824#else
7825 *prefix = name;
7826#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007827
7828 if (CUR == '*') {
7829 /*
7830 * All elements
7831 */
7832 NEXT;
7833 *test = NODE_TEST_ALL;
7834 return(NULL);
7835 }
7836
7837 name = xmlXPathParseNCName(ctxt);
7838 if (name == NULL) {
7839 XP_ERROR0(XPATH_EXPR_ERROR);
7840 }
7841 }
7842 return(name);
7843}
7844
7845/**
7846 * xmlXPathIsAxisName:
7847 * @name: a preparsed name token
7848 *
7849 * [6] AxisName ::= 'ancestor'
7850 * | 'ancestor-or-self'
7851 * | 'attribute'
7852 * | 'child'
7853 * | 'descendant'
7854 * | 'descendant-or-self'
7855 * | 'following'
7856 * | 'following-sibling'
7857 * | 'namespace'
7858 * | 'parent'
7859 * | 'preceding'
7860 * | 'preceding-sibling'
7861 * | 'self'
7862 *
7863 * Returns the axis or 0
7864 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007865static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007866xmlXPathIsAxisName(const xmlChar *name) {
7867 xmlXPathAxisVal ret = 0;
7868 switch (name[0]) {
7869 case 'a':
7870 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7871 ret = AXIS_ANCESTOR;
7872 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7873 ret = AXIS_ANCESTOR_OR_SELF;
7874 if (xmlStrEqual(name, BAD_CAST "attribute"))
7875 ret = AXIS_ATTRIBUTE;
7876 break;
7877 case 'c':
7878 if (xmlStrEqual(name, BAD_CAST "child"))
7879 ret = AXIS_CHILD;
7880 break;
7881 case 'd':
7882 if (xmlStrEqual(name, BAD_CAST "descendant"))
7883 ret = AXIS_DESCENDANT;
7884 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7885 ret = AXIS_DESCENDANT_OR_SELF;
7886 break;
7887 case 'f':
7888 if (xmlStrEqual(name, BAD_CAST "following"))
7889 ret = AXIS_FOLLOWING;
7890 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7891 ret = AXIS_FOLLOWING_SIBLING;
7892 break;
7893 case 'n':
7894 if (xmlStrEqual(name, BAD_CAST "namespace"))
7895 ret = AXIS_NAMESPACE;
7896 break;
7897 case 'p':
7898 if (xmlStrEqual(name, BAD_CAST "parent"))
7899 ret = AXIS_PARENT;
7900 if (xmlStrEqual(name, BAD_CAST "preceding"))
7901 ret = AXIS_PRECEDING;
7902 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7903 ret = AXIS_PRECEDING_SIBLING;
7904 break;
7905 case 's':
7906 if (xmlStrEqual(name, BAD_CAST "self"))
7907 ret = AXIS_SELF;
7908 break;
7909 }
7910 return(ret);
7911}
7912
7913/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007914 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007915 * @ctxt: the XPath Parser context
7916 *
7917 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7918 * | AbbreviatedStep
7919 *
7920 * [12] AbbreviatedStep ::= '.' | '..'
7921 *
7922 * [5] AxisSpecifier ::= AxisName '::'
7923 * | AbbreviatedAxisSpecifier
7924 *
7925 * [13] AbbreviatedAxisSpecifier ::= '@'?
7926 *
7927 * Modified for XPtr range support as:
7928 *
7929 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7930 * | AbbreviatedStep
7931 * | 'range-to' '(' Expr ')' Predicate*
7932 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007933 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007934 * A location step of . is short for self::node(). This is
7935 * particularly useful in conjunction with //. For example, the
7936 * location path .//para is short for
7937 * self::node()/descendant-or-self::node()/child::para
7938 * and so will select all para descendant elements of the context
7939 * node.
7940 * Similarly, a location step of .. is short for parent::node().
7941 * For example, ../title is short for parent::node()/child::title
7942 * and so will select the title children of the parent of the context
7943 * node.
7944 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007945static void
7946xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007947#ifdef LIBXML_XPTR_ENABLED
7948 int rangeto = 0;
7949 int op2 = -1;
7950#endif
7951
Owen Taylor3473f882001-02-23 17:55:21 +00007952 SKIP_BLANKS;
7953 if ((CUR == '.') && (NXT(1) == '.')) {
7954 SKIP(2);
7955 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007956 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7957 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007958 } else if (CUR == '.') {
7959 NEXT;
7960 SKIP_BLANKS;
7961 } else {
7962 xmlChar *name = NULL;
7963 const xmlChar *prefix = NULL;
7964 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007965 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007966 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007967 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007968
7969 /*
7970 * The modification needed for XPointer change to the production
7971 */
7972#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007973 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007974 name = xmlXPathParseNCName(ctxt);
7975 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007976 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007977 xmlFree(name);
7978 SKIP_BLANKS;
7979 if (CUR != '(') {
7980 XP_ERROR(XPATH_EXPR_ERROR);
7981 }
7982 NEXT;
7983 SKIP_BLANKS;
7984
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007985 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007986 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007987 CHECK_ERROR;
7988
7989 SKIP_BLANKS;
7990 if (CUR != ')') {
7991 XP_ERROR(XPATH_EXPR_ERROR);
7992 }
7993 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007994 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007995 goto eval_predicates;
7996 }
7997 }
7998#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007999 if (CUR == '*') {
8000 axis = AXIS_CHILD;
8001 } else {
8002 if (name == NULL)
8003 name = xmlXPathParseNCName(ctxt);
8004 if (name != NULL) {
8005 axis = xmlXPathIsAxisName(name);
8006 if (axis != 0) {
8007 SKIP_BLANKS;
8008 if ((CUR == ':') && (NXT(1) == ':')) {
8009 SKIP(2);
8010 xmlFree(name);
8011 name = NULL;
8012 } else {
8013 /* an element name can conflict with an axis one :-\ */
8014 axis = AXIS_CHILD;
8015 }
Owen Taylor3473f882001-02-23 17:55:21 +00008016 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008017 axis = AXIS_CHILD;
8018 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008019 } else if (CUR == '@') {
8020 NEXT;
8021 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008022 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008023 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008024 }
Owen Taylor3473f882001-02-23 17:55:21 +00008025 }
8026
8027 CHECK_ERROR;
8028
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008029 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008030 if (test == 0)
8031 return;
8032
8033#ifdef DEBUG_STEP
8034 xmlGenericError(xmlGenericErrorContext,
8035 "Basis : computing new set\n");
8036#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008037
Owen Taylor3473f882001-02-23 17:55:21 +00008038#ifdef DEBUG_STEP
8039 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008040 if (ctxt->value == NULL)
8041 xmlGenericError(xmlGenericErrorContext, "no value\n");
8042 else if (ctxt->value->nodesetval == NULL)
8043 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8044 else
8045 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008046#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008047
8048eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008049 op1 = ctxt->comp->last;
8050 ctxt->comp->last = -1;
8051
Owen Taylor3473f882001-02-23 17:55:21 +00008052 SKIP_BLANKS;
8053 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008054 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008055 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008056
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008057#ifdef LIBXML_XPTR_ENABLED
8058 if (rangeto) {
8059 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8060 } else
8061#endif
8062 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8063 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008064
Owen Taylor3473f882001-02-23 17:55:21 +00008065 }
8066#ifdef DEBUG_STEP
8067 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008068 if (ctxt->value == NULL)
8069 xmlGenericError(xmlGenericErrorContext, "no value\n");
8070 else if (ctxt->value->nodesetval == NULL)
8071 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8072 else
8073 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8074 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008075#endif
8076}
8077
8078/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008079 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008080 * @ctxt: the XPath Parser context
8081 *
8082 * [3] RelativeLocationPath ::= Step
8083 * | RelativeLocationPath '/' Step
8084 * | AbbreviatedRelativeLocationPath
8085 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8086 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008087 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008088 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008089static void
Owen Taylor3473f882001-02-23 17:55:21 +00008090#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008091xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008092#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008093xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008094#endif
8095(xmlXPathParserContextPtr ctxt) {
8096 SKIP_BLANKS;
8097 if ((CUR == '/') && (NXT(1) == '/')) {
8098 SKIP(2);
8099 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008100 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8101 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008102 } else if (CUR == '/') {
8103 NEXT;
8104 SKIP_BLANKS;
8105 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008106 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008107 SKIP_BLANKS;
8108 while (CUR == '/') {
8109 if ((CUR == '/') && (NXT(1) == '/')) {
8110 SKIP(2);
8111 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008112 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008113 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008114 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008115 } else if (CUR == '/') {
8116 NEXT;
8117 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008118 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008119 }
8120 SKIP_BLANKS;
8121 }
8122}
8123
8124/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008125 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008126 * @ctxt: the XPath Parser context
8127 *
8128 * [1] LocationPath ::= RelativeLocationPath
8129 * | AbsoluteLocationPath
8130 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8131 * | AbbreviatedAbsoluteLocationPath
8132 * [10] AbbreviatedAbsoluteLocationPath ::=
8133 * '//' RelativeLocationPath
8134 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008135 * Compile a location path
8136 *
Owen Taylor3473f882001-02-23 17:55:21 +00008137 * // is short for /descendant-or-self::node()/. For example,
8138 * //para is short for /descendant-or-self::node()/child::para and
8139 * so will select any para element in the document (even a para element
8140 * that is a document element will be selected by //para since the
8141 * document element node is a child of the root node); div//para is
8142 * short for div/descendant-or-self::node()/child::para and so will
8143 * select all para descendants of div children.
8144 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008145static void
8146xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008147 SKIP_BLANKS;
8148 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008149 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008150 } else {
8151 while (CUR == '/') {
8152 if ((CUR == '/') && (NXT(1) == '/')) {
8153 SKIP(2);
8154 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008155 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8156 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008157 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008158 } else if (CUR == '/') {
8159 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008160 SKIP_BLANKS;
8161 if ((CUR != 0 ) &&
8162 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8163 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008164 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008165 }
8166 }
8167 }
8168}
8169
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008170/************************************************************************
8171 * *
8172 * XPath precompiled expression evaluation *
8173 * *
8174 ************************************************************************/
8175
Daniel Veillardf06307e2001-07-03 10:35:50 +00008176static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008177xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8178
8179/**
8180 * xmlXPathNodeCollectAndTest:
8181 * @ctxt: the XPath Parser context
8182 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008183 * @first: pointer to the first element in document order
8184 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008185 *
8186 * This is the function implementing a step: based on the current list
8187 * of nodes, it builds up a new list, looking at all nodes under that
8188 * axis and selecting them it also do the predicate filtering
8189 *
8190 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008191 *
8192 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008193 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008194static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008195xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008196 xmlXPathStepOpPtr op,
8197 xmlNodePtr * first, xmlNodePtr * last)
8198{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008199 xmlXPathAxisVal axis = op->value;
8200 xmlXPathTestVal test = op->value2;
8201 xmlXPathTypeVal type = op->value3;
8202 const xmlChar *prefix = op->value4;
8203 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008204 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008205
8206#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008207 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008208#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008209 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008210 xmlNodeSetPtr ret, list;
8211 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008212 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008213 xmlNodePtr cur = NULL;
8214 xmlXPathObjectPtr obj;
8215 xmlNodeSetPtr nodelist;
8216 xmlNodePtr tmp;
8217
Daniel Veillardf06307e2001-07-03 10:35:50 +00008218 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008219 obj = valuePop(ctxt);
8220 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008221 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008222 URI = xmlXPathNsLookup(ctxt->context, prefix);
8223 if (URI == NULL)
8224 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008225 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008226#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008227 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008228#endif
8229 switch (axis) {
8230 case AXIS_ANCESTOR:
8231#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008232 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008233#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008234 first = NULL;
8235 next = xmlXPathNextAncestor;
8236 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008237 case AXIS_ANCESTOR_OR_SELF:
8238#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008239 xmlGenericError(xmlGenericErrorContext,
8240 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008241#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008242 first = NULL;
8243 next = xmlXPathNextAncestorOrSelf;
8244 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008245 case AXIS_ATTRIBUTE:
8246#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008247 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008248#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008249 first = NULL;
8250 last = NULL;
8251 next = xmlXPathNextAttribute;
8252 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008253 case AXIS_CHILD:
8254#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008255 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008256#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008257 last = NULL;
8258 next = xmlXPathNextChild;
8259 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008260 case AXIS_DESCENDANT:
8261#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008262 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008263#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008264 last = NULL;
8265 next = xmlXPathNextDescendant;
8266 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008267 case AXIS_DESCENDANT_OR_SELF:
8268#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008269 xmlGenericError(xmlGenericErrorContext,
8270 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008271#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008272 last = NULL;
8273 next = xmlXPathNextDescendantOrSelf;
8274 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008275 case AXIS_FOLLOWING:
8276#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008277 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008278#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008279 last = NULL;
8280 next = xmlXPathNextFollowing;
8281 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008282 case AXIS_FOLLOWING_SIBLING:
8283#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008284 xmlGenericError(xmlGenericErrorContext,
8285 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008286#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008287 last = NULL;
8288 next = xmlXPathNextFollowingSibling;
8289 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008290 case AXIS_NAMESPACE:
8291#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008292 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008293#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008294 first = NULL;
8295 last = NULL;
8296 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8297 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008298 case AXIS_PARENT:
8299#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008300 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008301#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008302 first = NULL;
8303 next = xmlXPathNextParent;
8304 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008305 case AXIS_PRECEDING:
8306#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008307 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008308#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008309 first = NULL;
8310 next = xmlXPathNextPrecedingInternal;
8311 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008312 case AXIS_PRECEDING_SIBLING:
8313#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008314 xmlGenericError(xmlGenericErrorContext,
8315 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008316#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008317 first = NULL;
8318 next = xmlXPathNextPrecedingSibling;
8319 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008320 case AXIS_SELF:
8321#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008322 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008323#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008324 first = NULL;
8325 last = NULL;
8326 next = xmlXPathNextSelf;
8327 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008328 }
8329 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008330 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008331
8332 nodelist = obj->nodesetval;
8333 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008334 xmlXPathFreeObject(obj);
8335 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8336 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008337 }
8338 addNode = xmlXPathNodeSetAddUnique;
8339 ret = NULL;
8340#ifdef DEBUG_STEP
8341 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008342 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008343 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008344 case NODE_TEST_NONE:
8345 xmlGenericError(xmlGenericErrorContext,
8346 " searching for none !!!\n");
8347 break;
8348 case NODE_TEST_TYPE:
8349 xmlGenericError(xmlGenericErrorContext,
8350 " searching for type %d\n", type);
8351 break;
8352 case NODE_TEST_PI:
8353 xmlGenericError(xmlGenericErrorContext,
8354 " searching for PI !!!\n");
8355 break;
8356 case NODE_TEST_ALL:
8357 xmlGenericError(xmlGenericErrorContext,
8358 " searching for *\n");
8359 break;
8360 case NODE_TEST_NS:
8361 xmlGenericError(xmlGenericErrorContext,
8362 " searching for namespace %s\n",
8363 prefix);
8364 break;
8365 case NODE_TEST_NAME:
8366 xmlGenericError(xmlGenericErrorContext,
8367 " searching for name %s\n", name);
8368 if (prefix != NULL)
8369 xmlGenericError(xmlGenericErrorContext,
8370 " with namespace %s\n", prefix);
8371 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008372 }
8373 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8374#endif
8375 /*
8376 * 2.3 Node Tests
8377 * - For the attribute axis, the principal node type is attribute.
8378 * - For the namespace axis, the principal node type is namespace.
8379 * - For other axes, the principal node type is element.
8380 *
8381 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008382 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008383 * select all element children of the context node
8384 */
8385 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008386 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008387 ctxt->context->node = nodelist->nodeTab[i];
8388
Daniel Veillardf06307e2001-07-03 10:35:50 +00008389 cur = NULL;
8390 list = xmlXPathNodeSetCreate(NULL);
8391 do {
8392 cur = next(ctxt, cur);
8393 if (cur == NULL)
8394 break;
8395 if ((first != NULL) && (*first == cur))
8396 break;
8397 if (((t % 256) == 0) &&
8398 (first != NULL) && (*first != NULL) &&
8399 (xmlXPathCmpNodes(*first, cur) >= 0))
8400 break;
8401 if ((last != NULL) && (*last == cur))
8402 break;
8403 if (((t % 256) == 0) &&
8404 (last != NULL) && (*last != NULL) &&
8405 (xmlXPathCmpNodes(cur, *last) >= 0))
8406 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008407 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008408#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008409 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8410#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008411 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008412 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008413 ctxt->context->node = tmp;
8414 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008415 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008416 if ((cur->type == type) ||
8417 ((type == NODE_TYPE_NODE) &&
8418 ((cur->type == XML_DOCUMENT_NODE) ||
8419 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8420 (cur->type == XML_ELEMENT_NODE) ||
8421 (cur->type == XML_PI_NODE) ||
8422 (cur->type == XML_COMMENT_NODE) ||
8423 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008424 (cur->type == XML_TEXT_NODE))) ||
8425 ((type == NODE_TYPE_TEXT) &&
8426 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008427#ifdef DEBUG_STEP
8428 n++;
8429#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008430 addNode(list, cur);
8431 }
8432 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008433 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008434 if (cur->type == XML_PI_NODE) {
8435 if ((name != NULL) &&
8436 (!xmlStrEqual(name, cur->name)))
8437 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008438#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008439 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008440#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008441 addNode(list, cur);
8442 }
8443 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008444 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008445 if (axis == AXIS_ATTRIBUTE) {
8446 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008447#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008448 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008449#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008450 addNode(list, cur);
8451 }
8452 } else if (axis == AXIS_NAMESPACE) {
8453 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008454#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008455 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008456#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008457 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8458 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008459 }
8460 } else {
8461 if (cur->type == XML_ELEMENT_NODE) {
8462 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008463#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008464 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008465#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008466 addNode(list, cur);
8467 } else if ((cur->ns != NULL) &&
8468 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008469#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008470 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008471#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008472 addNode(list, cur);
8473 }
8474 }
8475 }
8476 break;
8477 case NODE_TEST_NS:{
8478 TODO;
8479 break;
8480 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008481 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008482 switch (cur->type) {
8483 case XML_ELEMENT_NODE:
8484 if (xmlStrEqual(name, cur->name)) {
8485 if (prefix == NULL) {
8486 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008487#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008488 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008489#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008490 addNode(list, cur);
8491 }
8492 } else {
8493 if ((cur->ns != NULL) &&
8494 (xmlStrEqual(URI,
8495 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008496#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008497 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008498#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008499 addNode(list, cur);
8500 }
8501 }
8502 }
8503 break;
8504 case XML_ATTRIBUTE_NODE:{
8505 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008506
Daniel Veillardf06307e2001-07-03 10:35:50 +00008507 if (xmlStrEqual(name, attr->name)) {
8508 if (prefix == NULL) {
8509 if ((attr->ns == NULL) ||
8510 (attr->ns->prefix == NULL)) {
8511#ifdef DEBUG_STEP
8512 n++;
8513#endif
8514 addNode(list,
8515 (xmlNodePtr) attr);
8516 }
8517 } else {
8518 if ((attr->ns != NULL) &&
8519 (xmlStrEqual(URI,
8520 attr->ns->
8521 href))) {
8522#ifdef DEBUG_STEP
8523 n++;
8524#endif
8525 addNode(list,
8526 (xmlNodePtr) attr);
8527 }
8528 }
8529 }
8530 break;
8531 }
8532 case XML_NAMESPACE_DECL:
8533 if (cur->type == XML_NAMESPACE_DECL) {
8534 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008535
Daniel Veillardf06307e2001-07-03 10:35:50 +00008536 if ((ns->prefix != NULL) && (name != NULL)
8537 && (xmlStrEqual(ns->prefix, name))) {
8538#ifdef DEBUG_STEP
8539 n++;
8540#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008541 xmlXPathNodeSetAddNs(list,
8542 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008543 }
8544 }
8545 break;
8546 default:
8547 break;
8548 }
8549 break;
8550 break;
8551 }
8552 } while (cur != NULL);
8553
8554 /*
8555 * If there is some predicate filtering do it now
8556 */
8557 if (op->ch2 != -1) {
8558 xmlXPathObjectPtr obj2;
8559
8560 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8561 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8562 CHECK_TYPE0(XPATH_NODESET);
8563 obj2 = valuePop(ctxt);
8564 list = obj2->nodesetval;
8565 obj2->nodesetval = NULL;
8566 xmlXPathFreeObject(obj2);
8567 }
8568 if (ret == NULL) {
8569 ret = list;
8570 } else {
8571 ret = xmlXPathNodeSetMerge(ret, list);
8572 xmlXPathFreeNodeSet(list);
8573 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008574 }
8575 ctxt->context->node = tmp;
8576#ifdef DEBUG_STEP
8577 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008578 "\nExamined %d nodes, found %d nodes at that step\n",
8579 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008580#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008581 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008582 if ((obj->boolval) && (obj->user != NULL)) {
8583 ctxt->value->boolval = 1;
8584 ctxt->value->user = obj->user;
8585 obj->user = NULL;
8586 obj->boolval = 0;
8587 }
8588 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008589 return(t);
8590}
8591
8592/**
8593 * xmlXPathNodeCollectAndTestNth:
8594 * @ctxt: the XPath Parser context
8595 * @op: the XPath precompiled step operation
8596 * @indx: the index to collect
8597 * @first: pointer to the first element in document order
8598 * @last: pointer to the last element in document order
8599 *
8600 * This is the function implementing a step: based on the current list
8601 * of nodes, it builds up a new list, looking at all nodes under that
8602 * axis and selecting them it also do the predicate filtering
8603 *
8604 * Pushes the new NodeSet resulting from the search.
8605 * Returns the number of node traversed
8606 */
8607static int
8608xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8609 xmlXPathStepOpPtr op, int indx,
8610 xmlNodePtr * first, xmlNodePtr * last)
8611{
8612 xmlXPathAxisVal axis = op->value;
8613 xmlXPathTestVal test = op->value2;
8614 xmlXPathTypeVal type = op->value3;
8615 const xmlChar *prefix = op->value4;
8616 const xmlChar *name = op->value5;
8617 const xmlChar *URI = NULL;
8618 int n = 0, t = 0;
8619
8620 int i;
8621 xmlNodeSetPtr list;
8622 xmlXPathTraversalFunction next = NULL;
8623 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8624 xmlNodePtr cur = NULL;
8625 xmlXPathObjectPtr obj;
8626 xmlNodeSetPtr nodelist;
8627 xmlNodePtr tmp;
8628
8629 CHECK_TYPE0(XPATH_NODESET);
8630 obj = valuePop(ctxt);
8631 addNode = xmlXPathNodeSetAdd;
8632 if (prefix != NULL) {
8633 URI = xmlXPathNsLookup(ctxt->context, prefix);
8634 if (URI == NULL)
8635 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8636 }
8637#ifdef DEBUG_STEP_NTH
8638 xmlGenericError(xmlGenericErrorContext, "new step : ");
8639 if (first != NULL) {
8640 if (*first != NULL)
8641 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8642 (*first)->name);
8643 else
8644 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8645 }
8646 if (last != NULL) {
8647 if (*last != NULL)
8648 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8649 (*last)->name);
8650 else
8651 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8652 }
8653#endif
8654 switch (axis) {
8655 case AXIS_ANCESTOR:
8656#ifdef DEBUG_STEP_NTH
8657 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8658#endif
8659 first = NULL;
8660 next = xmlXPathNextAncestor;
8661 break;
8662 case AXIS_ANCESTOR_OR_SELF:
8663#ifdef DEBUG_STEP_NTH
8664 xmlGenericError(xmlGenericErrorContext,
8665 "axis 'ancestors-or-self' ");
8666#endif
8667 first = NULL;
8668 next = xmlXPathNextAncestorOrSelf;
8669 break;
8670 case AXIS_ATTRIBUTE:
8671#ifdef DEBUG_STEP_NTH
8672 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8673#endif
8674 first = NULL;
8675 last = NULL;
8676 next = xmlXPathNextAttribute;
8677 break;
8678 case AXIS_CHILD:
8679#ifdef DEBUG_STEP_NTH
8680 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8681#endif
8682 last = NULL;
8683 next = xmlXPathNextChild;
8684 break;
8685 case AXIS_DESCENDANT:
8686#ifdef DEBUG_STEP_NTH
8687 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8688#endif
8689 last = NULL;
8690 next = xmlXPathNextDescendant;
8691 break;
8692 case AXIS_DESCENDANT_OR_SELF:
8693#ifdef DEBUG_STEP_NTH
8694 xmlGenericError(xmlGenericErrorContext,
8695 "axis 'descendant-or-self' ");
8696#endif
8697 last = NULL;
8698 next = xmlXPathNextDescendantOrSelf;
8699 break;
8700 case AXIS_FOLLOWING:
8701#ifdef DEBUG_STEP_NTH
8702 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8703#endif
8704 last = NULL;
8705 next = xmlXPathNextFollowing;
8706 break;
8707 case AXIS_FOLLOWING_SIBLING:
8708#ifdef DEBUG_STEP_NTH
8709 xmlGenericError(xmlGenericErrorContext,
8710 "axis 'following-siblings' ");
8711#endif
8712 last = NULL;
8713 next = xmlXPathNextFollowingSibling;
8714 break;
8715 case AXIS_NAMESPACE:
8716#ifdef DEBUG_STEP_NTH
8717 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8718#endif
8719 last = NULL;
8720 first = NULL;
8721 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8722 break;
8723 case AXIS_PARENT:
8724#ifdef DEBUG_STEP_NTH
8725 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8726#endif
8727 first = NULL;
8728 next = xmlXPathNextParent;
8729 break;
8730 case AXIS_PRECEDING:
8731#ifdef DEBUG_STEP_NTH
8732 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8733#endif
8734 first = NULL;
8735 next = xmlXPathNextPrecedingInternal;
8736 break;
8737 case AXIS_PRECEDING_SIBLING:
8738#ifdef DEBUG_STEP_NTH
8739 xmlGenericError(xmlGenericErrorContext,
8740 "axis 'preceding-sibling' ");
8741#endif
8742 first = NULL;
8743 next = xmlXPathNextPrecedingSibling;
8744 break;
8745 case AXIS_SELF:
8746#ifdef DEBUG_STEP_NTH
8747 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8748#endif
8749 first = NULL;
8750 last = NULL;
8751 next = xmlXPathNextSelf;
8752 break;
8753 }
8754 if (next == NULL)
8755 return(0);
8756
8757 nodelist = obj->nodesetval;
8758 if (nodelist == NULL) {
8759 xmlXPathFreeObject(obj);
8760 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8761 return(0);
8762 }
8763 addNode = xmlXPathNodeSetAddUnique;
8764#ifdef DEBUG_STEP_NTH
8765 xmlGenericError(xmlGenericErrorContext,
8766 " context contains %d nodes\n", nodelist->nodeNr);
8767 switch (test) {
8768 case NODE_TEST_NONE:
8769 xmlGenericError(xmlGenericErrorContext,
8770 " searching for none !!!\n");
8771 break;
8772 case NODE_TEST_TYPE:
8773 xmlGenericError(xmlGenericErrorContext,
8774 " searching for type %d\n", type);
8775 break;
8776 case NODE_TEST_PI:
8777 xmlGenericError(xmlGenericErrorContext,
8778 " searching for PI !!!\n");
8779 break;
8780 case NODE_TEST_ALL:
8781 xmlGenericError(xmlGenericErrorContext,
8782 " searching for *\n");
8783 break;
8784 case NODE_TEST_NS:
8785 xmlGenericError(xmlGenericErrorContext,
8786 " searching for namespace %s\n",
8787 prefix);
8788 break;
8789 case NODE_TEST_NAME:
8790 xmlGenericError(xmlGenericErrorContext,
8791 " searching for name %s\n", name);
8792 if (prefix != NULL)
8793 xmlGenericError(xmlGenericErrorContext,
8794 " with namespace %s\n", prefix);
8795 break;
8796 }
8797 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8798#endif
8799 /*
8800 * 2.3 Node Tests
8801 * - For the attribute axis, the principal node type is attribute.
8802 * - For the namespace axis, the principal node type is namespace.
8803 * - For other axes, the principal node type is element.
8804 *
8805 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008806 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008807 * select all element children of the context node
8808 */
8809 tmp = ctxt->context->node;
8810 list = xmlXPathNodeSetCreate(NULL);
8811 for (i = 0; i < nodelist->nodeNr; i++) {
8812 ctxt->context->node = nodelist->nodeTab[i];
8813
8814 cur = NULL;
8815 n = 0;
8816 do {
8817 cur = next(ctxt, cur);
8818 if (cur == NULL)
8819 break;
8820 if ((first != NULL) && (*first == cur))
8821 break;
8822 if (((t % 256) == 0) &&
8823 (first != NULL) && (*first != NULL) &&
8824 (xmlXPathCmpNodes(*first, cur) >= 0))
8825 break;
8826 if ((last != NULL) && (*last == cur))
8827 break;
8828 if (((t % 256) == 0) &&
8829 (last != NULL) && (*last != NULL) &&
8830 (xmlXPathCmpNodes(cur, *last) >= 0))
8831 break;
8832 t++;
8833 switch (test) {
8834 case NODE_TEST_NONE:
8835 ctxt->context->node = tmp;
8836 STRANGE return(0);
8837 case NODE_TEST_TYPE:
8838 if ((cur->type == type) ||
8839 ((type == NODE_TYPE_NODE) &&
8840 ((cur->type == XML_DOCUMENT_NODE) ||
8841 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8842 (cur->type == XML_ELEMENT_NODE) ||
8843 (cur->type == XML_PI_NODE) ||
8844 (cur->type == XML_COMMENT_NODE) ||
8845 (cur->type == XML_CDATA_SECTION_NODE) ||
8846 (cur->type == XML_TEXT_NODE)))) {
8847 n++;
8848 if (n == indx)
8849 addNode(list, cur);
8850 }
8851 break;
8852 case NODE_TEST_PI:
8853 if (cur->type == XML_PI_NODE) {
8854 if ((name != NULL) &&
8855 (!xmlStrEqual(name, cur->name)))
8856 break;
8857 n++;
8858 if (n == indx)
8859 addNode(list, cur);
8860 }
8861 break;
8862 case NODE_TEST_ALL:
8863 if (axis == AXIS_ATTRIBUTE) {
8864 if (cur->type == XML_ATTRIBUTE_NODE) {
8865 n++;
8866 if (n == indx)
8867 addNode(list, cur);
8868 }
8869 } else if (axis == AXIS_NAMESPACE) {
8870 if (cur->type == XML_NAMESPACE_DECL) {
8871 n++;
8872 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008873 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8874 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 }
8876 } else {
8877 if (cur->type == XML_ELEMENT_NODE) {
8878 if (prefix == NULL) {
8879 n++;
8880 if (n == indx)
8881 addNode(list, cur);
8882 } else if ((cur->ns != NULL) &&
8883 (xmlStrEqual(URI, cur->ns->href))) {
8884 n++;
8885 if (n == indx)
8886 addNode(list, cur);
8887 }
8888 }
8889 }
8890 break;
8891 case NODE_TEST_NS:{
8892 TODO;
8893 break;
8894 }
8895 case NODE_TEST_NAME:
8896 switch (cur->type) {
8897 case XML_ELEMENT_NODE:
8898 if (xmlStrEqual(name, cur->name)) {
8899 if (prefix == NULL) {
8900 if (cur->ns == NULL) {
8901 n++;
8902 if (n == indx)
8903 addNode(list, cur);
8904 }
8905 } else {
8906 if ((cur->ns != NULL) &&
8907 (xmlStrEqual(URI,
8908 cur->ns->href))) {
8909 n++;
8910 if (n == indx)
8911 addNode(list, cur);
8912 }
8913 }
8914 }
8915 break;
8916 case XML_ATTRIBUTE_NODE:{
8917 xmlAttrPtr attr = (xmlAttrPtr) cur;
8918
8919 if (xmlStrEqual(name, attr->name)) {
8920 if (prefix == NULL) {
8921 if ((attr->ns == NULL) ||
8922 (attr->ns->prefix == NULL)) {
8923 n++;
8924 if (n == indx)
8925 addNode(list, cur);
8926 }
8927 } else {
8928 if ((attr->ns != NULL) &&
8929 (xmlStrEqual(URI,
8930 attr->ns->
8931 href))) {
8932 n++;
8933 if (n == indx)
8934 addNode(list, cur);
8935 }
8936 }
8937 }
8938 break;
8939 }
8940 case XML_NAMESPACE_DECL:
8941 if (cur->type == XML_NAMESPACE_DECL) {
8942 xmlNsPtr ns = (xmlNsPtr) cur;
8943
8944 if ((ns->prefix != NULL) && (name != NULL)
8945 && (xmlStrEqual(ns->prefix, name))) {
8946 n++;
8947 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008948 xmlXPathNodeSetAddNs(list,
8949 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008950 }
8951 }
8952 break;
8953 default:
8954 break;
8955 }
8956 break;
8957 break;
8958 }
8959 } while (n < indx);
8960 }
8961 ctxt->context->node = tmp;
8962#ifdef DEBUG_STEP_NTH
8963 xmlGenericError(xmlGenericErrorContext,
8964 "\nExamined %d nodes, found %d nodes at that step\n",
8965 t, list->nodeNr);
8966#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008968 if ((obj->boolval) && (obj->user != NULL)) {
8969 ctxt->value->boolval = 1;
8970 ctxt->value->user = obj->user;
8971 obj->user = NULL;
8972 obj->boolval = 0;
8973 }
8974 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 return(t);
8976}
8977
8978/**
8979 * xmlXPathCompOpEvalFirst:
8980 * @ctxt: the XPath parser context with the compiled expression
8981 * @op: an XPath compiled operation
8982 * @first: the first elem found so far
8983 *
8984 * Evaluate the Precompiled XPath operation searching only the first
8985 * element in document order
8986 *
8987 * Returns the number of examined objects.
8988 */
8989static int
8990xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8991 xmlXPathStepOpPtr op, xmlNodePtr * first)
8992{
8993 int total = 0, cur;
8994 xmlXPathCompExprPtr comp;
8995 xmlXPathObjectPtr arg1, arg2;
8996
Daniel Veillard556c6682001-10-06 09:59:51 +00008997 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008998 comp = ctxt->comp;
8999 switch (op->op) {
9000 case XPATH_OP_END:
9001 return (0);
9002 case XPATH_OP_UNION:
9003 total =
9004 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9005 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009006 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009007 if ((ctxt->value != NULL)
9008 && (ctxt->value->type == XPATH_NODESET)
9009 && (ctxt->value->nodesetval != NULL)
9010 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9011 /*
9012 * limit tree traversing to first node in the result
9013 */
9014 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9015 *first = ctxt->value->nodesetval->nodeTab[0];
9016 }
9017 cur =
9018 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9019 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009020 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009021 CHECK_TYPE0(XPATH_NODESET);
9022 arg2 = valuePop(ctxt);
9023
9024 CHECK_TYPE0(XPATH_NODESET);
9025 arg1 = valuePop(ctxt);
9026
9027 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9028 arg2->nodesetval);
9029 valuePush(ctxt, arg1);
9030 xmlXPathFreeObject(arg2);
9031 /* optimizer */
9032 if (total > cur)
9033 xmlXPathCompSwap(op);
9034 return (total + cur);
9035 case XPATH_OP_ROOT:
9036 xmlXPathRoot(ctxt);
9037 return (0);
9038 case XPATH_OP_NODE:
9039 if (op->ch1 != -1)
9040 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009041 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009042 if (op->ch2 != -1)
9043 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009044 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009045 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9046 return (total);
9047 case XPATH_OP_RESET:
9048 if (op->ch1 != -1)
9049 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009050 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 if (op->ch2 != -1)
9052 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009053 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009054 ctxt->context->node = NULL;
9055 return (total);
9056 case XPATH_OP_COLLECT:{
9057 if (op->ch1 == -1)
9058 return (total);
9059
9060 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009061 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062
9063 /*
9064 * Optimization for [n] selection where n is a number
9065 */
9066 if ((op->ch2 != -1) &&
9067 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9068 (comp->steps[op->ch2].ch1 == -1) &&
9069 (comp->steps[op->ch2].ch2 != -1) &&
9070 (comp->steps[comp->steps[op->ch2].ch2].op ==
9071 XPATH_OP_VALUE)) {
9072 xmlXPathObjectPtr val;
9073
9074 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9075 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9076 int indx = (int) val->floatval;
9077
9078 if (val->floatval == (float) indx) {
9079 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9080 first, NULL);
9081 return (total);
9082 }
9083 }
9084 }
9085 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9086 return (total);
9087 }
9088 case XPATH_OP_VALUE:
9089 valuePush(ctxt,
9090 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9091 return (0);
9092 case XPATH_OP_SORT:
9093 if (op->ch1 != -1)
9094 total +=
9095 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9096 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009097 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 if ((ctxt->value != NULL)
9099 && (ctxt->value->type == XPATH_NODESET)
9100 && (ctxt->value->nodesetval != NULL))
9101 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9102 return (total);
9103 default:
9104 return (xmlXPathCompOpEval(ctxt, op));
9105 }
9106}
9107
9108/**
9109 * xmlXPathCompOpEvalLast:
9110 * @ctxt: the XPath parser context with the compiled expression
9111 * @op: an XPath compiled operation
9112 * @last: the last elem found so far
9113 *
9114 * Evaluate the Precompiled XPath operation searching only the last
9115 * element in document order
9116 *
9117 * Returns the number of node traversed
9118 */
9119static int
9120xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9121 xmlNodePtr * last)
9122{
9123 int total = 0, cur;
9124 xmlXPathCompExprPtr comp;
9125 xmlXPathObjectPtr arg1, arg2;
9126
Daniel Veillard556c6682001-10-06 09:59:51 +00009127 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 comp = ctxt->comp;
9129 switch (op->op) {
9130 case XPATH_OP_END:
9131 return (0);
9132 case XPATH_OP_UNION:
9133 total =
9134 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009135 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 if ((ctxt->value != NULL)
9137 && (ctxt->value->type == XPATH_NODESET)
9138 && (ctxt->value->nodesetval != NULL)
9139 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9140 /*
9141 * limit tree traversing to first node in the result
9142 */
9143 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9144 *last =
9145 ctxt->value->nodesetval->nodeTab[ctxt->value->
9146 nodesetval->nodeNr -
9147 1];
9148 }
9149 cur =
9150 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009151 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009152 if ((ctxt->value != NULL)
9153 && (ctxt->value->type == XPATH_NODESET)
9154 && (ctxt->value->nodesetval != NULL)
9155 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9156 }
9157 CHECK_TYPE0(XPATH_NODESET);
9158 arg2 = valuePop(ctxt);
9159
9160 CHECK_TYPE0(XPATH_NODESET);
9161 arg1 = valuePop(ctxt);
9162
9163 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9164 arg2->nodesetval);
9165 valuePush(ctxt, arg1);
9166 xmlXPathFreeObject(arg2);
9167 /* optimizer */
9168 if (total > cur)
9169 xmlXPathCompSwap(op);
9170 return (total + cur);
9171 case XPATH_OP_ROOT:
9172 xmlXPathRoot(ctxt);
9173 return (0);
9174 case XPATH_OP_NODE:
9175 if (op->ch1 != -1)
9176 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009177 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009178 if (op->ch2 != -1)
9179 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009180 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009181 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9182 return (total);
9183 case XPATH_OP_RESET:
9184 if (op->ch1 != -1)
9185 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009186 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009187 if (op->ch2 != -1)
9188 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009189 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009190 ctxt->context->node = NULL;
9191 return (total);
9192 case XPATH_OP_COLLECT:{
9193 if (op->ch1 == -1)
9194 return (0);
9195
9196 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009197 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009198
9199 /*
9200 * Optimization for [n] selection where n is a number
9201 */
9202 if ((op->ch2 != -1) &&
9203 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9204 (comp->steps[op->ch2].ch1 == -1) &&
9205 (comp->steps[op->ch2].ch2 != -1) &&
9206 (comp->steps[comp->steps[op->ch2].ch2].op ==
9207 XPATH_OP_VALUE)) {
9208 xmlXPathObjectPtr val;
9209
9210 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9211 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9212 int indx = (int) val->floatval;
9213
9214 if (val->floatval == (float) indx) {
9215 total +=
9216 xmlXPathNodeCollectAndTestNth(ctxt, op,
9217 indx, NULL,
9218 last);
9219 return (total);
9220 }
9221 }
9222 }
9223 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9224 return (total);
9225 }
9226 case XPATH_OP_VALUE:
9227 valuePush(ctxt,
9228 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9229 return (0);
9230 case XPATH_OP_SORT:
9231 if (op->ch1 != -1)
9232 total +=
9233 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9234 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009235 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009236 if ((ctxt->value != NULL)
9237 && (ctxt->value->type == XPATH_NODESET)
9238 && (ctxt->value->nodesetval != NULL))
9239 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9240 return (total);
9241 default:
9242 return (xmlXPathCompOpEval(ctxt, op));
9243 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009244}
9245
Owen Taylor3473f882001-02-23 17:55:21 +00009246/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009247 * xmlXPathCompOpEval:
9248 * @ctxt: the XPath parser context with the compiled expression
9249 * @op: an XPath compiled operation
9250 *
9251 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009252 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009253 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009254static int
9255xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9256{
9257 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009258 int equal, ret;
9259 xmlXPathCompExprPtr comp;
9260 xmlXPathObjectPtr arg1, arg2;
9261
Daniel Veillard556c6682001-10-06 09:59:51 +00009262 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009263 comp = ctxt->comp;
9264 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009265 case XPATH_OP_END:
9266 return (0);
9267 case XPATH_OP_AND:
9268 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009269 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009270 xmlXPathBooleanFunction(ctxt, 1);
9271 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9272 return (total);
9273 arg2 = valuePop(ctxt);
9274 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009275 if (ctxt->error) {
9276 xmlXPathFreeObject(arg2);
9277 return(0);
9278 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009279 xmlXPathBooleanFunction(ctxt, 1);
9280 arg1 = valuePop(ctxt);
9281 arg1->boolval &= arg2->boolval;
9282 valuePush(ctxt, arg1);
9283 xmlXPathFreeObject(arg2);
9284 return (total);
9285 case XPATH_OP_OR:
9286 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009287 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009288 xmlXPathBooleanFunction(ctxt, 1);
9289 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9290 return (total);
9291 arg2 = valuePop(ctxt);
9292 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009293 if (ctxt->error) {
9294 xmlXPathFreeObject(arg2);
9295 return(0);
9296 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009297 xmlXPathBooleanFunction(ctxt, 1);
9298 arg1 = valuePop(ctxt);
9299 arg1->boolval |= arg2->boolval;
9300 valuePush(ctxt, arg1);
9301 xmlXPathFreeObject(arg2);
9302 return (total);
9303 case XPATH_OP_EQUAL:
9304 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009305 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009306 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009307 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009308 equal = xmlXPathEqualValues(ctxt);
9309 if (op->value)
9310 valuePush(ctxt, xmlXPathNewBoolean(equal));
9311 else
9312 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9313 return (total);
9314 case XPATH_OP_CMP:
9315 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009316 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009317 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009318 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009319 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9320 valuePush(ctxt, xmlXPathNewBoolean(ret));
9321 return (total);
9322 case XPATH_OP_PLUS:
9323 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009324 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009325 if (op->ch2 != -1)
9326 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009327 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009328 if (op->value == 0)
9329 xmlXPathSubValues(ctxt);
9330 else if (op->value == 1)
9331 xmlXPathAddValues(ctxt);
9332 else if (op->value == 2)
9333 xmlXPathValueFlipSign(ctxt);
9334 else if (op->value == 3) {
9335 CAST_TO_NUMBER;
9336 CHECK_TYPE0(XPATH_NUMBER);
9337 }
9338 return (total);
9339 case XPATH_OP_MULT:
9340 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009341 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009342 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009343 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009344 if (op->value == 0)
9345 xmlXPathMultValues(ctxt);
9346 else if (op->value == 1)
9347 xmlXPathDivValues(ctxt);
9348 else if (op->value == 2)
9349 xmlXPathModValues(ctxt);
9350 return (total);
9351 case XPATH_OP_UNION:
9352 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009353 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009355 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009356 CHECK_TYPE0(XPATH_NODESET);
9357 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009358
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 CHECK_TYPE0(XPATH_NODESET);
9360 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009361
Daniel Veillardf06307e2001-07-03 10:35:50 +00009362 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9363 arg2->nodesetval);
9364 valuePush(ctxt, arg1);
9365 xmlXPathFreeObject(arg2);
9366 return (total);
9367 case XPATH_OP_ROOT:
9368 xmlXPathRoot(ctxt);
9369 return (total);
9370 case XPATH_OP_NODE:
9371 if (op->ch1 != -1)
9372 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009373 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009374 if (op->ch2 != -1)
9375 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009376 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009377 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9378 return (total);
9379 case XPATH_OP_RESET:
9380 if (op->ch1 != -1)
9381 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009382 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009383 if (op->ch2 != -1)
9384 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009385 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009386 ctxt->context->node = NULL;
9387 return (total);
9388 case XPATH_OP_COLLECT:{
9389 if (op->ch1 == -1)
9390 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009391
Daniel Veillardf06307e2001-07-03 10:35:50 +00009392 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009393 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009394
Daniel Veillardf06307e2001-07-03 10:35:50 +00009395 /*
9396 * Optimization for [n] selection where n is a number
9397 */
9398 if ((op->ch2 != -1) &&
9399 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9400 (comp->steps[op->ch2].ch1 == -1) &&
9401 (comp->steps[op->ch2].ch2 != -1) &&
9402 (comp->steps[comp->steps[op->ch2].ch2].op ==
9403 XPATH_OP_VALUE)) {
9404 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009405
Daniel Veillardf06307e2001-07-03 10:35:50 +00009406 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9407 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9408 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009409
Daniel Veillardf06307e2001-07-03 10:35:50 +00009410 if (val->floatval == (float) indx) {
9411 total +=
9412 xmlXPathNodeCollectAndTestNth(ctxt, op,
9413 indx, NULL,
9414 NULL);
9415 return (total);
9416 }
9417 }
9418 }
9419 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9420 return (total);
9421 }
9422 case XPATH_OP_VALUE:
9423 valuePush(ctxt,
9424 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9425 return (total);
9426 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009427 xmlXPathObjectPtr val;
9428
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 if (op->ch1 != -1)
9430 total +=
9431 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009432 if (op->value5 == NULL) {
9433 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9434 if (val == NULL) {
9435 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9436 return(0);
9437 }
9438 valuePush(ctxt, val);
9439 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009440 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009441
Daniel Veillardf06307e2001-07-03 10:35:50 +00009442 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9443 if (URI == NULL) {
9444 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009445 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009446 op->value4, op->value5);
9447 return (total);
9448 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009449 val = xmlXPathVariableLookupNS(ctxt->context,
9450 op->value4, URI);
9451 if (val == NULL) {
9452 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9453 return(0);
9454 }
9455 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009456 }
9457 return (total);
9458 }
9459 case XPATH_OP_FUNCTION:{
9460 xmlXPathFunction func;
9461 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009462 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009463
9464 if (op->ch1 != -1)
9465 total +=
9466 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009467 if (ctxt->valueNr < op->value) {
9468 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009469 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009470 ctxt->error = XPATH_INVALID_OPERAND;
9471 return (total);
9472 }
9473 for (i = 0; i < op->value; i++)
9474 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9475 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009476 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009477 ctxt->error = XPATH_INVALID_OPERAND;
9478 return (total);
9479 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009480 if (op->cache != NULL)
9481 func = (xmlXPathFunction) op->cache;
9482 else {
9483 const xmlChar *URI = NULL;
9484
9485 if (op->value5 == NULL)
9486 func =
9487 xmlXPathFunctionLookup(ctxt->context,
9488 op->value4);
9489 else {
9490 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9491 if (URI == NULL) {
9492 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009493 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009494 op->value4, op->value5);
9495 return (total);
9496 }
9497 func = xmlXPathFunctionLookupNS(ctxt->context,
9498 op->value4, URI);
9499 }
9500 if (func == NULL) {
9501 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009502 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009503 op->value4);
9504 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009505 }
9506 op->cache = (void *) func;
9507 op->cacheURI = (void *) URI;
9508 }
9509 oldFunc = ctxt->context->function;
9510 oldFuncURI = ctxt->context->functionURI;
9511 ctxt->context->function = op->value4;
9512 ctxt->context->functionURI = op->cacheURI;
9513 func(ctxt, op->value);
9514 ctxt->context->function = oldFunc;
9515 ctxt->context->functionURI = oldFuncURI;
9516 return (total);
9517 }
9518 case XPATH_OP_ARG:
9519 if (op->ch1 != -1)
9520 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009521 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009522 if (op->ch2 != -1)
9523 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009524 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009525 return (total);
9526 case XPATH_OP_PREDICATE:
9527 case XPATH_OP_FILTER:{
9528 xmlXPathObjectPtr res;
9529 xmlXPathObjectPtr obj, tmp;
9530 xmlNodeSetPtr newset = NULL;
9531 xmlNodeSetPtr oldset;
9532 xmlNodePtr oldnode;
9533 int i;
9534
9535 /*
9536 * Optimization for ()[1] selection i.e. the first elem
9537 */
9538 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9539 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9540 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9541 xmlXPathObjectPtr val;
9542
9543 val = comp->steps[op->ch2].value4;
9544 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9545 (val->floatval == 1.0)) {
9546 xmlNodePtr first = NULL;
9547
9548 total +=
9549 xmlXPathCompOpEvalFirst(ctxt,
9550 &comp->steps[op->ch1],
9551 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009552 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009553 /*
9554 * The nodeset should be in document order,
9555 * Keep only the first value
9556 */
9557 if ((ctxt->value != NULL) &&
9558 (ctxt->value->type == XPATH_NODESET) &&
9559 (ctxt->value->nodesetval != NULL) &&
9560 (ctxt->value->nodesetval->nodeNr > 1))
9561 ctxt->value->nodesetval->nodeNr = 1;
9562 return (total);
9563 }
9564 }
9565 /*
9566 * Optimization for ()[last()] selection i.e. the last elem
9567 */
9568 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9569 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9570 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9571 int f = comp->steps[op->ch2].ch1;
9572
9573 if ((f != -1) &&
9574 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9575 (comp->steps[f].value5 == NULL) &&
9576 (comp->steps[f].value == 0) &&
9577 (comp->steps[f].value4 != NULL) &&
9578 (xmlStrEqual
9579 (comp->steps[f].value4, BAD_CAST "last"))) {
9580 xmlNodePtr last = NULL;
9581
9582 total +=
9583 xmlXPathCompOpEvalLast(ctxt,
9584 &comp->steps[op->ch1],
9585 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009586 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009587 /*
9588 * The nodeset should be in document order,
9589 * Keep only the last value
9590 */
9591 if ((ctxt->value != NULL) &&
9592 (ctxt->value->type == XPATH_NODESET) &&
9593 (ctxt->value->nodesetval != NULL) &&
9594 (ctxt->value->nodesetval->nodeTab != NULL) &&
9595 (ctxt->value->nodesetval->nodeNr > 1)) {
9596 ctxt->value->nodesetval->nodeTab[0] =
9597 ctxt->value->nodesetval->nodeTab[ctxt->
9598 value->
9599 nodesetval->
9600 nodeNr -
9601 1];
9602 ctxt->value->nodesetval->nodeNr = 1;
9603 }
9604 return (total);
9605 }
9606 }
9607
9608 if (op->ch1 != -1)
9609 total +=
9610 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009611 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009612 if (op->ch2 == -1)
9613 return (total);
9614 if (ctxt->value == NULL)
9615 return (total);
9616
9617 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009618
9619#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009620 /*
9621 * Hum are we filtering the result of an XPointer expression
9622 */
9623 if (ctxt->value->type == XPATH_LOCATIONSET) {
9624 xmlLocationSetPtr newlocset = NULL;
9625 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009626
Daniel Veillardf06307e2001-07-03 10:35:50 +00009627 /*
9628 * Extract the old locset, and then evaluate the result of the
9629 * expression for all the element in the locset. use it to grow
9630 * up a new locset.
9631 */
9632 CHECK_TYPE0(XPATH_LOCATIONSET);
9633 obj = valuePop(ctxt);
9634 oldlocset = obj->user;
9635 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009636
Daniel Veillardf06307e2001-07-03 10:35:50 +00009637 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9638 ctxt->context->contextSize = 0;
9639 ctxt->context->proximityPosition = 0;
9640 if (op->ch2 != -1)
9641 total +=
9642 xmlXPathCompOpEval(ctxt,
9643 &comp->steps[op->ch2]);
9644 res = valuePop(ctxt);
9645 if (res != NULL)
9646 xmlXPathFreeObject(res);
9647 valuePush(ctxt, obj);
9648 CHECK_ERROR0;
9649 return (total);
9650 }
9651 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009652
Daniel Veillardf06307e2001-07-03 10:35:50 +00009653 for (i = 0; i < oldlocset->locNr; i++) {
9654 /*
9655 * Run the evaluation with a node list made of a
9656 * single item in the nodelocset.
9657 */
9658 ctxt->context->node = oldlocset->locTab[i]->user;
9659 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9660 valuePush(ctxt, tmp);
9661 ctxt->context->contextSize = oldlocset->locNr;
9662 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009663
Daniel Veillardf06307e2001-07-03 10:35:50 +00009664 if (op->ch2 != -1)
9665 total +=
9666 xmlXPathCompOpEval(ctxt,
9667 &comp->steps[op->ch2]);
9668 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009669
Daniel Veillardf06307e2001-07-03 10:35:50 +00009670 /*
9671 * The result of the evaluation need to be tested to
9672 * decided whether the filter succeeded or not
9673 */
9674 res = valuePop(ctxt);
9675 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9676 xmlXPtrLocationSetAdd(newlocset,
9677 xmlXPathObjectCopy
9678 (oldlocset->locTab[i]));
9679 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009680
Daniel Veillardf06307e2001-07-03 10:35:50 +00009681 /*
9682 * Cleanup
9683 */
9684 if (res != NULL)
9685 xmlXPathFreeObject(res);
9686 if (ctxt->value == tmp) {
9687 res = valuePop(ctxt);
9688 xmlXPathFreeObject(res);
9689 }
9690
9691 ctxt->context->node = NULL;
9692 }
9693
9694 /*
9695 * The result is used as the new evaluation locset.
9696 */
9697 xmlXPathFreeObject(obj);
9698 ctxt->context->node = NULL;
9699 ctxt->context->contextSize = -1;
9700 ctxt->context->proximityPosition = -1;
9701 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9702 ctxt->context->node = oldnode;
9703 return (total);
9704 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009705#endif /* LIBXML_XPTR_ENABLED */
9706
Daniel Veillardf06307e2001-07-03 10:35:50 +00009707 /*
9708 * Extract the old set, and then evaluate the result of the
9709 * expression for all the element in the set. use it to grow
9710 * up a new set.
9711 */
9712 CHECK_TYPE0(XPATH_NODESET);
9713 obj = valuePop(ctxt);
9714 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009715
Daniel Veillardf06307e2001-07-03 10:35:50 +00009716 oldnode = ctxt->context->node;
9717 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009718
Daniel Veillardf06307e2001-07-03 10:35:50 +00009719 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9720 ctxt->context->contextSize = 0;
9721 ctxt->context->proximityPosition = 0;
9722 if (op->ch2 != -1)
9723 total +=
9724 xmlXPathCompOpEval(ctxt,
9725 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009726 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009727 res = valuePop(ctxt);
9728 if (res != NULL)
9729 xmlXPathFreeObject(res);
9730 valuePush(ctxt, obj);
9731 ctxt->context->node = oldnode;
9732 CHECK_ERROR0;
9733 } else {
9734 /*
9735 * Initialize the new set.
9736 */
9737 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009738
Daniel Veillardf06307e2001-07-03 10:35:50 +00009739 for (i = 0; i < oldset->nodeNr; i++) {
9740 /*
9741 * Run the evaluation with a node list made of
9742 * a single item in the nodeset.
9743 */
9744 ctxt->context->node = oldset->nodeTab[i];
9745 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9746 valuePush(ctxt, tmp);
9747 ctxt->context->contextSize = oldset->nodeNr;
9748 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009749
Daniel Veillardf06307e2001-07-03 10:35:50 +00009750 if (op->ch2 != -1)
9751 total +=
9752 xmlXPathCompOpEval(ctxt,
9753 &comp->steps[op->ch2]);
9754 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009755
Daniel Veillardf06307e2001-07-03 10:35:50 +00009756 /*
9757 * The result of the evaluation need to be tested to
9758 * decided whether the filter succeeded or not
9759 */
9760 res = valuePop(ctxt);
9761 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9762 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9763 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009764
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765 /*
9766 * Cleanup
9767 */
9768 if (res != NULL)
9769 xmlXPathFreeObject(res);
9770 if (ctxt->value == tmp) {
9771 res = valuePop(ctxt);
9772 xmlXPathFreeObject(res);
9773 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009774
Daniel Veillardf06307e2001-07-03 10:35:50 +00009775 ctxt->context->node = NULL;
9776 }
9777
9778 /*
9779 * The result is used as the new evaluation set.
9780 */
9781 xmlXPathFreeObject(obj);
9782 ctxt->context->node = NULL;
9783 ctxt->context->contextSize = -1;
9784 ctxt->context->proximityPosition = -1;
9785 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9786 }
9787 ctxt->context->node = oldnode;
9788 return (total);
9789 }
9790 case XPATH_OP_SORT:
9791 if (op->ch1 != -1)
9792 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009793 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009794 if ((ctxt->value != NULL) &&
9795 (ctxt->value->type == XPATH_NODESET) &&
9796 (ctxt->value->nodesetval != NULL))
9797 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9798 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009799#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009800 case XPATH_OP_RANGETO:{
9801 xmlXPathObjectPtr range;
9802 xmlXPathObjectPtr res, obj;
9803 xmlXPathObjectPtr tmp;
9804 xmlLocationSetPtr newset = NULL;
9805 xmlNodeSetPtr oldset;
9806 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009807
Daniel Veillardf06307e2001-07-03 10:35:50 +00009808 if (op->ch1 != -1)
9809 total +=
9810 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9811 if (op->ch2 == -1)
9812 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009813
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814 CHECK_TYPE0(XPATH_NODESET);
9815 obj = valuePop(ctxt);
9816 oldset = obj->nodesetval;
9817 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009818
Daniel Veillardf06307e2001-07-03 10:35:50 +00009819 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009820
Daniel Veillardf06307e2001-07-03 10:35:50 +00009821 if (oldset != NULL) {
9822 for (i = 0; i < oldset->nodeNr; i++) {
9823 /*
9824 * Run the evaluation with a node list made of a single item
9825 * in the nodeset.
9826 */
9827 ctxt->context->node = oldset->nodeTab[i];
9828 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9829 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009830
Daniel Veillardf06307e2001-07-03 10:35:50 +00009831 if (op->ch2 != -1)
9832 total +=
9833 xmlXPathCompOpEval(ctxt,
9834 &comp->steps[op->ch2]);
9835 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009836
Daniel Veillardf06307e2001-07-03 10:35:50 +00009837 /*
9838 * The result of the evaluation need to be tested to
9839 * decided whether the filter succeeded or not
9840 */
9841 res = valuePop(ctxt);
9842 range =
9843 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9844 res);
9845 if (range != NULL) {
9846 xmlXPtrLocationSetAdd(newset, range);
9847 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009848
Daniel Veillardf06307e2001-07-03 10:35:50 +00009849 /*
9850 * Cleanup
9851 */
9852 if (res != NULL)
9853 xmlXPathFreeObject(res);
9854 if (ctxt->value == tmp) {
9855 res = valuePop(ctxt);
9856 xmlXPathFreeObject(res);
9857 }
9858
9859 ctxt->context->node = NULL;
9860 }
9861 }
9862
9863 /*
9864 * The result is used as the new evaluation set.
9865 */
9866 xmlXPathFreeObject(obj);
9867 ctxt->context->node = NULL;
9868 ctxt->context->contextSize = -1;
9869 ctxt->context->proximityPosition = -1;
9870 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9871 return (total);
9872 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009873#endif /* LIBXML_XPTR_ENABLED */
9874 }
9875 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876 "XPath: unknown precompiled operation %d\n", op->op);
9877 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009878}
9879
9880/**
9881 * xmlXPathRunEval:
9882 * @ctxt: the XPath parser context with the compiled expression
9883 *
9884 * Evaluate the Precompiled XPath expression in the given context.
9885 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009886static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009887xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9888 xmlXPathCompExprPtr comp;
9889
9890 if ((ctxt == NULL) || (ctxt->comp == NULL))
9891 return;
9892
9893 if (ctxt->valueTab == NULL) {
9894 /* Allocate the value stack */
9895 ctxt->valueTab = (xmlXPathObjectPtr *)
9896 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9897 if (ctxt->valueTab == NULL) {
9898 xmlFree(ctxt);
9899 xmlGenericError(xmlGenericErrorContext,
9900 "xmlXPathRunEval: out of memory\n");
9901 return;
9902 }
9903 ctxt->valueNr = 0;
9904 ctxt->valueMax = 10;
9905 ctxt->value = NULL;
9906 }
9907 comp = ctxt->comp;
9908 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9909}
9910
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009911/************************************************************************
9912 * *
9913 * Public interfaces *
9914 * *
9915 ************************************************************************/
9916
9917/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009918 * xmlXPathEvalPredicate:
9919 * @ctxt: the XPath context
9920 * @res: the Predicate Expression evaluation result
9921 *
9922 * Evaluate a predicate result for the current node.
9923 * A PredicateExpr is evaluated by evaluating the Expr and converting
9924 * the result to a boolean. If the result is a number, the result will
9925 * be converted to true if the number is equal to the position of the
9926 * context node in the context node list (as returned by the position
9927 * function) and will be converted to false otherwise; if the result
9928 * is not a number, then the result will be converted as if by a call
9929 * to the boolean function.
9930 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009931 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009932 */
9933int
9934xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9935 if (res == NULL) return(0);
9936 switch (res->type) {
9937 case XPATH_BOOLEAN:
9938 return(res->boolval);
9939 case XPATH_NUMBER:
9940 return(res->floatval == ctxt->proximityPosition);
9941 case XPATH_NODESET:
9942 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009943 if (res->nodesetval == NULL)
9944 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009945 return(res->nodesetval->nodeNr != 0);
9946 case XPATH_STRING:
9947 return((res->stringval != NULL) &&
9948 (xmlStrlen(res->stringval) != 0));
9949 default:
9950 STRANGE
9951 }
9952 return(0);
9953}
9954
9955/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009956 * xmlXPathEvaluatePredicateResult:
9957 * @ctxt: the XPath Parser context
9958 * @res: the Predicate Expression evaluation result
9959 *
9960 * Evaluate a predicate result for the current node.
9961 * A PredicateExpr is evaluated by evaluating the Expr and converting
9962 * the result to a boolean. If the result is a number, the result will
9963 * be converted to true if the number is equal to the position of the
9964 * context node in the context node list (as returned by the position
9965 * function) and will be converted to false otherwise; if the result
9966 * is not a number, then the result will be converted as if by a call
9967 * to the boolean function.
9968 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009969 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009970 */
9971int
9972xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9973 xmlXPathObjectPtr res) {
9974 if (res == NULL) return(0);
9975 switch (res->type) {
9976 case XPATH_BOOLEAN:
9977 return(res->boolval);
9978 case XPATH_NUMBER:
9979 return(res->floatval == ctxt->context->proximityPosition);
9980 case XPATH_NODESET:
9981 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009982 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009983 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009984 return(res->nodesetval->nodeNr != 0);
9985 case XPATH_STRING:
9986 return((res->stringval != NULL) &&
9987 (xmlStrlen(res->stringval) != 0));
9988 default:
9989 STRANGE
9990 }
9991 return(0);
9992}
9993
9994/**
9995 * xmlXPathCompile:
9996 * @str: the XPath expression
9997 *
9998 * Compile an XPath expression
9999 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010000 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010001 * the caller has to free the object.
10002 */
10003xmlXPathCompExprPtr
10004xmlXPathCompile(const xmlChar *str) {
10005 xmlXPathParserContextPtr ctxt;
10006 xmlXPathCompExprPtr comp;
10007
10008 xmlXPathInit();
10009
10010 ctxt = xmlXPathNewParserContext(str, NULL);
10011 xmlXPathCompileExpr(ctxt);
10012
Daniel Veillard40af6492001-04-22 08:50:55 +000010013 if (*ctxt->cur != 0) {
10014 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10015 comp = NULL;
10016 } else {
10017 comp = ctxt->comp;
10018 ctxt->comp = NULL;
10019 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010020 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010021#ifdef DEBUG_EVAL_COUNTS
10022 if (comp != NULL) {
10023 comp->string = xmlStrdup(str);
10024 comp->nb = 0;
10025 }
10026#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010027 return(comp);
10028}
10029
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010030/**
10031 * xmlXPathCompiledEval:
10032 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010033 * @ctx: the XPath context
10034 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010035 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010036 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010037 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010038 * the caller has to free the object.
10039 */
10040xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010041xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010042 xmlXPathParserContextPtr ctxt;
10043 xmlXPathObjectPtr res, tmp, init = NULL;
10044 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010045#ifndef LIBXML_THREAD_ENABLED
10046 static int reentance = 0;
10047#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010048
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010049 if ((comp == NULL) || (ctx == NULL))
10050 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010051 xmlXPathInit();
10052
10053 CHECK_CONTEXT(ctx)
10054
Daniel Veillard81463942001-10-16 12:34:39 +000010055#ifndef LIBXML_THREAD_ENABLED
10056 reentance++;
10057 if (reentance > 1)
10058 xmlXPathDisableOptimizer = 1;
10059#endif
10060
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061#ifdef DEBUG_EVAL_COUNTS
10062 comp->nb++;
10063 if ((comp->string != NULL) && (comp->nb > 100)) {
10064 fprintf(stderr, "100 x %s\n", comp->string);
10065 comp->nb = 0;
10066 }
10067#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010068 ctxt = xmlXPathCompParserContext(comp, ctx);
10069 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010070
10071 if (ctxt->value == NULL) {
10072 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010073 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010074 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010075 } else {
10076 res = valuePop(ctxt);
10077 }
10078
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079
Owen Taylor3473f882001-02-23 17:55:21 +000010080 do {
10081 tmp = valuePop(ctxt);
10082 if (tmp != NULL) {
10083 if (tmp != init)
10084 stack++;
10085 xmlXPathFreeObject(tmp);
10086 }
10087 } while (tmp != NULL);
10088 if ((stack != 0) && (res != NULL)) {
10089 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010090 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010091 stack);
10092 }
10093 if (ctxt->error != XPATH_EXPRESSION_OK) {
10094 xmlXPathFreeObject(res);
10095 res = NULL;
10096 }
10097
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010098
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010099 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010100 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010101#ifndef LIBXML_THREAD_ENABLED
10102 reentance--;
10103#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010104 return(res);
10105}
10106
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010107/**
10108 * xmlXPathEvalExpr:
10109 * @ctxt: the XPath Parser context
10110 *
10111 * Parse and evaluate an XPath expression in the given context,
10112 * then push the result on the context stack
10113 */
10114void
10115xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10116 xmlXPathCompileExpr(ctxt);
10117 xmlXPathRunEval(ctxt);
10118}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010119
10120/**
10121 * xmlXPathEval:
10122 * @str: the XPath expression
10123 * @ctx: the XPath context
10124 *
10125 * Evaluate the XPath Location Path in the given context.
10126 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010127 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010128 * the caller has to free the object.
10129 */
10130xmlXPathObjectPtr
10131xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10132 xmlXPathParserContextPtr ctxt;
10133 xmlXPathObjectPtr res, tmp, init = NULL;
10134 int stack = 0;
10135
10136 xmlXPathInit();
10137
10138 CHECK_CONTEXT(ctx)
10139
10140 ctxt = xmlXPathNewParserContext(str, ctx);
10141 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010142
10143 if (ctxt->value == NULL) {
10144 xmlGenericError(xmlGenericErrorContext,
10145 "xmlXPathEval: evaluation failed\n");
10146 res = NULL;
10147 } else if (*ctxt->cur != 0) {
10148 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10149 res = NULL;
10150 } else {
10151 res = valuePop(ctxt);
10152 }
10153
10154 do {
10155 tmp = valuePop(ctxt);
10156 if (tmp != NULL) {
10157 if (tmp != init)
10158 stack++;
10159 xmlXPathFreeObject(tmp);
10160 }
10161 } while (tmp != NULL);
10162 if ((stack != 0) && (res != NULL)) {
10163 xmlGenericError(xmlGenericErrorContext,
10164 "xmlXPathEval: %d object left on the stack\n",
10165 stack);
10166 }
10167 if (ctxt->error != XPATH_EXPRESSION_OK) {
10168 xmlXPathFreeObject(res);
10169 res = NULL;
10170 }
10171
Owen Taylor3473f882001-02-23 17:55:21 +000010172 xmlXPathFreeParserContext(ctxt);
10173 return(res);
10174}
10175
10176/**
10177 * xmlXPathEvalExpression:
10178 * @str: the XPath expression
10179 * @ctxt: the XPath context
10180 *
10181 * Evaluate the XPath expression in the given context.
10182 *
10183 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10184 * the caller has to free the object.
10185 */
10186xmlXPathObjectPtr
10187xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10188 xmlXPathParserContextPtr pctxt;
10189 xmlXPathObjectPtr res, tmp;
10190 int stack = 0;
10191
10192 xmlXPathInit();
10193
10194 CHECK_CONTEXT(ctxt)
10195
10196 pctxt = xmlXPathNewParserContext(str, ctxt);
10197 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010198
10199 if (*pctxt->cur != 0) {
10200 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10201 res = NULL;
10202 } else {
10203 res = valuePop(pctxt);
10204 }
10205 do {
10206 tmp = valuePop(pctxt);
10207 if (tmp != NULL) {
10208 xmlXPathFreeObject(tmp);
10209 stack++;
10210 }
10211 } while (tmp != NULL);
10212 if ((stack != 0) && (res != NULL)) {
10213 xmlGenericError(xmlGenericErrorContext,
10214 "xmlXPathEvalExpression: %d object left on the stack\n",
10215 stack);
10216 }
10217 xmlXPathFreeParserContext(pctxt);
10218 return(res);
10219}
10220
10221/**
10222 * xmlXPathRegisterAllFunctions:
10223 * @ctxt: the XPath context
10224 *
10225 * Registers all default XPath functions in this context
10226 */
10227void
10228xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10229{
10230 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10231 xmlXPathBooleanFunction);
10232 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10233 xmlXPathCeilingFunction);
10234 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10235 xmlXPathCountFunction);
10236 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10237 xmlXPathConcatFunction);
10238 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10239 xmlXPathContainsFunction);
10240 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10241 xmlXPathIdFunction);
10242 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10243 xmlXPathFalseFunction);
10244 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10245 xmlXPathFloorFunction);
10246 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10247 xmlXPathLastFunction);
10248 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10249 xmlXPathLangFunction);
10250 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10251 xmlXPathLocalNameFunction);
10252 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10253 xmlXPathNotFunction);
10254 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10255 xmlXPathNameFunction);
10256 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10257 xmlXPathNamespaceURIFunction);
10258 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10259 xmlXPathNormalizeFunction);
10260 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10261 xmlXPathNumberFunction);
10262 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10263 xmlXPathPositionFunction);
10264 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10265 xmlXPathRoundFunction);
10266 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10267 xmlXPathStringFunction);
10268 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10269 xmlXPathStringLengthFunction);
10270 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10271 xmlXPathStartsWithFunction);
10272 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10273 xmlXPathSubstringFunction);
10274 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10275 xmlXPathSubstringBeforeFunction);
10276 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10277 xmlXPathSubstringAfterFunction);
10278 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10279 xmlXPathSumFunction);
10280 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10281 xmlXPathTrueFunction);
10282 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10283 xmlXPathTranslateFunction);
10284}
10285
10286#endif /* LIBXML_XPATH_ENABLED */