blob: 0707b16694533bbc45cf1480b5cf0b27c72e7b4b [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/**
1390 * xmlXPathNodeSetCreate:
1391 * @val: an initial xmlNodePtr, or NULL
1392 *
1393 * Create a new xmlNodeSetPtr of type double and of value @val
1394 *
1395 * Returns the newly created object.
1396 */
1397xmlNodeSetPtr
1398xmlXPathNodeSetCreate(xmlNodePtr val) {
1399 xmlNodeSetPtr ret;
1400
1401 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1402 if (ret == NULL) {
1403 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001404 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001405 return(NULL);
1406 }
1407 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1408 if (val != NULL) {
1409 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1410 sizeof(xmlNodePtr));
1411 if (ret->nodeTab == NULL) {
1412 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001413 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001414 return(NULL);
1415 }
1416 memset(ret->nodeTab, 0 ,
1417 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1418 ret->nodeMax = XML_NODESET_DEFAULT;
1419 ret->nodeTab[ret->nodeNr++] = val;
1420 }
1421 return(ret);
1422}
1423
1424/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001425 * xmlXPathNodeSetContains:
1426 * @cur: the node-set
1427 * @val: the node
1428 *
1429 * checks whether @cur contains @val
1430 *
1431 * Returns true (1) if @cur contains @val, false (0) otherwise
1432 */
1433int
1434xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1435 int i;
1436
1437 for (i = 0; i < cur->nodeNr; i++) {
1438 if (cur->nodeTab[i] == val)
1439 return(1);
1440 }
1441 return(0);
1442}
1443
1444/**
Owen Taylor3473f882001-02-23 17:55:21 +00001445 * xmlXPathNodeSetAdd:
1446 * @cur: the initial node set
1447 * @val: a new xmlNodePtr
1448 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001449 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001450 */
1451void
1452xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1453 int i;
1454
1455 if (val == NULL) return;
1456
1457 /*
1458 * check against doublons
1459 */
1460 for (i = 0;i < cur->nodeNr;i++)
1461 if (cur->nodeTab[i] == val) return;
1462
1463 /*
1464 * grow the nodeTab if needed
1465 */
1466 if (cur->nodeMax == 0) {
1467 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1468 sizeof(xmlNodePtr));
1469 if (cur->nodeTab == NULL) {
1470 xmlGenericError(xmlGenericErrorContext,
1471 "xmlXPathNodeSetAdd: out of memory\n");
1472 return;
1473 }
1474 memset(cur->nodeTab, 0 ,
1475 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1476 cur->nodeMax = XML_NODESET_DEFAULT;
1477 } else if (cur->nodeNr == cur->nodeMax) {
1478 xmlNodePtr *temp;
1479
1480 cur->nodeMax *= 2;
1481 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1482 sizeof(xmlNodePtr));
1483 if (temp == NULL) {
1484 xmlGenericError(xmlGenericErrorContext,
1485 "xmlXPathNodeSetAdd: out of memory\n");
1486 return;
1487 }
1488 cur->nodeTab = temp;
1489 }
1490 cur->nodeTab[cur->nodeNr++] = val;
1491}
1492
1493/**
1494 * xmlXPathNodeSetAddUnique:
1495 * @cur: the initial node set
1496 * @val: a new xmlNodePtr
1497 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001498 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001499 * when we are sure the node is not already in the set.
1500 */
1501void
1502xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1503 if (val == NULL) return;
1504
1505 /*
1506 * grow the nodeTab if needed
1507 */
1508 if (cur->nodeMax == 0) {
1509 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1510 sizeof(xmlNodePtr));
1511 if (cur->nodeTab == NULL) {
1512 xmlGenericError(xmlGenericErrorContext,
1513 "xmlXPathNodeSetAddUnique: out of memory\n");
1514 return;
1515 }
1516 memset(cur->nodeTab, 0 ,
1517 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1518 cur->nodeMax = XML_NODESET_DEFAULT;
1519 } else if (cur->nodeNr == cur->nodeMax) {
1520 xmlNodePtr *temp;
1521
1522 cur->nodeMax *= 2;
1523 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1524 sizeof(xmlNodePtr));
1525 if (temp == NULL) {
1526 xmlGenericError(xmlGenericErrorContext,
1527 "xmlXPathNodeSetAddUnique: out of memory\n");
1528 return;
1529 }
1530 cur->nodeTab = temp;
1531 }
1532 cur->nodeTab[cur->nodeNr++] = val;
1533}
1534
1535/**
1536 * xmlXPathNodeSetMerge:
1537 * @val1: the first NodeSet or NULL
1538 * @val2: the second NodeSet
1539 *
1540 * Merges two nodesets, all nodes from @val2 are added to @val1
1541 * if @val1 is NULL, a new set is created and copied from @val2
1542 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001543 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001544 */
1545xmlNodeSetPtr
1546xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001547 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001548
1549 if (val2 == NULL) return(val1);
1550 if (val1 == NULL) {
1551 val1 = xmlXPathNodeSetCreate(NULL);
1552 }
1553
1554 initNr = val1->nodeNr;
1555
1556 for (i = 0;i < val2->nodeNr;i++) {
1557 /*
1558 * check against doublons
1559 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001560 skip = 0;
1561 for (j = 0; j < initNr; j++) {
1562 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1563 skip = 1;
1564 break;
1565 }
1566 }
1567 if (skip)
1568 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001569
1570 /*
1571 * grow the nodeTab if needed
1572 */
1573 if (val1->nodeMax == 0) {
1574 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1575 sizeof(xmlNodePtr));
1576 if (val1->nodeTab == NULL) {
1577 xmlGenericError(xmlGenericErrorContext,
1578 "xmlXPathNodeSetMerge: out of memory\n");
1579 return(NULL);
1580 }
1581 memset(val1->nodeTab, 0 ,
1582 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1583 val1->nodeMax = XML_NODESET_DEFAULT;
1584 } else if (val1->nodeNr == val1->nodeMax) {
1585 xmlNodePtr *temp;
1586
1587 val1->nodeMax *= 2;
1588 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1589 sizeof(xmlNodePtr));
1590 if (temp == NULL) {
1591 xmlGenericError(xmlGenericErrorContext,
1592 "xmlXPathNodeSetMerge: out of memory\n");
1593 return(NULL);
1594 }
1595 val1->nodeTab = temp;
1596 }
1597 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1598 }
1599
1600 return(val1);
1601}
1602
1603/**
1604 * xmlXPathNodeSetDel:
1605 * @cur: the initial node set
1606 * @val: an xmlNodePtr
1607 *
1608 * Removes an xmlNodePtr from an existing NodeSet
1609 */
1610void
1611xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1612 int i;
1613
1614 if (cur == NULL) return;
1615 if (val == NULL) return;
1616
1617 /*
1618 * check against doublons
1619 */
1620 for (i = 0;i < cur->nodeNr;i++)
1621 if (cur->nodeTab[i] == val) break;
1622
1623 if (i >= cur->nodeNr) {
1624#ifdef DEBUG
1625 xmlGenericError(xmlGenericErrorContext,
1626 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1627 val->name);
1628#endif
1629 return;
1630 }
1631 cur->nodeNr--;
1632 for (;i < cur->nodeNr;i++)
1633 cur->nodeTab[i] = cur->nodeTab[i + 1];
1634 cur->nodeTab[cur->nodeNr] = NULL;
1635}
1636
1637/**
1638 * xmlXPathNodeSetRemove:
1639 * @cur: the initial node set
1640 * @val: the index to remove
1641 *
1642 * Removes an entry from an existing NodeSet list.
1643 */
1644void
1645xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1646 if (cur == NULL) return;
1647 if (val >= cur->nodeNr) return;
1648 cur->nodeNr--;
1649 for (;val < cur->nodeNr;val++)
1650 cur->nodeTab[val] = cur->nodeTab[val + 1];
1651 cur->nodeTab[cur->nodeNr] = NULL;
1652}
1653
1654/**
1655 * xmlXPathFreeNodeSet:
1656 * @obj: the xmlNodeSetPtr to free
1657 *
1658 * Free the NodeSet compound (not the actual nodes !).
1659 */
1660void
1661xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1662 if (obj == NULL) return;
1663 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001664 xmlFree(obj->nodeTab);
1665 }
Owen Taylor3473f882001-02-23 17:55:21 +00001666 xmlFree(obj);
1667}
1668
1669/**
1670 * xmlXPathFreeValueTree:
1671 * @obj: the xmlNodeSetPtr to free
1672 *
1673 * Free the NodeSet compound and the actual tree, this is different
1674 * from xmlXPathFreeNodeSet()
1675 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001676static void
Owen Taylor3473f882001-02-23 17:55:21 +00001677xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1678 int i;
1679
1680 if (obj == NULL) return;
1681 for (i = 0;i < obj->nodeNr;i++)
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001682 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001683 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001684
1685 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001686 xmlFree(obj->nodeTab);
1687 }
Owen Taylor3473f882001-02-23 17:55:21 +00001688 xmlFree(obj);
1689}
1690
1691#if defined(DEBUG) || defined(DEBUG_STEP)
1692/**
1693 * xmlGenericErrorContextNodeSet:
1694 * @output: a FILE * for the output
1695 * @obj: the xmlNodeSetPtr to free
1696 *
1697 * Quick display of a NodeSet
1698 */
1699void
1700xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1701 int i;
1702
1703 if (output == NULL) output = xmlGenericErrorContext;
1704 if (obj == NULL) {
1705 fprintf(output, "NodeSet == NULL !\n");
1706 return;
1707 }
1708 if (obj->nodeNr == 0) {
1709 fprintf(output, "NodeSet is empty\n");
1710 return;
1711 }
1712 if (obj->nodeTab == NULL) {
1713 fprintf(output, " nodeTab == NULL !\n");
1714 return;
1715 }
1716 for (i = 0; i < obj->nodeNr; i++) {
1717 if (obj->nodeTab[i] == NULL) {
1718 fprintf(output, " NULL !\n");
1719 return;
1720 }
1721 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1722 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1723 fprintf(output, " /");
1724 else if (obj->nodeTab[i]->name == NULL)
1725 fprintf(output, " noname!");
1726 else fprintf(output, " %s", obj->nodeTab[i]->name);
1727 }
1728 fprintf(output, "\n");
1729}
1730#endif
1731
1732/**
1733 * xmlXPathNewNodeSet:
1734 * @val: the NodePtr value
1735 *
1736 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1737 * it with the single Node @val
1738 *
1739 * Returns the newly created object.
1740 */
1741xmlXPathObjectPtr
1742xmlXPathNewNodeSet(xmlNodePtr val) {
1743 xmlXPathObjectPtr ret;
1744
1745 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1746 if (ret == NULL) {
1747 xmlGenericError(xmlGenericErrorContext,
1748 "xmlXPathNewNodeSet: out of memory\n");
1749 return(NULL);
1750 }
1751 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1752 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001753 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001754 ret->nodesetval = xmlXPathNodeSetCreate(val);
1755 return(ret);
1756}
1757
1758/**
1759 * xmlXPathNewValueTree:
1760 * @val: the NodePtr value
1761 *
1762 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1763 * it with the tree root @val
1764 *
1765 * Returns the newly created object.
1766 */
1767xmlXPathObjectPtr
1768xmlXPathNewValueTree(xmlNodePtr val) {
1769 xmlXPathObjectPtr ret;
1770
1771 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1772 if (ret == NULL) {
1773 xmlGenericError(xmlGenericErrorContext,
1774 "xmlXPathNewNodeSet: out of memory\n");
1775 return(NULL);
1776 }
1777 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1778 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001779 ret->boolval = 1;
1780 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00001781 ret->nodesetval = xmlXPathNodeSetCreate(val);
1782 return(ret);
1783}
1784
1785/**
1786 * xmlXPathNewNodeSetList:
1787 * @val: an existing NodeSet
1788 *
1789 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1790 * it with the Nodeset @val
1791 *
1792 * Returns the newly created object.
1793 */
1794xmlXPathObjectPtr
1795xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1796 xmlXPathObjectPtr ret;
1797 int i;
1798
1799 if (val == NULL)
1800 ret = NULL;
1801 else if (val->nodeTab == NULL)
1802 ret = xmlXPathNewNodeSet(NULL);
1803 else
1804 {
1805 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1806 for (i = 1; i < val->nodeNr; ++i)
1807 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1808 }
1809
1810 return(ret);
1811}
1812
1813/**
1814 * xmlXPathWrapNodeSet:
1815 * @val: the NodePtr value
1816 *
1817 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1818 *
1819 * Returns the newly created object.
1820 */
1821xmlXPathObjectPtr
1822xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1823 xmlXPathObjectPtr ret;
1824
1825 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1826 if (ret == NULL) {
1827 xmlGenericError(xmlGenericErrorContext,
1828 "xmlXPathWrapNodeSet: out of memory\n");
1829 return(NULL);
1830 }
1831 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1832 ret->type = XPATH_NODESET;
1833 ret->nodesetval = val;
1834 return(ret);
1835}
1836
1837/**
1838 * xmlXPathFreeNodeSetList:
1839 * @obj: an existing NodeSetList object
1840 *
1841 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1842 * the list contrary to xmlXPathFreeObject().
1843 */
1844void
1845xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1846 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001847 xmlFree(obj);
1848}
1849
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001850/**
1851 * xmlXPathDifference:
1852 * @nodes1: a node-set
1853 * @nodes2: a node-set
1854 *
1855 * Implements the EXSLT - Sets difference() function:
1856 * node-set set:difference (node-set, node-set)
1857 *
1858 * Returns the difference between the two node sets, or nodes1 if
1859 * nodes2 is empty
1860 */
1861xmlNodeSetPtr
1862xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1863 xmlNodeSetPtr ret;
1864 int i, l1;
1865 xmlNodePtr cur;
1866
1867 if (xmlXPathNodeSetIsEmpty(nodes2))
1868 return(nodes1);
1869
1870 ret = xmlXPathNodeSetCreate(NULL);
1871 if (xmlXPathNodeSetIsEmpty(nodes1))
1872 return(ret);
1873
1874 l1 = xmlXPathNodeSetGetLength(nodes1);
1875
1876 for (i = 0; i < l1; i++) {
1877 cur = xmlXPathNodeSetItem(nodes1, i);
1878 if (!xmlXPathNodeSetContains(nodes2, cur))
1879 xmlXPathNodeSetAddUnique(ret, cur);
1880 }
1881 return(ret);
1882}
1883
1884/**
1885 * xmlXPathIntersection:
1886 * @nodes1: a node-set
1887 * @nodes2: a node-set
1888 *
1889 * Implements the EXSLT - Sets intersection() function:
1890 * node-set set:intersection (node-set, node-set)
1891 *
1892 * Returns a node set comprising the nodes that are within both the
1893 * node sets passed as arguments
1894 */
1895xmlNodeSetPtr
1896xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1897 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
1898 int i, l1;
1899 xmlNodePtr cur;
1900
1901 if (xmlXPathNodeSetIsEmpty(nodes1))
1902 return(ret);
1903 if (xmlXPathNodeSetIsEmpty(nodes2))
1904 return(ret);
1905
1906 l1 = xmlXPathNodeSetGetLength(nodes1);
1907
1908 for (i = 0; i < l1; i++) {
1909 cur = xmlXPathNodeSetItem(nodes1, i);
1910 if (xmlXPathNodeSetContains(nodes2, cur))
1911 xmlXPathNodeSetAddUnique(ret, cur);
1912 }
1913 return(ret);
1914}
1915
1916/**
1917 * xmlXPathDistinctSorted:
1918 * @nodes: a node-set, sorted by document order
1919 *
1920 * Implements the EXSLT - Sets distinct() function:
1921 * node-set set:distinct (node-set)
1922 *
1923 * Returns a subset of the nodes contained in @nodes, or @nodes if
1924 * it is empty
1925 */
1926xmlNodeSetPtr
1927xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
1928 xmlNodeSetPtr ret;
1929 xmlHashTablePtr hash;
1930 int i, l;
1931 xmlChar * strval;
1932 xmlNodePtr cur;
1933
1934 if (xmlXPathNodeSetIsEmpty(nodes))
1935 return(nodes);
1936
1937 ret = xmlXPathNodeSetCreate(NULL);
1938 l = xmlXPathNodeSetGetLength(nodes);
1939 hash = xmlHashCreate (l);
1940 for (i = 0; i < l; i++) {
1941 cur = xmlXPathNodeSetItem(nodes, i);
1942 strval = xmlXPathCastNodeToString(cur);
1943 if (xmlHashLookup(hash, strval) == NULL) {
1944 xmlHashAddEntry(hash, strval, strval);
1945 xmlXPathNodeSetAddUnique(ret, cur);
1946 } else {
1947 xmlFree(strval);
1948 }
1949 }
1950 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
1951 return(ret);
1952}
1953
1954/**
1955 * xmlXPathDistinct:
1956 * @nodes: a node-set
1957 *
1958 * Implements the EXSLT - Sets distinct() function:
1959 * node-set set:distinct (node-set)
1960 * @nodes is sorted by document order, then #exslSetsDistinctSorted
1961 * is called with the sorted node-set
1962 *
1963 * Returns a subset of the nodes contained in @nodes, or @nodes if
1964 * it is empty
1965 */
1966xmlNodeSetPtr
1967xmlXPathDistinct (xmlNodeSetPtr nodes) {
1968 if (xmlXPathNodeSetIsEmpty(nodes))
1969 return(nodes);
1970
1971 xmlXPathNodeSetSort(nodes);
1972 return(xmlXPathDistinctSorted(nodes));
1973}
1974
1975/**
1976 * xmlXPathHasSameNodes:
1977 * @nodes1: a node-set
1978 * @nodes2: a node-set
1979 *
1980 * Implements the EXSLT - Sets has-same-nodes function:
1981 * boolean set:has-same-node(node-set, node-set)
1982 *
1983 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
1984 * otherwise
1985 */
1986int
1987xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1988 int i, l;
1989 xmlNodePtr cur;
1990
1991 if (xmlXPathNodeSetIsEmpty(nodes1) ||
1992 xmlXPathNodeSetIsEmpty(nodes2))
1993 return(0);
1994
1995 l = xmlXPathNodeSetGetLength(nodes1);
1996 for (i = 0; i < l; i++) {
1997 cur = xmlXPathNodeSetItem(nodes1, i);
1998 if (xmlXPathNodeSetContains(nodes2, cur))
1999 return(1);
2000 }
2001 return(0);
2002}
2003
2004/**
2005 * xmlXPathNodeLeadingSorted:
2006 * @nodes: a node-set, sorted by document order
2007 * @node: a node
2008 *
2009 * Implements the EXSLT - Sets leading() function:
2010 * node-set set:leading (node-set, node-set)
2011 *
2012 * Returns the nodes in @nodes that precede @node in document order,
2013 * @nodes if @node is NULL or an empty node-set if @nodes
2014 * doesn't contain @node
2015 */
2016xmlNodeSetPtr
2017xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2018 int i, l;
2019 xmlNodePtr cur;
2020 xmlNodeSetPtr ret;
2021
2022 if (node == NULL)
2023 return(nodes);
2024
2025 ret = xmlXPathNodeSetCreate(NULL);
2026 if (xmlXPathNodeSetIsEmpty(nodes) ||
2027 (!xmlXPathNodeSetContains(nodes, node)))
2028 return(ret);
2029
2030 l = xmlXPathNodeSetGetLength(nodes);
2031 for (i = 0; i < l; i++) {
2032 cur = xmlXPathNodeSetItem(nodes, i);
2033 if (cur == node)
2034 break;
2035 xmlXPathNodeSetAddUnique(ret, cur);
2036 }
2037 return(ret);
2038}
2039
2040/**
2041 * xmlXPathNodeLeading:
2042 * @nodes: a node-set
2043 * @node: a node
2044 *
2045 * Implements the EXSLT - Sets leading() function:
2046 * node-set set:leading (node-set, node-set)
2047 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2048 * is called.
2049 *
2050 * Returns the nodes in @nodes that precede @node in document order,
2051 * @nodes if @node is NULL or an empty node-set if @nodes
2052 * doesn't contain @node
2053 */
2054xmlNodeSetPtr
2055xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2056 xmlXPathNodeSetSort(nodes);
2057 return(xmlXPathNodeLeadingSorted(nodes, node));
2058}
2059
2060/**
2061 * xmlXPathLeadingSorted:
2062 * @nodes1: a node-set, sorted by document order
2063 * @nodes2: a node-set, sorted by document order
2064 *
2065 * Implements the EXSLT - Sets leading() function:
2066 * node-set set:leading (node-set, node-set)
2067 *
2068 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2069 * in document order, @nodes1 if @nodes2 is NULL or empty or
2070 * an empty node-set if @nodes1 doesn't contain @nodes2
2071 */
2072xmlNodeSetPtr
2073xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2074 if (xmlXPathNodeSetIsEmpty(nodes2))
2075 return(nodes1);
2076 return(xmlXPathNodeLeadingSorted(nodes1,
2077 xmlXPathNodeSetItem(nodes2, 1)));
2078}
2079
2080/**
2081 * xmlXPathLeading:
2082 * @nodes1: a node-set
2083 * @nodes2: a node-set
2084 *
2085 * Implements the EXSLT - Sets leading() function:
2086 * node-set set:leading (node-set, node-set)
2087 * @nodes1 and @nodes2 are sorted by document order, then
2088 * #exslSetsLeadingSorted is called.
2089 *
2090 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2091 * in document order, @nodes1 if @nodes2 is NULL or empty or
2092 * an empty node-set if @nodes1 doesn't contain @nodes2
2093 */
2094xmlNodeSetPtr
2095xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2096 if (xmlXPathNodeSetIsEmpty(nodes2))
2097 return(nodes1);
2098 if (xmlXPathNodeSetIsEmpty(nodes1))
2099 return(xmlXPathNodeSetCreate(NULL));
2100 xmlXPathNodeSetSort(nodes1);
2101 xmlXPathNodeSetSort(nodes2);
2102 return(xmlXPathNodeLeadingSorted(nodes1,
2103 xmlXPathNodeSetItem(nodes2, 1)));
2104}
2105
2106/**
2107 * xmlXPathNodeTrailingSorted:
2108 * @nodes: a node-set, sorted by document order
2109 * @node: a node
2110 *
2111 * Implements the EXSLT - Sets trailing() function:
2112 * node-set set:trailing (node-set, node-set)
2113 *
2114 * Returns the nodes in @nodes that follow @node in document order,
2115 * @nodes if @node is NULL or an empty node-set if @nodes
2116 * doesn't contain @node
2117 */
2118xmlNodeSetPtr
2119xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2120 int i, l;
2121 xmlNodePtr cur;
2122 xmlNodeSetPtr ret;
2123
2124 if (node == NULL)
2125 return(nodes);
2126
2127 ret = xmlXPathNodeSetCreate(NULL);
2128 if (xmlXPathNodeSetIsEmpty(nodes) ||
2129 (!xmlXPathNodeSetContains(nodes, node)))
2130 return(ret);
2131
2132 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002133 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002134 cur = xmlXPathNodeSetItem(nodes, i);
2135 if (cur == node)
2136 break;
2137 xmlXPathNodeSetAddUnique(ret, cur);
2138 }
2139 return(ret);
2140}
2141
2142/**
2143 * xmlXPathNodeTrailing:
2144 * @nodes: a node-set
2145 * @node: a node
2146 *
2147 * Implements the EXSLT - Sets trailing() function:
2148 * node-set set:trailing (node-set, node-set)
2149 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2150 * is called.
2151 *
2152 * Returns the nodes in @nodes that follow @node in document order,
2153 * @nodes if @node is NULL or an empty node-set if @nodes
2154 * doesn't contain @node
2155 */
2156xmlNodeSetPtr
2157xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2158 xmlXPathNodeSetSort(nodes);
2159 return(xmlXPathNodeTrailingSorted(nodes, node));
2160}
2161
2162/**
2163 * xmlXPathTrailingSorted:
2164 * @nodes1: a node-set, sorted by document order
2165 * @nodes2: a node-set, sorted by document order
2166 *
2167 * Implements the EXSLT - Sets trailing() function:
2168 * node-set set:trailing (node-set, node-set)
2169 *
2170 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2171 * in document order, @nodes1 if @nodes2 is NULL or empty or
2172 * an empty node-set if @nodes1 doesn't contain @nodes2
2173 */
2174xmlNodeSetPtr
2175xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2176 if (xmlXPathNodeSetIsEmpty(nodes2))
2177 return(nodes1);
2178 return(xmlXPathNodeTrailingSorted(nodes1,
2179 xmlXPathNodeSetItem(nodes2, 0)));
2180}
2181
2182/**
2183 * xmlXPathTrailing:
2184 * @nodes1: a node-set
2185 * @nodes2: a node-set
2186 *
2187 * Implements the EXSLT - Sets trailing() function:
2188 * node-set set:trailing (node-set, node-set)
2189 * @nodes1 and @nodes2 are sorted by document order, then
2190 * #xmlXPathTrailingSorted is called.
2191 *
2192 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2193 * in document order, @nodes1 if @nodes2 is NULL or empty or
2194 * an empty node-set if @nodes1 doesn't contain @nodes2
2195 */
2196xmlNodeSetPtr
2197xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2198 if (xmlXPathNodeSetIsEmpty(nodes2))
2199 return(nodes1);
2200 if (xmlXPathNodeSetIsEmpty(nodes1))
2201 return(xmlXPathNodeSetCreate(NULL));
2202 xmlXPathNodeSetSort(nodes1);
2203 xmlXPathNodeSetSort(nodes2);
2204 return(xmlXPathNodeTrailingSorted(nodes1,
2205 xmlXPathNodeSetItem(nodes2, 0)));
2206}
2207
Owen Taylor3473f882001-02-23 17:55:21 +00002208/************************************************************************
2209 * *
2210 * Routines to handle extra functions *
2211 * *
2212 ************************************************************************/
2213
2214/**
2215 * xmlXPathRegisterFunc:
2216 * @ctxt: the XPath context
2217 * @name: the function name
2218 * @f: the function implementation or NULL
2219 *
2220 * Register a new function. If @f is NULL it unregisters the function
2221 *
2222 * Returns 0 in case of success, -1 in case of error
2223 */
2224int
2225xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2226 xmlXPathFunction f) {
2227 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2228}
2229
2230/**
2231 * xmlXPathRegisterFuncNS:
2232 * @ctxt: the XPath context
2233 * @name: the function name
2234 * @ns_uri: the function namespace URI
2235 * @f: the function implementation or NULL
2236 *
2237 * Register a new function. If @f is NULL it unregisters the function
2238 *
2239 * Returns 0 in case of success, -1 in case of error
2240 */
2241int
2242xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2243 const xmlChar *ns_uri, xmlXPathFunction f) {
2244 if (ctxt == NULL)
2245 return(-1);
2246 if (name == NULL)
2247 return(-1);
2248
2249 if (ctxt->funcHash == NULL)
2250 ctxt->funcHash = xmlHashCreate(0);
2251 if (ctxt->funcHash == NULL)
2252 return(-1);
2253 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2254}
2255
2256/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002257 * xmlXPathRegisterFuncLookup:
2258 * @ctxt: the XPath context
2259 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002260 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002261 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002262 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002263 */
2264void
2265xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2266 xmlXPathFuncLookupFunc f,
2267 void *funcCtxt) {
2268 if (ctxt == NULL)
2269 return;
2270 ctxt->funcLookupFunc = (void *) f;
2271 ctxt->funcLookupData = funcCtxt;
2272}
2273
2274/**
Owen Taylor3473f882001-02-23 17:55:21 +00002275 * xmlXPathFunctionLookup:
2276 * @ctxt: the XPath context
2277 * @name: the function name
2278 *
2279 * Search in the Function array of the context for the given
2280 * function.
2281 *
2282 * Returns the xmlXPathFunction or NULL if not found
2283 */
2284xmlXPathFunction
2285xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002286 if (ctxt == NULL)
2287 return (NULL);
2288
2289 if (ctxt->funcLookupFunc != NULL) {
2290 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002291 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002292
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002293 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002294 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002295 if (ret != NULL)
2296 return(ret);
2297 }
Owen Taylor3473f882001-02-23 17:55:21 +00002298 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2299}
2300
2301/**
2302 * xmlXPathFunctionLookupNS:
2303 * @ctxt: the XPath context
2304 * @name: the function name
2305 * @ns_uri: the function namespace URI
2306 *
2307 * Search in the Function array of the context for the given
2308 * function.
2309 *
2310 * Returns the xmlXPathFunction or NULL if not found
2311 */
2312xmlXPathFunction
2313xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2314 const xmlChar *ns_uri) {
2315 if (ctxt == NULL)
2316 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002317 if (name == NULL)
2318 return(NULL);
2319
Thomas Broyerba4ad322001-07-26 16:55:21 +00002320 if (ctxt->funcLookupFunc != NULL) {
2321 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002322 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002323
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002324 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002325 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002326 if (ret != NULL)
2327 return(ret);
2328 }
2329
2330 if (ctxt->funcHash == NULL)
2331 return(NULL);
2332
Owen Taylor3473f882001-02-23 17:55:21 +00002333 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2334}
2335
2336/**
2337 * xmlXPathRegisteredFuncsCleanup:
2338 * @ctxt: the XPath context
2339 *
2340 * Cleanup the XPath context data associated to registered functions
2341 */
2342void
2343xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2344 if (ctxt == NULL)
2345 return;
2346
2347 xmlHashFree(ctxt->funcHash, NULL);
2348 ctxt->funcHash = NULL;
2349}
2350
2351/************************************************************************
2352 * *
2353 * Routines to handle Variable *
2354 * *
2355 ************************************************************************/
2356
2357/**
2358 * xmlXPathRegisterVariable:
2359 * @ctxt: the XPath context
2360 * @name: the variable name
2361 * @value: the variable value or NULL
2362 *
2363 * Register a new variable value. If @value is NULL it unregisters
2364 * the variable
2365 *
2366 * Returns 0 in case of success, -1 in case of error
2367 */
2368int
2369xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2370 xmlXPathObjectPtr value) {
2371 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2372}
2373
2374/**
2375 * xmlXPathRegisterVariableNS:
2376 * @ctxt: the XPath context
2377 * @name: the variable name
2378 * @ns_uri: the variable namespace URI
2379 * @value: the variable value or NULL
2380 *
2381 * Register a new variable value. If @value is NULL it unregisters
2382 * the variable
2383 *
2384 * Returns 0 in case of success, -1 in case of error
2385 */
2386int
2387xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2388 const xmlChar *ns_uri,
2389 xmlXPathObjectPtr value) {
2390 if (ctxt == NULL)
2391 return(-1);
2392 if (name == NULL)
2393 return(-1);
2394
2395 if (ctxt->varHash == NULL)
2396 ctxt->varHash = xmlHashCreate(0);
2397 if (ctxt->varHash == NULL)
2398 return(-1);
2399 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2400 (void *) value,
2401 (xmlHashDeallocator)xmlXPathFreeObject));
2402}
2403
2404/**
2405 * xmlXPathRegisterVariableLookup:
2406 * @ctxt: the XPath context
2407 * @f: the lookup function
2408 * @data: the lookup data
2409 *
2410 * register an external mechanism to do variable lookup
2411 */
2412void
2413xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2414 xmlXPathVariableLookupFunc f, void *data) {
2415 if (ctxt == NULL)
2416 return;
2417 ctxt->varLookupFunc = (void *) f;
2418 ctxt->varLookupData = data;
2419}
2420
2421/**
2422 * xmlXPathVariableLookup:
2423 * @ctxt: the XPath context
2424 * @name: the variable name
2425 *
2426 * Search in the Variable array of the context for the given
2427 * variable value.
2428 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002429 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002430 */
2431xmlXPathObjectPtr
2432xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2433 if (ctxt == NULL)
2434 return(NULL);
2435
2436 if (ctxt->varLookupFunc != NULL) {
2437 xmlXPathObjectPtr ret;
2438
2439 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2440 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002441 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002442 }
2443 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2444}
2445
2446/**
2447 * xmlXPathVariableLookupNS:
2448 * @ctxt: the XPath context
2449 * @name: the variable name
2450 * @ns_uri: the variable namespace URI
2451 *
2452 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002453 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002454 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002455 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002456 */
2457xmlXPathObjectPtr
2458xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2459 const xmlChar *ns_uri) {
2460 if (ctxt == NULL)
2461 return(NULL);
2462
2463 if (ctxt->varLookupFunc != NULL) {
2464 xmlXPathObjectPtr ret;
2465
2466 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2467 (ctxt->varLookupData, name, ns_uri);
2468 if (ret != NULL) return(ret);
2469 }
2470
2471 if (ctxt->varHash == NULL)
2472 return(NULL);
2473 if (name == NULL)
2474 return(NULL);
2475
Daniel Veillard8c357d52001-07-03 23:43:33 +00002476 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2477 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002478}
2479
2480/**
2481 * xmlXPathRegisteredVariablesCleanup:
2482 * @ctxt: the XPath context
2483 *
2484 * Cleanup the XPath context data associated to registered variables
2485 */
2486void
2487xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2488 if (ctxt == NULL)
2489 return;
2490
Daniel Veillard76d66f42001-05-16 21:05:17 +00002491 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002492 ctxt->varHash = NULL;
2493}
2494
2495/**
2496 * xmlXPathRegisterNs:
2497 * @ctxt: the XPath context
2498 * @prefix: the namespace prefix
2499 * @ns_uri: the namespace name
2500 *
2501 * Register a new namespace. If @ns_uri is NULL it unregisters
2502 * the namespace
2503 *
2504 * Returns 0 in case of success, -1 in case of error
2505 */
2506int
2507xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2508 const xmlChar *ns_uri) {
2509 if (ctxt == NULL)
2510 return(-1);
2511 if (prefix == NULL)
2512 return(-1);
2513
2514 if (ctxt->nsHash == NULL)
2515 ctxt->nsHash = xmlHashCreate(10);
2516 if (ctxt->nsHash == NULL)
2517 return(-1);
2518 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2519 (xmlHashDeallocator)xmlFree));
2520}
2521
2522/**
2523 * xmlXPathNsLookup:
2524 * @ctxt: the XPath context
2525 * @prefix: the namespace prefix value
2526 *
2527 * Search in the namespace declaration array of the context for the given
2528 * namespace name associated to the given prefix
2529 *
2530 * Returns the value or NULL if not found
2531 */
2532const xmlChar *
2533xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2534 if (ctxt == NULL)
2535 return(NULL);
2536 if (prefix == NULL)
2537 return(NULL);
2538
2539#ifdef XML_XML_NAMESPACE
2540 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2541 return(XML_XML_NAMESPACE);
2542#endif
2543
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002544 if (ctxt->namespaces != NULL) {
2545 int i;
2546
2547 for (i = 0;i < ctxt->nsNr;i++) {
2548 if ((ctxt->namespaces[i] != NULL) &&
2549 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2550 return(ctxt->namespaces[i]->href);
2551 }
2552 }
Owen Taylor3473f882001-02-23 17:55:21 +00002553
2554 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2555}
2556
2557/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002558 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002559 * @ctxt: the XPath context
2560 *
2561 * Cleanup the XPath context data associated to registered variables
2562 */
2563void
2564xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2565 if (ctxt == NULL)
2566 return;
2567
2568 xmlHashFree(ctxt->nsHash, NULL);
2569 ctxt->nsHash = NULL;
2570}
2571
2572/************************************************************************
2573 * *
2574 * Routines to handle Values *
2575 * *
2576 ************************************************************************/
2577
2578/* Allocations are terrible, one need to optimize all this !!! */
2579
2580/**
2581 * xmlXPathNewFloat:
2582 * @val: the double value
2583 *
2584 * Create a new xmlXPathObjectPtr of type double and of value @val
2585 *
2586 * Returns the newly created object.
2587 */
2588xmlXPathObjectPtr
2589xmlXPathNewFloat(double val) {
2590 xmlXPathObjectPtr ret;
2591
2592 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2593 if (ret == NULL) {
2594 xmlGenericError(xmlGenericErrorContext,
2595 "xmlXPathNewFloat: out of memory\n");
2596 return(NULL);
2597 }
2598 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2599 ret->type = XPATH_NUMBER;
2600 ret->floatval = val;
2601 return(ret);
2602}
2603
2604/**
2605 * xmlXPathNewBoolean:
2606 * @val: the boolean value
2607 *
2608 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2609 *
2610 * Returns the newly created object.
2611 */
2612xmlXPathObjectPtr
2613xmlXPathNewBoolean(int val) {
2614 xmlXPathObjectPtr ret;
2615
2616 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2617 if (ret == NULL) {
2618 xmlGenericError(xmlGenericErrorContext,
2619 "xmlXPathNewBoolean: out of memory\n");
2620 return(NULL);
2621 }
2622 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2623 ret->type = XPATH_BOOLEAN;
2624 ret->boolval = (val != 0);
2625 return(ret);
2626}
2627
2628/**
2629 * xmlXPathNewString:
2630 * @val: the xmlChar * value
2631 *
2632 * Create a new xmlXPathObjectPtr of type string and of value @val
2633 *
2634 * Returns the newly created object.
2635 */
2636xmlXPathObjectPtr
2637xmlXPathNewString(const xmlChar *val) {
2638 xmlXPathObjectPtr ret;
2639
2640 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2641 if (ret == NULL) {
2642 xmlGenericError(xmlGenericErrorContext,
2643 "xmlXPathNewString: out of memory\n");
2644 return(NULL);
2645 }
2646 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2647 ret->type = XPATH_STRING;
2648 if (val != NULL)
2649 ret->stringval = xmlStrdup(val);
2650 else
2651 ret->stringval = xmlStrdup((const xmlChar *)"");
2652 return(ret);
2653}
2654
2655/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002656 * xmlXPathWrapString:
2657 * @val: the xmlChar * value
2658 *
2659 * Wraps the @val string into an XPath object.
2660 *
2661 * Returns the newly created object.
2662 */
2663xmlXPathObjectPtr
2664xmlXPathWrapString (xmlChar *val) {
2665 xmlXPathObjectPtr ret;
2666
2667 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2668 if (ret == NULL) {
2669 xmlGenericError(xmlGenericErrorContext,
2670 "xmlXPathWrapString: out of memory\n");
2671 return(NULL);
2672 }
2673 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2674 ret->type = XPATH_STRING;
2675 ret->stringval = val;
2676 return(ret);
2677}
2678
2679/**
Owen Taylor3473f882001-02-23 17:55:21 +00002680 * xmlXPathNewCString:
2681 * @val: the char * value
2682 *
2683 * Create a new xmlXPathObjectPtr of type string and of value @val
2684 *
2685 * Returns the newly created object.
2686 */
2687xmlXPathObjectPtr
2688xmlXPathNewCString(const char *val) {
2689 xmlXPathObjectPtr ret;
2690
2691 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2692 if (ret == NULL) {
2693 xmlGenericError(xmlGenericErrorContext,
2694 "xmlXPathNewCString: out of memory\n");
2695 return(NULL);
2696 }
2697 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2698 ret->type = XPATH_STRING;
2699 ret->stringval = xmlStrdup(BAD_CAST val);
2700 return(ret);
2701}
2702
2703/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002704 * xmlXPathWrapCString:
2705 * @val: the char * value
2706 *
2707 * Wraps a string into an XPath object.
2708 *
2709 * Returns the newly created object.
2710 */
2711xmlXPathObjectPtr
2712xmlXPathWrapCString (char * val) {
2713 return(xmlXPathWrapString((xmlChar *)(val)));
2714}
2715
2716/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002717 * xmlXPathWrapExternal:
2718 * @val: the user data
2719 *
2720 * Wraps the @val data into an XPath object.
2721 *
2722 * Returns the newly created object.
2723 */
2724xmlXPathObjectPtr
2725xmlXPathWrapExternal (void *val) {
2726 xmlXPathObjectPtr ret;
2727
2728 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2729 if (ret == NULL) {
2730 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002731 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002732 return(NULL);
2733 }
2734 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2735 ret->type = XPATH_USERS;
2736 ret->user = val;
2737 return(ret);
2738}
2739
2740/**
Owen Taylor3473f882001-02-23 17:55:21 +00002741 * xmlXPathObjectCopy:
2742 * @val: the original object
2743 *
2744 * allocate a new copy of a given object
2745 *
2746 * Returns the newly created object.
2747 */
2748xmlXPathObjectPtr
2749xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2750 xmlXPathObjectPtr ret;
2751
2752 if (val == NULL)
2753 return(NULL);
2754
2755 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2756 if (ret == NULL) {
2757 xmlGenericError(xmlGenericErrorContext,
2758 "xmlXPathObjectCopy: out of memory\n");
2759 return(NULL);
2760 }
2761 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2762 switch (val->type) {
2763 case XPATH_BOOLEAN:
2764 case XPATH_NUMBER:
2765 case XPATH_POINT:
2766 case XPATH_RANGE:
2767 break;
2768 case XPATH_STRING:
2769 ret->stringval = xmlStrdup(val->stringval);
2770 break;
2771 case XPATH_XSLT_TREE:
2772 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002773 (val->nodesetval->nodeTab != NULL)) {
2774 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00002775 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
2776 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002777 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002778 (xmlNodePtr) ret->user);
2779 } else
Owen Taylor3473f882001-02-23 17:55:21 +00002780 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002781 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00002782 break;
2783 case XPATH_NODESET:
2784 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002785 /* Do not deallocate the copied tree value */
2786 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002787 break;
2788 case XPATH_LOCATIONSET:
2789#ifdef LIBXML_XPTR_ENABLED
2790 {
2791 xmlLocationSetPtr loc = val->user;
2792 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2793 break;
2794 }
2795#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00002796 case XPATH_USERS:
2797 ret->user = val->user;
2798 break;
2799 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00002800 xmlGenericError(xmlGenericErrorContext,
2801 "xmlXPathObjectCopy: unsupported type %d\n",
2802 val->type);
2803 break;
2804 }
2805 return(ret);
2806}
2807
2808/**
2809 * xmlXPathFreeObject:
2810 * @obj: the object to free
2811 *
2812 * Free up an xmlXPathObjectPtr object.
2813 */
2814void
2815xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2816 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002817 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00002818 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002819 if (obj->user != NULL) {
2820 xmlFreeNodeList((xmlNodePtr) obj->user);
2821 xmlXPathFreeNodeSet(obj->nodesetval);
2822 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00002823 xmlXPathFreeValueTree(obj->nodesetval);
2824 } else {
2825 if (obj->nodesetval != NULL)
2826 xmlXPathFreeNodeSet(obj->nodesetval);
2827 }
Owen Taylor3473f882001-02-23 17:55:21 +00002828#ifdef LIBXML_XPTR_ENABLED
2829 } else if (obj->type == XPATH_LOCATIONSET) {
2830 if (obj->user != NULL)
2831 xmlXPtrFreeLocationSet(obj->user);
2832#endif
2833 } else if (obj->type == XPATH_STRING) {
2834 if (obj->stringval != NULL)
2835 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00002836 }
2837
Owen Taylor3473f882001-02-23 17:55:21 +00002838 xmlFree(obj);
2839}
2840
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002841
2842/************************************************************************
2843 * *
2844 * Type Casting Routines *
2845 * *
2846 ************************************************************************/
2847
2848/**
2849 * xmlXPathCastBooleanToString:
2850 * @val: a boolean
2851 *
2852 * Converts a boolean to its string value.
2853 *
2854 * Returns a newly allocated string.
2855 */
2856xmlChar *
2857xmlXPathCastBooleanToString (int val) {
2858 xmlChar *ret;
2859 if (val)
2860 ret = xmlStrdup((const xmlChar *) "true");
2861 else
2862 ret = xmlStrdup((const xmlChar *) "false");
2863 return(ret);
2864}
2865
2866/**
2867 * xmlXPathCastNumberToString:
2868 * @val: a number
2869 *
2870 * Converts a number to its string value.
2871 *
2872 * Returns a newly allocated string.
2873 */
2874xmlChar *
2875xmlXPathCastNumberToString (double val) {
2876 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00002877 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002878 case 1:
2879 ret = xmlStrdup((const xmlChar *) "+Infinity");
2880 break;
2881 case -1:
2882 ret = xmlStrdup((const xmlChar *) "-Infinity");
2883 break;
2884 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002885 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002886 ret = xmlStrdup((const xmlChar *) "NaN");
2887 } else {
2888 /* could be improved */
2889 char buf[100];
2890 xmlXPathFormatNumber(val, buf, 100);
2891 ret = xmlStrdup((const xmlChar *) buf);
2892 }
2893 }
2894 return(ret);
2895}
2896
2897/**
2898 * xmlXPathCastNodeToString:
2899 * @node: a node
2900 *
2901 * Converts a node to its string value.
2902 *
2903 * Returns a newly allocated string.
2904 */
2905xmlChar *
2906xmlXPathCastNodeToString (xmlNodePtr node) {
2907 return(xmlNodeGetContent(node));
2908}
2909
2910/**
2911 * xmlXPathCastNodeSetToString:
2912 * @ns: a node-set
2913 *
2914 * Converts a node-set to its string value.
2915 *
2916 * Returns a newly allocated string.
2917 */
2918xmlChar *
2919xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2920 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2921 return(xmlStrdup((const xmlChar *) ""));
2922
2923 xmlXPathNodeSetSort(ns);
2924 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2925}
2926
2927/**
2928 * xmlXPathCastToString:
2929 * @val: an XPath object
2930 *
2931 * Converts an existing object to its string() equivalent
2932 *
2933 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002934 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002935 * string object).
2936 */
2937xmlChar *
2938xmlXPathCastToString(xmlXPathObjectPtr val) {
2939 xmlChar *ret = NULL;
2940
2941 if (val == NULL)
2942 return(xmlStrdup((const xmlChar *) ""));
2943 switch (val->type) {
2944 case XPATH_UNDEFINED:
2945#ifdef DEBUG_EXPR
2946 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2947#endif
2948 ret = xmlStrdup((const xmlChar *) "");
2949 break;
2950 case XPATH_XSLT_TREE:
2951 case XPATH_NODESET:
2952 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2953 break;
2954 case XPATH_STRING:
2955 return(val->stringval);
2956 case XPATH_BOOLEAN:
2957 ret = xmlXPathCastBooleanToString(val->boolval);
2958 break;
2959 case XPATH_NUMBER: {
2960 ret = xmlXPathCastNumberToString(val->floatval);
2961 break;
2962 }
2963 case XPATH_USERS:
2964 case XPATH_POINT:
2965 case XPATH_RANGE:
2966 case XPATH_LOCATIONSET:
2967 TODO
2968 ret = xmlStrdup((const xmlChar *) "");
2969 break;
2970 }
2971 return(ret);
2972}
2973
2974/**
2975 * xmlXPathConvertString:
2976 * @val: an XPath object
2977 *
2978 * Converts an existing object to its string() equivalent
2979 *
2980 * Returns the new object, the old one is freed (or the operation
2981 * is done directly on @val)
2982 */
2983xmlXPathObjectPtr
2984xmlXPathConvertString(xmlXPathObjectPtr val) {
2985 xmlChar *res = NULL;
2986
2987 if (val == NULL)
2988 return(xmlXPathNewCString(""));
2989
2990 switch (val->type) {
2991 case XPATH_UNDEFINED:
2992#ifdef DEBUG_EXPR
2993 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2994#endif
2995 break;
2996 case XPATH_XSLT_TREE:
2997 case XPATH_NODESET:
2998 res = xmlXPathCastNodeSetToString(val->nodesetval);
2999 break;
3000 case XPATH_STRING:
3001 return(val);
3002 case XPATH_BOOLEAN:
3003 res = xmlXPathCastBooleanToString(val->boolval);
3004 break;
3005 case XPATH_NUMBER:
3006 res = xmlXPathCastNumberToString(val->floatval);
3007 break;
3008 case XPATH_USERS:
3009 case XPATH_POINT:
3010 case XPATH_RANGE:
3011 case XPATH_LOCATIONSET:
3012 TODO;
3013 break;
3014 }
3015 xmlXPathFreeObject(val);
3016 if (res == NULL)
3017 return(xmlXPathNewCString(""));
3018 return(xmlXPathWrapString(res));
3019}
3020
3021/**
3022 * xmlXPathCastBooleanToNumber:
3023 * @val: a boolean
3024 *
3025 * Converts a boolean to its number value
3026 *
3027 * Returns the number value
3028 */
3029double
3030xmlXPathCastBooleanToNumber(int val) {
3031 if (val)
3032 return(1.0);
3033 return(0.0);
3034}
3035
3036/**
3037 * xmlXPathCastStringToNumber:
3038 * @val: a string
3039 *
3040 * Converts a string to its number value
3041 *
3042 * Returns the number value
3043 */
3044double
3045xmlXPathCastStringToNumber(const xmlChar * val) {
3046 return(xmlXPathStringEvalNumber(val));
3047}
3048
3049/**
3050 * xmlXPathCastNodeToNumber:
3051 * @node: a node
3052 *
3053 * Converts a node to its number value
3054 *
3055 * Returns the number value
3056 */
3057double
3058xmlXPathCastNodeToNumber (xmlNodePtr node) {
3059 xmlChar *strval;
3060 double ret;
3061
3062 if (node == NULL)
3063 return(xmlXPathNAN);
3064 strval = xmlXPathCastNodeToString(node);
3065 if (strval == NULL)
3066 return(xmlXPathNAN);
3067 ret = xmlXPathCastStringToNumber(strval);
3068 xmlFree(strval);
3069
3070 return(ret);
3071}
3072
3073/**
3074 * xmlXPathCastNodeSetToNumber:
3075 * @ns: a node-set
3076 *
3077 * Converts a node-set to its number value
3078 *
3079 * Returns the number value
3080 */
3081double
3082xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3083 xmlChar *str;
3084 double ret;
3085
3086 if (ns == NULL)
3087 return(xmlXPathNAN);
3088 str = xmlXPathCastNodeSetToString(ns);
3089 ret = xmlXPathCastStringToNumber(str);
3090 xmlFree(str);
3091 return(ret);
3092}
3093
3094/**
3095 * xmlXPathCastToNumber:
3096 * @val: an XPath object
3097 *
3098 * Converts an XPath object to its number value
3099 *
3100 * Returns the number value
3101 */
3102double
3103xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3104 double ret = 0.0;
3105
3106 if (val == NULL)
3107 return(xmlXPathNAN);
3108 switch (val->type) {
3109 case XPATH_UNDEFINED:
3110#ifdef DEGUB_EXPR
3111 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3112#endif
3113 ret = xmlXPathNAN;
3114 break;
3115 case XPATH_XSLT_TREE:
3116 case XPATH_NODESET:
3117 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3118 break;
3119 case XPATH_STRING:
3120 ret = xmlXPathCastStringToNumber(val->stringval);
3121 break;
3122 case XPATH_NUMBER:
3123 ret = val->floatval;
3124 break;
3125 case XPATH_BOOLEAN:
3126 ret = xmlXPathCastBooleanToNumber(val->boolval);
3127 break;
3128 case XPATH_USERS:
3129 case XPATH_POINT:
3130 case XPATH_RANGE:
3131 case XPATH_LOCATIONSET:
3132 TODO;
3133 ret = xmlXPathNAN;
3134 break;
3135 }
3136 return(ret);
3137}
3138
3139/**
3140 * xmlXPathConvertNumber:
3141 * @val: an XPath object
3142 *
3143 * Converts an existing object to its number() equivalent
3144 *
3145 * Returns the new object, the old one is freed (or the operation
3146 * is done directly on @val)
3147 */
3148xmlXPathObjectPtr
3149xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3150 xmlXPathObjectPtr ret;
3151
3152 if (val == NULL)
3153 return(xmlXPathNewFloat(0.0));
3154 if (val->type == XPATH_NUMBER)
3155 return(val);
3156 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3157 xmlXPathFreeObject(val);
3158 return(ret);
3159}
3160
3161/**
3162 * xmlXPathCastNumberToBoolean:
3163 * @val: a number
3164 *
3165 * Converts a number to its boolean value
3166 *
3167 * Returns the boolean value
3168 */
3169int
3170xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003171 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003172 return(0);
3173 return(1);
3174}
3175
3176/**
3177 * xmlXPathCastStringToBoolean:
3178 * @val: a string
3179 *
3180 * Converts a string to its boolean value
3181 *
3182 * Returns the boolean value
3183 */
3184int
3185xmlXPathCastStringToBoolean (const xmlChar *val) {
3186 if ((val == NULL) || (xmlStrlen(val) == 0))
3187 return(0);
3188 return(1);
3189}
3190
3191/**
3192 * xmlXPathCastNodeSetToBoolean:
3193 * @ns: a node-set
3194 *
3195 * Converts a node-set to its boolean value
3196 *
3197 * Returns the boolean value
3198 */
3199int
3200xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3201 if ((ns == NULL) || (ns->nodeNr == 0))
3202 return(0);
3203 return(1);
3204}
3205
3206/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003207 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003208 * @val: an XPath object
3209 *
3210 * Converts an XPath object to its boolean value
3211 *
3212 * Returns the boolean value
3213 */
3214int
3215xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3216 int ret = 0;
3217
3218 if (val == NULL)
3219 return(0);
3220 switch (val->type) {
3221 case XPATH_UNDEFINED:
3222#ifdef DEBUG_EXPR
3223 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3224#endif
3225 ret = 0;
3226 break;
3227 case XPATH_XSLT_TREE:
3228 case XPATH_NODESET:
3229 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3230 break;
3231 case XPATH_STRING:
3232 ret = xmlXPathCastStringToBoolean(val->stringval);
3233 break;
3234 case XPATH_NUMBER:
3235 ret = xmlXPathCastNumberToBoolean(val->floatval);
3236 break;
3237 case XPATH_BOOLEAN:
3238 ret = val->boolval;
3239 break;
3240 case XPATH_USERS:
3241 case XPATH_POINT:
3242 case XPATH_RANGE:
3243 case XPATH_LOCATIONSET:
3244 TODO;
3245 ret = 0;
3246 break;
3247 }
3248 return(ret);
3249}
3250
3251
3252/**
3253 * xmlXPathConvertBoolean:
3254 * @val: an XPath object
3255 *
3256 * Converts an existing object to its boolean() equivalent
3257 *
3258 * Returns the new object, the old one is freed (or the operation
3259 * is done directly on @val)
3260 */
3261xmlXPathObjectPtr
3262xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3263 xmlXPathObjectPtr ret;
3264
3265 if (val == NULL)
3266 return(xmlXPathNewBoolean(0));
3267 if (val->type == XPATH_BOOLEAN)
3268 return(val);
3269 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3270 xmlXPathFreeObject(val);
3271 return(ret);
3272}
3273
Owen Taylor3473f882001-02-23 17:55:21 +00003274/************************************************************************
3275 * *
3276 * Routines to handle XPath contexts *
3277 * *
3278 ************************************************************************/
3279
3280/**
3281 * xmlXPathNewContext:
3282 * @doc: the XML document
3283 *
3284 * Create a new xmlXPathContext
3285 *
3286 * Returns the xmlXPathContext just allocated.
3287 */
3288xmlXPathContextPtr
3289xmlXPathNewContext(xmlDocPtr doc) {
3290 xmlXPathContextPtr ret;
3291
3292 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3293 if (ret == NULL) {
3294 xmlGenericError(xmlGenericErrorContext,
3295 "xmlXPathNewContext: out of memory\n");
3296 return(NULL);
3297 }
3298 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3299 ret->doc = doc;
3300 ret->node = NULL;
3301
3302 ret->varHash = NULL;
3303
3304 ret->nb_types = 0;
3305 ret->max_types = 0;
3306 ret->types = NULL;
3307
3308 ret->funcHash = xmlHashCreate(0);
3309
3310 ret->nb_axis = 0;
3311 ret->max_axis = 0;
3312 ret->axis = NULL;
3313
3314 ret->nsHash = NULL;
3315 ret->user = NULL;
3316
3317 ret->contextSize = -1;
3318 ret->proximityPosition = -1;
3319
3320 xmlXPathRegisterAllFunctions(ret);
3321
3322 return(ret);
3323}
3324
3325/**
3326 * xmlXPathFreeContext:
3327 * @ctxt: the context to free
3328 *
3329 * Free up an xmlXPathContext
3330 */
3331void
3332xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3333 xmlXPathRegisteredNsCleanup(ctxt);
3334 xmlXPathRegisteredFuncsCleanup(ctxt);
3335 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003336 xmlFree(ctxt);
3337}
3338
3339/************************************************************************
3340 * *
3341 * Routines to handle XPath parser contexts *
3342 * *
3343 ************************************************************************/
3344
3345#define CHECK_CTXT(ctxt) \
3346 if (ctxt == NULL) { \
3347 xmlGenericError(xmlGenericErrorContext, \
3348 "%s:%d Internal error: ctxt == NULL\n", \
3349 __FILE__, __LINE__); \
3350 } \
3351
3352
3353#define CHECK_CONTEXT(ctxt) \
3354 if (ctxt == NULL) { \
3355 xmlGenericError(xmlGenericErrorContext, \
3356 "%s:%d Internal error: no context\n", \
3357 __FILE__, __LINE__); \
3358 } \
3359 else if (ctxt->doc == NULL) { \
3360 xmlGenericError(xmlGenericErrorContext, \
3361 "%s:%d Internal error: no document\n", \
3362 __FILE__, __LINE__); \
3363 } \
3364 else if (ctxt->doc->children == NULL) { \
3365 xmlGenericError(xmlGenericErrorContext, \
3366 "%s:%d Internal error: document without root\n", \
3367 __FILE__, __LINE__); \
3368 } \
3369
3370
3371/**
3372 * xmlXPathNewParserContext:
3373 * @str: the XPath expression
3374 * @ctxt: the XPath context
3375 *
3376 * Create a new xmlXPathParserContext
3377 *
3378 * Returns the xmlXPathParserContext just allocated.
3379 */
3380xmlXPathParserContextPtr
3381xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3382 xmlXPathParserContextPtr ret;
3383
3384 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3385 if (ret == NULL) {
3386 xmlGenericError(xmlGenericErrorContext,
3387 "xmlXPathNewParserContext: out of memory\n");
3388 return(NULL);
3389 }
3390 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3391 ret->cur = ret->base = str;
3392 ret->context = ctxt;
3393
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003394 ret->comp = xmlXPathNewCompExpr();
3395 if (ret->comp == NULL) {
3396 xmlFree(ret->valueTab);
3397 xmlFree(ret);
3398 return(NULL);
3399 }
3400
3401 return(ret);
3402}
3403
3404/**
3405 * xmlXPathCompParserContext:
3406 * @comp: the XPath compiled expression
3407 * @ctxt: the XPath context
3408 *
3409 * Create a new xmlXPathParserContext when processing a compiled expression
3410 *
3411 * Returns the xmlXPathParserContext just allocated.
3412 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003413static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003414xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3415 xmlXPathParserContextPtr ret;
3416
3417 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3418 if (ret == NULL) {
3419 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003420 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003421 return(NULL);
3422 }
3423 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3424
Owen Taylor3473f882001-02-23 17:55:21 +00003425 /* Allocate the value stack */
3426 ret->valueTab = (xmlXPathObjectPtr *)
3427 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003428 if (ret->valueTab == NULL) {
3429 xmlFree(ret);
3430 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003431 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003432 return(NULL);
3433 }
Owen Taylor3473f882001-02-23 17:55:21 +00003434 ret->valueNr = 0;
3435 ret->valueMax = 10;
3436 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003437
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003438 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003439 ret->comp = comp;
3440
Owen Taylor3473f882001-02-23 17:55:21 +00003441 return(ret);
3442}
3443
3444/**
3445 * xmlXPathFreeParserContext:
3446 * @ctxt: the context to free
3447 *
3448 * Free up an xmlXPathParserContext
3449 */
3450void
3451xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3452 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003453 xmlFree(ctxt->valueTab);
3454 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003455 if (ctxt->comp)
3456 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003457 xmlFree(ctxt);
3458}
3459
3460/************************************************************************
3461 * *
3462 * The implicit core function library *
3463 * *
3464 ************************************************************************/
3465
Owen Taylor3473f882001-02-23 17:55:21 +00003466/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003467 * xmlXPathNodeStringHash:
3468 * @node: a node pointer
3469 *
3470 * Function computing the beginning of the string value of the node,
3471 * used to speed up comparisons
3472 *
3473 * Returns an int usable as a hash
3474 */
3475static unsigned int
3476xmlXPathNodeValHash(xmlNodePtr node) {
3477 int len = 2;
3478 const xmlChar * string = NULL;
3479 xmlNodePtr tmp = NULL;
3480 unsigned int ret = 0;
3481
3482 if (node == NULL)
3483 return(0);
3484
3485
3486 switch (node->type) {
3487 case XML_COMMENT_NODE:
3488 case XML_PI_NODE:
3489 case XML_CDATA_SECTION_NODE:
3490 case XML_TEXT_NODE:
3491 string = node->content;
3492 if (string == NULL)
3493 return(0);
3494 if (string[0] == 0)
3495 return(0);
3496 return(((unsigned int) string[0]) +
3497 (((unsigned int) string[1]) << 8));
3498 case XML_NAMESPACE_DECL:
3499 string = ((xmlNsPtr)node)->href;
3500 if (string == NULL)
3501 return(0);
3502 if (string[0] == 0)
3503 return(0);
3504 return(((unsigned int) string[0]) +
3505 (((unsigned int) string[1]) << 8));
3506 case XML_ATTRIBUTE_NODE:
3507 tmp = ((xmlAttrPtr) node)->children;
3508 break;
3509 case XML_ELEMENT_NODE:
3510 tmp = node->children;
3511 break;
3512 default:
3513 return(0);
3514 }
3515 while (tmp != NULL) {
3516 switch (tmp->type) {
3517 case XML_COMMENT_NODE:
3518 case XML_PI_NODE:
3519 case XML_CDATA_SECTION_NODE:
3520 case XML_TEXT_NODE:
3521 string = tmp->content;
3522 break;
3523 case XML_NAMESPACE_DECL:
3524 string = ((xmlNsPtr)tmp)->href;
3525 break;
3526 default:
3527 break;
3528 }
3529 if ((string != NULL) && (string[0] != 0)) {
3530 if (string[0] == 0)
3531 return(0);
3532 if (len == 1) {
3533 return(ret + (((unsigned int) string[0]) << 8));
3534 }
3535 if (string[1] == 0) {
3536 len = 1;
3537 ret = (unsigned int) string[0];
3538 } else {
3539 return(((unsigned int) string[0]) +
3540 (((unsigned int) string[1]) << 8));
3541 }
3542 }
3543 /*
3544 * Skip to next node
3545 */
3546 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3547 if (tmp->children->type != XML_ENTITY_DECL) {
3548 tmp = tmp->children;
3549 continue;
3550 }
3551 }
3552 if (tmp == node)
3553 break;
3554
3555 if (tmp->next != NULL) {
3556 tmp = tmp->next;
3557 continue;
3558 }
3559
3560 do {
3561 tmp = tmp->parent;
3562 if (tmp == NULL)
3563 break;
3564 if (tmp == node) {
3565 tmp = NULL;
3566 break;
3567 }
3568 if (tmp->next != NULL) {
3569 tmp = tmp->next;
3570 break;
3571 }
3572 } while (tmp != NULL);
3573 }
3574 return(ret);
3575}
3576
3577/**
3578 * xmlXPathStringHash:
3579 * @string: a string
3580 *
3581 * Function computing the beginning of the string value of the node,
3582 * used to speed up comparisons
3583 *
3584 * Returns an int usable as a hash
3585 */
3586static unsigned int
3587xmlXPathStringHash(const xmlChar * string) {
3588 if (string == NULL)
3589 return((unsigned int) 0);
3590 if (string[0] == 0)
3591 return(0);
3592 return(((unsigned int) string[0]) +
3593 (((unsigned int) string[1]) << 8));
3594}
3595
3596/**
Owen Taylor3473f882001-02-23 17:55:21 +00003597 * xmlXPathCompareNodeSetFloat:
3598 * @ctxt: the XPath Parser context
3599 * @inf: less than (1) or greater than (0)
3600 * @strict: is the comparison strict
3601 * @arg: the node set
3602 * @f: the value
3603 *
3604 * Implement the compare operation between a nodeset and a number
3605 * @ns < @val (1, 1, ...
3606 * @ns <= @val (1, 0, ...
3607 * @ns > @val (0, 1, ...
3608 * @ns >= @val (0, 0, ...
3609 *
3610 * If one object to be compared is a node-set and the other is a number,
3611 * then the comparison will be true if and only if there is a node in the
3612 * node-set such that the result of performing the comparison on the number
3613 * to be compared and on the result of converting the string-value of that
3614 * node to a number using the number function is true.
3615 *
3616 * Returns 0 or 1 depending on the results of the test.
3617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003618static int
Owen Taylor3473f882001-02-23 17:55:21 +00003619xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3620 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3621 int i, ret = 0;
3622 xmlNodeSetPtr ns;
3623 xmlChar *str2;
3624
3625 if ((f == NULL) || (arg == NULL) ||
3626 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3627 xmlXPathFreeObject(arg);
3628 xmlXPathFreeObject(f);
3629 return(0);
3630 }
3631 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003632 if (ns != NULL) {
3633 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003634 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003635 if (str2 != NULL) {
3636 valuePush(ctxt,
3637 xmlXPathNewString(str2));
3638 xmlFree(str2);
3639 xmlXPathNumberFunction(ctxt, 1);
3640 valuePush(ctxt, xmlXPathObjectCopy(f));
3641 ret = xmlXPathCompareValues(ctxt, inf, strict);
3642 if (ret)
3643 break;
3644 }
3645 }
Owen Taylor3473f882001-02-23 17:55:21 +00003646 }
3647 xmlXPathFreeObject(arg);
3648 xmlXPathFreeObject(f);
3649 return(ret);
3650}
3651
3652/**
3653 * xmlXPathCompareNodeSetString:
3654 * @ctxt: the XPath Parser context
3655 * @inf: less than (1) or greater than (0)
3656 * @strict: is the comparison strict
3657 * @arg: the node set
3658 * @s: the value
3659 *
3660 * Implement the compare operation between a nodeset and a string
3661 * @ns < @val (1, 1, ...
3662 * @ns <= @val (1, 0, ...
3663 * @ns > @val (0, 1, ...
3664 * @ns >= @val (0, 0, ...
3665 *
3666 * If one object to be compared is a node-set and the other is a string,
3667 * then the comparison will be true if and only if there is a node in
3668 * the node-set such that the result of performing the comparison on the
3669 * string-value of the node and the other string is true.
3670 *
3671 * Returns 0 or 1 depending on the results of the test.
3672 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003673static int
Owen Taylor3473f882001-02-23 17:55:21 +00003674xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3675 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3676 int i, ret = 0;
3677 xmlNodeSetPtr ns;
3678 xmlChar *str2;
3679
3680 if ((s == NULL) || (arg == NULL) ||
3681 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3682 xmlXPathFreeObject(arg);
3683 xmlXPathFreeObject(s);
3684 return(0);
3685 }
3686 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003687 if (ns != NULL) {
3688 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003689 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003690 if (str2 != NULL) {
3691 valuePush(ctxt,
3692 xmlXPathNewString(str2));
3693 xmlFree(str2);
3694 valuePush(ctxt, xmlXPathObjectCopy(s));
3695 ret = xmlXPathCompareValues(ctxt, inf, strict);
3696 if (ret)
3697 break;
3698 }
3699 }
Owen Taylor3473f882001-02-23 17:55:21 +00003700 }
3701 xmlXPathFreeObject(arg);
3702 xmlXPathFreeObject(s);
3703 return(ret);
3704}
3705
3706/**
3707 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003708 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003709 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003710 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00003711 * @arg2: the second node set object
3712 *
3713 * Implement the compare operation on nodesets:
3714 *
3715 * If both objects to be compared are node-sets, then the comparison
3716 * will be true if and only if there is a node in the first node-set
3717 * and a node in the second node-set such that the result of performing
3718 * the comparison on the string-values of the two nodes is true.
3719 * ....
3720 * When neither object to be compared is a node-set and the operator
3721 * is <=, <, >= or >, then the objects are compared by converting both
3722 * objects to numbers and comparing the numbers according to IEEE 754.
3723 * ....
3724 * The number function converts its argument to a number as follows:
3725 * - a string that consists of optional whitespace followed by an
3726 * optional minus sign followed by a Number followed by whitespace
3727 * is converted to the IEEE 754 number that is nearest (according
3728 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3729 * represented by the string; any other string is converted to NaN
3730 *
3731 * Conclusion all nodes need to be converted first to their string value
3732 * and then the comparison must be done when possible
3733 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003734static int
3735xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003736 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3737 int i, j, init = 0;
3738 double val1;
3739 double *values2;
3740 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003741 xmlNodeSetPtr ns1;
3742 xmlNodeSetPtr ns2;
3743
3744 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003745 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3746 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003747 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003748 }
Owen Taylor3473f882001-02-23 17:55:21 +00003749 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003750 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3751 xmlXPathFreeObject(arg1);
3752 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003753 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003754 }
Owen Taylor3473f882001-02-23 17:55:21 +00003755
3756 ns1 = arg1->nodesetval;
3757 ns2 = arg2->nodesetval;
3758
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003759 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003760 xmlXPathFreeObject(arg1);
3761 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003762 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003763 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003764 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003765 xmlXPathFreeObject(arg1);
3766 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003767 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003768 }
Owen Taylor3473f882001-02-23 17:55:21 +00003769
3770 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3771 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003772 xmlXPathFreeObject(arg1);
3773 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003774 return(0);
3775 }
3776 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003777 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00003778 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003779 continue;
3780 for (j = 0;j < ns2->nodeNr;j++) {
3781 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003782 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003783 }
Daniel Veillardcda96922001-08-21 10:56:31 +00003784 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003785 continue;
3786 if (inf && strict)
3787 ret = (val1 < values2[j]);
3788 else if (inf && !strict)
3789 ret = (val1 <= values2[j]);
3790 else if (!inf && strict)
3791 ret = (val1 > values2[j]);
3792 else if (!inf && !strict)
3793 ret = (val1 >= values2[j]);
3794 if (ret)
3795 break;
3796 }
3797 if (ret)
3798 break;
3799 init = 1;
3800 }
3801 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003802 xmlXPathFreeObject(arg1);
3803 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003804 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003805}
3806
3807/**
3808 * xmlXPathCompareNodeSetValue:
3809 * @ctxt: the XPath Parser context
3810 * @inf: less than (1) or greater than (0)
3811 * @strict: is the comparison strict
3812 * @arg: the node set
3813 * @val: the value
3814 *
3815 * Implement the compare operation between a nodeset and a value
3816 * @ns < @val (1, 1, ...
3817 * @ns <= @val (1, 0, ...
3818 * @ns > @val (0, 1, ...
3819 * @ns >= @val (0, 0, ...
3820 *
3821 * If one object to be compared is a node-set and the other is a boolean,
3822 * then the comparison will be true if and only if the result of performing
3823 * the comparison on the boolean and on the result of converting
3824 * the node-set to a boolean using the boolean function is true.
3825 *
3826 * Returns 0 or 1 depending on the results of the test.
3827 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003828static int
Owen Taylor3473f882001-02-23 17:55:21 +00003829xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3830 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3831 if ((val == NULL) || (arg == NULL) ||
3832 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3833 return(0);
3834
3835 switch(val->type) {
3836 case XPATH_NUMBER:
3837 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3838 case XPATH_NODESET:
3839 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003840 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003841 case XPATH_STRING:
3842 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3843 case XPATH_BOOLEAN:
3844 valuePush(ctxt, arg);
3845 xmlXPathBooleanFunction(ctxt, 1);
3846 valuePush(ctxt, val);
3847 return(xmlXPathCompareValues(ctxt, inf, strict));
3848 default:
3849 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00003850 }
3851 return(0);
3852}
3853
3854/**
3855 * xmlXPathEqualNodeSetString
3856 * @arg: the nodeset object argument
3857 * @str: the string to compare to.
3858 *
3859 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3860 * If one object to be compared is a node-set and the other is a string,
3861 * then the comparison will be true if and only if there is a node in
3862 * the node-set such that the result of performing the comparison on the
3863 * string-value of the node and the other string is true.
3864 *
3865 * Returns 0 or 1 depending on the results of the test.
3866 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003867static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003868xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3869{
Owen Taylor3473f882001-02-23 17:55:21 +00003870 int i;
3871 xmlNodeSetPtr ns;
3872 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003873 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003874
3875 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003876 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3877 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003878 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003879 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003880 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003881 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003882 if (ns->nodeNr <= 0) {
3883 if (hash == 0)
3884 return(1);
3885 return(0);
3886 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003887 for (i = 0; i < ns->nodeNr; i++) {
3888 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3889 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3890 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3891 xmlFree(str2);
3892 return (1);
3893 }
3894 if (str2 != NULL)
3895 xmlFree(str2);
3896 }
Owen Taylor3473f882001-02-23 17:55:21 +00003897 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003898 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003899}
3900
3901/**
3902 * xmlXPathEqualNodeSetFloat
3903 * @arg: the nodeset object argument
3904 * @f: the float to compare to
3905 *
3906 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3907 * If one object to be compared is a node-set and the other is a number,
3908 * then the comparison will be true if and only if there is a node in
3909 * the node-set such that the result of performing the comparison on the
3910 * number to be compared and on the result of converting the string-value
3911 * of that node to a number using the number function is true.
3912 *
3913 * Returns 0 or 1 depending on the results of the test.
3914 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003915static int
Owen Taylor3473f882001-02-23 17:55:21 +00003916xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3917 char buf[100] = "";
3918
3919 if ((arg == NULL) ||
3920 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3921 return(0);
3922
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003923 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003924 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3925}
3926
3927
3928/**
3929 * xmlXPathEqualNodeSets
3930 * @arg1: first nodeset object argument
3931 * @arg2: second nodeset object argument
3932 *
3933 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3934 * If both objects to be compared are node-sets, then the comparison
3935 * will be true if and only if there is a node in the first node-set and
3936 * a node in the second node-set such that the result of performing the
3937 * comparison on the string-values of the two nodes is true.
3938 *
3939 * (needless to say, this is a costly operation)
3940 *
3941 * Returns 0 or 1 depending on the results of the test.
3942 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003943static int
Owen Taylor3473f882001-02-23 17:55:21 +00003944xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3945 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003946 unsigned int *hashs1;
3947 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003948 xmlChar **values1;
3949 xmlChar **values2;
3950 int ret = 0;
3951 xmlNodeSetPtr ns1;
3952 xmlNodeSetPtr ns2;
3953
3954 if ((arg1 == NULL) ||
3955 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3956 return(0);
3957 if ((arg2 == NULL) ||
3958 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3959 return(0);
3960
3961 ns1 = arg1->nodesetval;
3962 ns2 = arg2->nodesetval;
3963
Daniel Veillard911f49a2001-04-07 15:39:35 +00003964 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003965 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003966 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003967 return(0);
3968
3969 /*
3970 * check if there is a node pertaining to both sets
3971 */
3972 for (i = 0;i < ns1->nodeNr;i++)
3973 for (j = 0;j < ns2->nodeNr;j++)
3974 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3975 return(1);
3976
3977 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3978 if (values1 == NULL)
3979 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003980 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3981 if (hashs1 == NULL) {
3982 xmlFree(values1);
3983 return(0);
3984 }
Owen Taylor3473f882001-02-23 17:55:21 +00003985 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3986 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3987 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003988 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003989 xmlFree(values1);
3990 return(0);
3991 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003992 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3993 if (hashs2 == NULL) {
3994 xmlFree(hashs1);
3995 xmlFree(values1);
3996 xmlFree(values2);
3997 return(0);
3998 }
Owen Taylor3473f882001-02-23 17:55:21 +00003999 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4000 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004001 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004002 for (j = 0;j < ns2->nodeNr;j++) {
4003 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004004 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4005 if (hashs1[i] == hashs2[j]) {
4006 if (values1[i] == NULL)
4007 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4008 if (values2[j] == NULL)
4009 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4010 ret = xmlStrEqual(values1[i], values2[j]);
4011 if (ret)
4012 break;
4013 }
Owen Taylor3473f882001-02-23 17:55:21 +00004014 }
4015 if (ret)
4016 break;
4017 }
4018 for (i = 0;i < ns1->nodeNr;i++)
4019 if (values1[i] != NULL)
4020 xmlFree(values1[i]);
4021 for (j = 0;j < ns2->nodeNr;j++)
4022 if (values2[j] != NULL)
4023 xmlFree(values2[j]);
4024 xmlFree(values1);
4025 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004026 xmlFree(hashs1);
4027 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004028 return(ret);
4029}
4030
4031/**
4032 * xmlXPathEqualValues:
4033 * @ctxt: the XPath Parser context
4034 *
4035 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4036 *
4037 * Returns 0 or 1 depending on the results of the test.
4038 */
4039int
4040xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4041 xmlXPathObjectPtr arg1, arg2;
4042 int ret = 0;
4043
4044 arg1 = valuePop(ctxt);
4045 if (arg1 == NULL)
4046 XP_ERROR0(XPATH_INVALID_OPERAND);
4047
4048 arg2 = valuePop(ctxt);
4049 if (arg2 == NULL) {
4050 xmlXPathFreeObject(arg1);
4051 XP_ERROR0(XPATH_INVALID_OPERAND);
4052 }
4053
4054 if (arg1 == arg2) {
4055#ifdef DEBUG_EXPR
4056 xmlGenericError(xmlGenericErrorContext,
4057 "Equal: by pointer\n");
4058#endif
4059 return(1);
4060 }
4061
4062 switch (arg1->type) {
4063 case XPATH_UNDEFINED:
4064#ifdef DEBUG_EXPR
4065 xmlGenericError(xmlGenericErrorContext,
4066 "Equal: undefined\n");
4067#endif
4068 break;
4069 case XPATH_XSLT_TREE:
4070 case XPATH_NODESET:
4071 switch (arg2->type) {
4072 case XPATH_UNDEFINED:
4073#ifdef DEBUG_EXPR
4074 xmlGenericError(xmlGenericErrorContext,
4075 "Equal: undefined\n");
4076#endif
4077 break;
4078 case XPATH_XSLT_TREE:
4079 case XPATH_NODESET:
4080 ret = xmlXPathEqualNodeSets(arg1, arg2);
4081 break;
4082 case XPATH_BOOLEAN:
4083 if ((arg1->nodesetval == NULL) ||
4084 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4085 else
4086 ret = 1;
4087 ret = (ret == arg2->boolval);
4088 break;
4089 case XPATH_NUMBER:
4090 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4091 break;
4092 case XPATH_STRING:
4093 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4094 break;
4095 case XPATH_USERS:
4096 case XPATH_POINT:
4097 case XPATH_RANGE:
4098 case XPATH_LOCATIONSET:
4099 TODO
4100 break;
4101 }
4102 break;
4103 case XPATH_BOOLEAN:
4104 switch (arg2->type) {
4105 case XPATH_UNDEFINED:
4106#ifdef DEBUG_EXPR
4107 xmlGenericError(xmlGenericErrorContext,
4108 "Equal: undefined\n");
4109#endif
4110 break;
4111 case XPATH_NODESET:
4112 case XPATH_XSLT_TREE:
4113 if ((arg2->nodesetval == NULL) ||
4114 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4115 else
4116 ret = 1;
4117 break;
4118 case XPATH_BOOLEAN:
4119#ifdef DEBUG_EXPR
4120 xmlGenericError(xmlGenericErrorContext,
4121 "Equal: %d boolean %d \n",
4122 arg1->boolval, arg2->boolval);
4123#endif
4124 ret = (arg1->boolval == arg2->boolval);
4125 break;
4126 case XPATH_NUMBER:
4127 if (arg2->floatval) ret = 1;
4128 else ret = 0;
4129 ret = (arg1->boolval == ret);
4130 break;
4131 case XPATH_STRING:
4132 if ((arg2->stringval == NULL) ||
4133 (arg2->stringval[0] == 0)) ret = 0;
4134 else
4135 ret = 1;
4136 ret = (arg1->boolval == ret);
4137 break;
4138 case XPATH_USERS:
4139 case XPATH_POINT:
4140 case XPATH_RANGE:
4141 case XPATH_LOCATIONSET:
4142 TODO
4143 break;
4144 }
4145 break;
4146 case XPATH_NUMBER:
4147 switch (arg2->type) {
4148 case XPATH_UNDEFINED:
4149#ifdef DEBUG_EXPR
4150 xmlGenericError(xmlGenericErrorContext,
4151 "Equal: undefined\n");
4152#endif
4153 break;
4154 case XPATH_NODESET:
4155 case XPATH_XSLT_TREE:
4156 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4157 break;
4158 case XPATH_BOOLEAN:
4159 if (arg1->floatval) ret = 1;
4160 else ret = 0;
4161 ret = (arg2->boolval == ret);
4162 break;
4163 case XPATH_STRING:
4164 valuePush(ctxt, arg2);
4165 xmlXPathNumberFunction(ctxt, 1);
4166 arg2 = valuePop(ctxt);
4167 /* no break on purpose */
4168 case XPATH_NUMBER:
4169 ret = (arg1->floatval == arg2->floatval);
4170 break;
4171 case XPATH_USERS:
4172 case XPATH_POINT:
4173 case XPATH_RANGE:
4174 case XPATH_LOCATIONSET:
4175 TODO
4176 break;
4177 }
4178 break;
4179 case XPATH_STRING:
4180 switch (arg2->type) {
4181 case XPATH_UNDEFINED:
4182#ifdef DEBUG_EXPR
4183 xmlGenericError(xmlGenericErrorContext,
4184 "Equal: undefined\n");
4185#endif
4186 break;
4187 case XPATH_NODESET:
4188 case XPATH_XSLT_TREE:
4189 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4190 break;
4191 case XPATH_BOOLEAN:
4192 if ((arg1->stringval == NULL) ||
4193 (arg1->stringval[0] == 0)) ret = 0;
4194 else
4195 ret = 1;
4196 ret = (arg2->boolval == ret);
4197 break;
4198 case XPATH_STRING:
4199 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4200 break;
4201 case XPATH_NUMBER:
4202 valuePush(ctxt, arg1);
4203 xmlXPathNumberFunction(ctxt, 1);
4204 arg1 = valuePop(ctxt);
4205 ret = (arg1->floatval == arg2->floatval);
4206 break;
4207 case XPATH_USERS:
4208 case XPATH_POINT:
4209 case XPATH_RANGE:
4210 case XPATH_LOCATIONSET:
4211 TODO
4212 break;
4213 }
4214 break;
4215 case XPATH_USERS:
4216 case XPATH_POINT:
4217 case XPATH_RANGE:
4218 case XPATH_LOCATIONSET:
4219 TODO
4220 break;
4221 }
4222 xmlXPathFreeObject(arg1);
4223 xmlXPathFreeObject(arg2);
4224 return(ret);
4225}
4226
4227
4228/**
4229 * xmlXPathCompareValues:
4230 * @ctxt: the XPath Parser context
4231 * @inf: less than (1) or greater than (0)
4232 * @strict: is the comparison strict
4233 *
4234 * Implement the compare operation on XPath objects:
4235 * @arg1 < @arg2 (1, 1, ...
4236 * @arg1 <= @arg2 (1, 0, ...
4237 * @arg1 > @arg2 (0, 1, ...
4238 * @arg1 >= @arg2 (0, 0, ...
4239 *
4240 * When neither object to be compared is a node-set and the operator is
4241 * <=, <, >=, >, then the objects are compared by converted both objects
4242 * to numbers and comparing the numbers according to IEEE 754. The <
4243 * comparison will be true if and only if the first number is less than the
4244 * second number. The <= comparison will be true if and only if the first
4245 * number is less than or equal to the second number. The > comparison
4246 * will be true if and only if the first number is greater than the second
4247 * number. The >= comparison will be true if and only if the first number
4248 * is greater than or equal to the second number.
4249 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004250 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004251 */
4252int
4253xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4254 int ret = 0;
4255 xmlXPathObjectPtr arg1, arg2;
4256
4257 arg2 = valuePop(ctxt);
4258 if (arg2 == NULL) {
4259 XP_ERROR0(XPATH_INVALID_OPERAND);
4260 }
4261
4262 arg1 = valuePop(ctxt);
4263 if (arg1 == NULL) {
4264 xmlXPathFreeObject(arg2);
4265 XP_ERROR0(XPATH_INVALID_OPERAND);
4266 }
4267
4268 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4269 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004270 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004271 } else {
4272 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004273 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4274 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004275 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004276 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4277 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004278 }
4279 }
4280 return(ret);
4281 }
4282
4283 if (arg1->type != XPATH_NUMBER) {
4284 valuePush(ctxt, arg1);
4285 xmlXPathNumberFunction(ctxt, 1);
4286 arg1 = valuePop(ctxt);
4287 }
4288 if (arg1->type != XPATH_NUMBER) {
4289 xmlXPathFreeObject(arg1);
4290 xmlXPathFreeObject(arg2);
4291 XP_ERROR0(XPATH_INVALID_OPERAND);
4292 }
4293 if (arg2->type != XPATH_NUMBER) {
4294 valuePush(ctxt, arg2);
4295 xmlXPathNumberFunction(ctxt, 1);
4296 arg2 = valuePop(ctxt);
4297 }
4298 if (arg2->type != XPATH_NUMBER) {
4299 xmlXPathFreeObject(arg1);
4300 xmlXPathFreeObject(arg2);
4301 XP_ERROR0(XPATH_INVALID_OPERAND);
4302 }
4303 /*
4304 * Add tests for infinity and nan
4305 * => feedback on 3.4 for Inf and NaN
4306 */
4307 if (inf && strict)
4308 ret = (arg1->floatval < arg2->floatval);
4309 else if (inf && !strict)
4310 ret = (arg1->floatval <= arg2->floatval);
4311 else if (!inf && strict)
4312 ret = (arg1->floatval > arg2->floatval);
4313 else if (!inf && !strict)
4314 ret = (arg1->floatval >= arg2->floatval);
4315 xmlXPathFreeObject(arg1);
4316 xmlXPathFreeObject(arg2);
4317 return(ret);
4318}
4319
4320/**
4321 * xmlXPathValueFlipSign:
4322 * @ctxt: the XPath Parser context
4323 *
4324 * Implement the unary - operation on an XPath object
4325 * The numeric operators convert their operands to numbers as if
4326 * by calling the number function.
4327 */
4328void
4329xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004330 CAST_TO_NUMBER;
4331 CHECK_TYPE(XPATH_NUMBER);
4332 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004333}
4334
4335/**
4336 * xmlXPathAddValues:
4337 * @ctxt: the XPath Parser context
4338 *
4339 * Implement the add operation on XPath objects:
4340 * The numeric operators convert their operands to numbers as if
4341 * by calling the number function.
4342 */
4343void
4344xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4345 xmlXPathObjectPtr arg;
4346 double val;
4347
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004348 arg = valuePop(ctxt);
4349 if (arg == NULL)
4350 XP_ERROR(XPATH_INVALID_OPERAND);
4351 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004352 xmlXPathFreeObject(arg);
4353
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004354 CAST_TO_NUMBER;
4355 CHECK_TYPE(XPATH_NUMBER);
4356 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004357}
4358
4359/**
4360 * xmlXPathSubValues:
4361 * @ctxt: the XPath Parser context
4362 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004363 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004364 * The numeric operators convert their operands to numbers as if
4365 * by calling the number function.
4366 */
4367void
4368xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4369 xmlXPathObjectPtr arg;
4370 double val;
4371
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004372 arg = valuePop(ctxt);
4373 if (arg == NULL)
4374 XP_ERROR(XPATH_INVALID_OPERAND);
4375 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004376 xmlXPathFreeObject(arg);
4377
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004378 CAST_TO_NUMBER;
4379 CHECK_TYPE(XPATH_NUMBER);
4380 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004381}
4382
4383/**
4384 * xmlXPathMultValues:
4385 * @ctxt: the XPath Parser context
4386 *
4387 * Implement the multiply operation on XPath objects:
4388 * The numeric operators convert their operands to numbers as if
4389 * by calling the number function.
4390 */
4391void
4392xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4393 xmlXPathObjectPtr arg;
4394 double val;
4395
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004396 arg = valuePop(ctxt);
4397 if (arg == NULL)
4398 XP_ERROR(XPATH_INVALID_OPERAND);
4399 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004400 xmlXPathFreeObject(arg);
4401
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004402 CAST_TO_NUMBER;
4403 CHECK_TYPE(XPATH_NUMBER);
4404 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004405}
4406
4407/**
4408 * xmlXPathDivValues:
4409 * @ctxt: the XPath Parser context
4410 *
4411 * Implement the div operation on XPath objects @arg1 / @arg2:
4412 * The numeric operators convert their operands to numbers as if
4413 * by calling the number function.
4414 */
4415void
4416xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4417 xmlXPathObjectPtr arg;
4418 double val;
4419
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004420 arg = valuePop(ctxt);
4421 if (arg == NULL)
4422 XP_ERROR(XPATH_INVALID_OPERAND);
4423 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004424 xmlXPathFreeObject(arg);
4425
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004426 CAST_TO_NUMBER;
4427 CHECK_TYPE(XPATH_NUMBER);
4428 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004429}
4430
4431/**
4432 * xmlXPathModValues:
4433 * @ctxt: the XPath Parser context
4434 *
4435 * Implement the mod operation on XPath objects: @arg1 / @arg2
4436 * The numeric operators convert their operands to numbers as if
4437 * by calling the number function.
4438 */
4439void
4440xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4441 xmlXPathObjectPtr arg;
4442 int arg1, arg2;
4443
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004444 arg = valuePop(ctxt);
4445 if (arg == NULL)
4446 XP_ERROR(XPATH_INVALID_OPERAND);
4447 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004448 xmlXPathFreeObject(arg);
4449
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004450 CAST_TO_NUMBER;
4451 CHECK_TYPE(XPATH_NUMBER);
4452 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004453 if (arg2 == 0)
4454 ctxt->value->floatval = xmlXPathNAN;
4455 else
4456 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004457}
4458
4459/************************************************************************
4460 * *
4461 * The traversal functions *
4462 * *
4463 ************************************************************************/
4464
Owen Taylor3473f882001-02-23 17:55:21 +00004465/*
4466 * A traversal function enumerates nodes along an axis.
4467 * Initially it must be called with NULL, and it indicates
4468 * termination on the axis by returning NULL.
4469 */
4470typedef xmlNodePtr (*xmlXPathTraversalFunction)
4471 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4472
4473/**
4474 * xmlXPathNextSelf:
4475 * @ctxt: the XPath Parser context
4476 * @cur: the current node in the traversal
4477 *
4478 * Traversal function for the "self" direction
4479 * The self axis contains just the context node itself
4480 *
4481 * Returns the next element following that axis
4482 */
4483xmlNodePtr
4484xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4485 if (cur == NULL)
4486 return(ctxt->context->node);
4487 return(NULL);
4488}
4489
4490/**
4491 * xmlXPathNextChild:
4492 * @ctxt: the XPath Parser context
4493 * @cur: the current node in the traversal
4494 *
4495 * Traversal function for the "child" direction
4496 * The child axis contains the children of the context node in document order.
4497 *
4498 * Returns the next element following that axis
4499 */
4500xmlNodePtr
4501xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4502 if (cur == NULL) {
4503 if (ctxt->context->node == NULL) return(NULL);
4504 switch (ctxt->context->node->type) {
4505 case XML_ELEMENT_NODE:
4506 case XML_TEXT_NODE:
4507 case XML_CDATA_SECTION_NODE:
4508 case XML_ENTITY_REF_NODE:
4509 case XML_ENTITY_NODE:
4510 case XML_PI_NODE:
4511 case XML_COMMENT_NODE:
4512 case XML_NOTATION_NODE:
4513 case XML_DTD_NODE:
4514 return(ctxt->context->node->children);
4515 case XML_DOCUMENT_NODE:
4516 case XML_DOCUMENT_TYPE_NODE:
4517 case XML_DOCUMENT_FRAG_NODE:
4518 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004519#ifdef LIBXML_DOCB_ENABLED
4520 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004521#endif
4522 return(((xmlDocPtr) ctxt->context->node)->children);
4523 case XML_ELEMENT_DECL:
4524 case XML_ATTRIBUTE_DECL:
4525 case XML_ENTITY_DECL:
4526 case XML_ATTRIBUTE_NODE:
4527 case XML_NAMESPACE_DECL:
4528 case XML_XINCLUDE_START:
4529 case XML_XINCLUDE_END:
4530 return(NULL);
4531 }
4532 return(NULL);
4533 }
4534 if ((cur->type == XML_DOCUMENT_NODE) ||
4535 (cur->type == XML_HTML_DOCUMENT_NODE))
4536 return(NULL);
4537 return(cur->next);
4538}
4539
4540/**
4541 * xmlXPathNextDescendant:
4542 * @ctxt: the XPath Parser context
4543 * @cur: the current node in the traversal
4544 *
4545 * Traversal function for the "descendant" direction
4546 * the descendant axis contains the descendants of the context node in document
4547 * order; a descendant is a child or a child of a child and so on.
4548 *
4549 * Returns the next element following that axis
4550 */
4551xmlNodePtr
4552xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4553 if (cur == NULL) {
4554 if (ctxt->context->node == NULL)
4555 return(NULL);
4556 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4557 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4558 return(NULL);
4559
4560 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4561 return(ctxt->context->doc->children);
4562 return(ctxt->context->node->children);
4563 }
4564
Daniel Veillard567e1b42001-08-01 15:53:47 +00004565 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004566 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004567 return(cur->children);
4568 }
4569
4570 if (cur == ctxt->context->node) return(NULL);
4571
Owen Taylor3473f882001-02-23 17:55:21 +00004572 if (cur->next != NULL) return(cur->next);
4573
4574 do {
4575 cur = cur->parent;
4576 if (cur == NULL) return(NULL);
4577 if (cur == ctxt->context->node) return(NULL);
4578 if (cur->next != NULL) {
4579 cur = cur->next;
4580 return(cur);
4581 }
4582 } while (cur != NULL);
4583 return(cur);
4584}
4585
4586/**
4587 * xmlXPathNextDescendantOrSelf:
4588 * @ctxt: the XPath Parser context
4589 * @cur: the current node in the traversal
4590 *
4591 * Traversal function for the "descendant-or-self" direction
4592 * the descendant-or-self axis contains the context node and the descendants
4593 * of the context node in document order; thus the context node is the first
4594 * node on the axis, and the first child of the context node is the second node
4595 * on the axis
4596 *
4597 * Returns the next element following that axis
4598 */
4599xmlNodePtr
4600xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4601 if (cur == NULL) {
4602 if (ctxt->context->node == NULL)
4603 return(NULL);
4604 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4605 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4606 return(NULL);
4607 return(ctxt->context->node);
4608 }
4609
4610 return(xmlXPathNextDescendant(ctxt, cur));
4611}
4612
4613/**
4614 * xmlXPathNextParent:
4615 * @ctxt: the XPath Parser context
4616 * @cur: the current node in the traversal
4617 *
4618 * Traversal function for the "parent" direction
4619 * The parent axis contains the parent of the context node, if there is one.
4620 *
4621 * Returns the next element following that axis
4622 */
4623xmlNodePtr
4624xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4625 /*
4626 * the parent of an attribute or namespace node is the element
4627 * to which the attribute or namespace node is attached
4628 * Namespace handling !!!
4629 */
4630 if (cur == NULL) {
4631 if (ctxt->context->node == NULL) return(NULL);
4632 switch (ctxt->context->node->type) {
4633 case XML_ELEMENT_NODE:
4634 case XML_TEXT_NODE:
4635 case XML_CDATA_SECTION_NODE:
4636 case XML_ENTITY_REF_NODE:
4637 case XML_ENTITY_NODE:
4638 case XML_PI_NODE:
4639 case XML_COMMENT_NODE:
4640 case XML_NOTATION_NODE:
4641 case XML_DTD_NODE:
4642 case XML_ELEMENT_DECL:
4643 case XML_ATTRIBUTE_DECL:
4644 case XML_XINCLUDE_START:
4645 case XML_XINCLUDE_END:
4646 case XML_ENTITY_DECL:
4647 if (ctxt->context->node->parent == NULL)
4648 return((xmlNodePtr) ctxt->context->doc);
4649 return(ctxt->context->node->parent);
4650 case XML_ATTRIBUTE_NODE: {
4651 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4652
4653 return(att->parent);
4654 }
4655 case XML_DOCUMENT_NODE:
4656 case XML_DOCUMENT_TYPE_NODE:
4657 case XML_DOCUMENT_FRAG_NODE:
4658 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004659#ifdef LIBXML_DOCB_ENABLED
4660 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004661#endif
4662 return(NULL);
4663 case XML_NAMESPACE_DECL:
4664 /*
4665 * TODO !!! may require extending struct _xmlNs with
4666 * parent field
4667 * C.f. Infoset case...
4668 */
4669 return(NULL);
4670 }
4671 }
4672 return(NULL);
4673}
4674
4675/**
4676 * xmlXPathNextAncestor:
4677 * @ctxt: the XPath Parser context
4678 * @cur: the current node in the traversal
4679 *
4680 * Traversal function for the "ancestor" direction
4681 * the ancestor axis contains the ancestors of the context node; the ancestors
4682 * of the context node consist of the parent of context node and the parent's
4683 * parent and so on; the nodes are ordered in reverse document order; thus the
4684 * parent is the first node on the axis, and the parent's parent is the second
4685 * node on the axis
4686 *
4687 * Returns the next element following that axis
4688 */
4689xmlNodePtr
4690xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4691 /*
4692 * the parent of an attribute or namespace node is the element
4693 * to which the attribute or namespace node is attached
4694 * !!!!!!!!!!!!!
4695 */
4696 if (cur == NULL) {
4697 if (ctxt->context->node == NULL) return(NULL);
4698 switch (ctxt->context->node->type) {
4699 case XML_ELEMENT_NODE:
4700 case XML_TEXT_NODE:
4701 case XML_CDATA_SECTION_NODE:
4702 case XML_ENTITY_REF_NODE:
4703 case XML_ENTITY_NODE:
4704 case XML_PI_NODE:
4705 case XML_COMMENT_NODE:
4706 case XML_DTD_NODE:
4707 case XML_ELEMENT_DECL:
4708 case XML_ATTRIBUTE_DECL:
4709 case XML_ENTITY_DECL:
4710 case XML_NOTATION_NODE:
4711 case XML_XINCLUDE_START:
4712 case XML_XINCLUDE_END:
4713 if (ctxt->context->node->parent == NULL)
4714 return((xmlNodePtr) ctxt->context->doc);
4715 return(ctxt->context->node->parent);
4716 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004717 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004718
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004719 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004720 }
4721 case XML_DOCUMENT_NODE:
4722 case XML_DOCUMENT_TYPE_NODE:
4723 case XML_DOCUMENT_FRAG_NODE:
4724 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004725#ifdef LIBXML_DOCB_ENABLED
4726 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004727#endif
4728 return(NULL);
4729 case XML_NAMESPACE_DECL:
4730 /*
4731 * TODO !!! may require extending struct _xmlNs with
4732 * parent field
4733 * C.f. Infoset case...
4734 */
4735 return(NULL);
4736 }
4737 return(NULL);
4738 }
4739 if (cur == ctxt->context->doc->children)
4740 return((xmlNodePtr) ctxt->context->doc);
4741 if (cur == (xmlNodePtr) ctxt->context->doc)
4742 return(NULL);
4743 switch (cur->type) {
4744 case XML_ELEMENT_NODE:
4745 case XML_TEXT_NODE:
4746 case XML_CDATA_SECTION_NODE:
4747 case XML_ENTITY_REF_NODE:
4748 case XML_ENTITY_NODE:
4749 case XML_PI_NODE:
4750 case XML_COMMENT_NODE:
4751 case XML_NOTATION_NODE:
4752 case XML_DTD_NODE:
4753 case XML_ELEMENT_DECL:
4754 case XML_ATTRIBUTE_DECL:
4755 case XML_ENTITY_DECL:
4756 case XML_XINCLUDE_START:
4757 case XML_XINCLUDE_END:
4758 return(cur->parent);
4759 case XML_ATTRIBUTE_NODE: {
4760 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4761
4762 return(att->parent);
4763 }
4764 case XML_DOCUMENT_NODE:
4765 case XML_DOCUMENT_TYPE_NODE:
4766 case XML_DOCUMENT_FRAG_NODE:
4767 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004768#ifdef LIBXML_DOCB_ENABLED
4769 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004770#endif
4771 return(NULL);
4772 case XML_NAMESPACE_DECL:
4773 /*
4774 * TODO !!! may require extending struct _xmlNs with
4775 * parent field
4776 * C.f. Infoset case...
4777 */
4778 return(NULL);
4779 }
4780 return(NULL);
4781}
4782
4783/**
4784 * xmlXPathNextAncestorOrSelf:
4785 * @ctxt: the XPath Parser context
4786 * @cur: the current node in the traversal
4787 *
4788 * Traversal function for the "ancestor-or-self" direction
4789 * he ancestor-or-self axis contains the context node and ancestors of
4790 * the context node in reverse document order; thus the context node is
4791 * the first node on the axis, and the context node's parent the second;
4792 * parent here is defined the same as with the parent axis.
4793 *
4794 * Returns the next element following that axis
4795 */
4796xmlNodePtr
4797xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4798 if (cur == NULL)
4799 return(ctxt->context->node);
4800 return(xmlXPathNextAncestor(ctxt, cur));
4801}
4802
4803/**
4804 * xmlXPathNextFollowingSibling:
4805 * @ctxt: the XPath Parser context
4806 * @cur: the current node in the traversal
4807 *
4808 * Traversal function for the "following-sibling" direction
4809 * The following-sibling axis contains the following siblings of the context
4810 * node in document order.
4811 *
4812 * Returns the next element following that axis
4813 */
4814xmlNodePtr
4815xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4816 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4817 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4818 return(NULL);
4819 if (cur == (xmlNodePtr) ctxt->context->doc)
4820 return(NULL);
4821 if (cur == NULL)
4822 return(ctxt->context->node->next);
4823 return(cur->next);
4824}
4825
4826/**
4827 * xmlXPathNextPrecedingSibling:
4828 * @ctxt: the XPath Parser context
4829 * @cur: the current node in the traversal
4830 *
4831 * Traversal function for the "preceding-sibling" direction
4832 * The preceding-sibling axis contains the preceding siblings of the context
4833 * node in reverse document order; the first preceding sibling is first on the
4834 * axis; the sibling preceding that node is the second on the axis and so on.
4835 *
4836 * Returns the next element following that axis
4837 */
4838xmlNodePtr
4839xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4840 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4841 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4842 return(NULL);
4843 if (cur == (xmlNodePtr) ctxt->context->doc)
4844 return(NULL);
4845 if (cur == NULL)
4846 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004847 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4848 cur = cur->prev;
4849 if (cur == NULL)
4850 return(ctxt->context->node->prev);
4851 }
Owen Taylor3473f882001-02-23 17:55:21 +00004852 return(cur->prev);
4853}
4854
4855/**
4856 * xmlXPathNextFollowing:
4857 * @ctxt: the XPath Parser context
4858 * @cur: the current node in the traversal
4859 *
4860 * Traversal function for the "following" direction
4861 * The following axis contains all nodes in the same document as the context
4862 * node that are after the context node in document order, excluding any
4863 * descendants and excluding attribute nodes and namespace nodes; the nodes
4864 * are ordered in document order
4865 *
4866 * Returns the next element following that axis
4867 */
4868xmlNodePtr
4869xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4870 if (cur != NULL && cur->children != NULL)
4871 return cur->children ;
4872 if (cur == NULL) cur = ctxt->context->node;
4873 if (cur == NULL) return(NULL) ; /* ERROR */
4874 if (cur->next != NULL) return(cur->next) ;
4875 do {
4876 cur = cur->parent;
4877 if (cur == NULL) return(NULL);
4878 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4879 if (cur->next != NULL) return(cur->next);
4880 } while (cur != NULL);
4881 return(cur);
4882}
4883
4884/*
4885 * xmlXPathIsAncestor:
4886 * @ancestor: the ancestor node
4887 * @node: the current node
4888 *
4889 * Check that @ancestor is a @node's ancestor
4890 *
4891 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4892 */
4893static int
4894xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4895 if ((ancestor == NULL) || (node == NULL)) return(0);
4896 /* nodes need to be in the same document */
4897 if (ancestor->doc != node->doc) return(0);
4898 /* avoid searching if ancestor or node is the root node */
4899 if (ancestor == (xmlNodePtr) node->doc) return(1);
4900 if (node == (xmlNodePtr) ancestor->doc) return(0);
4901 while (node->parent != NULL) {
4902 if (node->parent == ancestor)
4903 return(1);
4904 node = node->parent;
4905 }
4906 return(0);
4907}
4908
4909/**
4910 * xmlXPathNextPreceding:
4911 * @ctxt: the XPath Parser context
4912 * @cur: the current node in the traversal
4913 *
4914 * Traversal function for the "preceding" direction
4915 * the preceding axis contains all nodes in the same document as the context
4916 * node that are before the context node in document order, excluding any
4917 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4918 * ordered in reverse document order
4919 *
4920 * Returns the next element following that axis
4921 */
4922xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004923xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4924{
Owen Taylor3473f882001-02-23 17:55:21 +00004925 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004926 cur = ctxt->context->node;
4927 if (cur == NULL)
4928 return (NULL);
4929 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4930 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004931 do {
4932 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004933 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4934 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004935 }
4936
4937 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004938 if (cur == NULL)
4939 return (NULL);
4940 if (cur == ctxt->context->doc->children)
4941 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004942 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004943 return (cur);
4944}
4945
4946/**
4947 * xmlXPathNextPrecedingInternal:
4948 * @ctxt: the XPath Parser context
4949 * @cur: the current node in the traversal
4950 *
4951 * Traversal function for the "preceding" direction
4952 * the preceding axis contains all nodes in the same document as the context
4953 * node that are before the context node in document order, excluding any
4954 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4955 * ordered in reverse document order
4956 * This is a faster implementation but internal only since it requires a
4957 * state kept in the parser context: ctxt->ancestor.
4958 *
4959 * Returns the next element following that axis
4960 */
4961static xmlNodePtr
4962xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4963 xmlNodePtr cur)
4964{
4965 if (cur == NULL) {
4966 cur = ctxt->context->node;
4967 if (cur == NULL)
4968 return (NULL);
4969 ctxt->ancestor = cur->parent;
4970 }
4971 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4972 cur = cur->prev;
4973 while (cur->prev == NULL) {
4974 cur = cur->parent;
4975 if (cur == NULL)
4976 return (NULL);
4977 if (cur == ctxt->context->doc->children)
4978 return (NULL);
4979 if (cur != ctxt->ancestor)
4980 return (cur);
4981 ctxt->ancestor = cur->parent;
4982 }
4983 cur = cur->prev;
4984 while (cur->last != NULL)
4985 cur = cur->last;
4986 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004987}
4988
4989/**
4990 * xmlXPathNextNamespace:
4991 * @ctxt: the XPath Parser context
4992 * @cur: the current attribute in the traversal
4993 *
4994 * Traversal function for the "namespace" direction
4995 * the namespace axis contains the namespace nodes of the context node;
4996 * the order of nodes on this axis is implementation-defined; the axis will
4997 * be empty unless the context node is an element
4998 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00004999 * We keep the XML namespace node at the end of the list.
5000 *
Owen Taylor3473f882001-02-23 17:55:21 +00005001 * Returns the next element following that axis
5002 */
5003xmlNodePtr
5004xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005005 xmlNodePtr ret;
5006
Owen Taylor3473f882001-02-23 17:55:21 +00005007 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005008 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5009 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005010 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5011 if (ctxt->context->tmpNsList != NULL)
5012 xmlFree(ctxt->context->tmpNsList);
5013 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005014 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005015 if (ctxt->context->tmpNsList == NULL) return(NULL);
5016 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005017 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005018 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5019 if (ret == NULL) {
5020 xmlFree(ctxt->context->tmpNsList);
5021 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005022 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005023 }
5024 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005025}
5026
5027/**
5028 * xmlXPathNextAttribute:
5029 * @ctxt: the XPath Parser context
5030 * @cur: the current attribute in the traversal
5031 *
5032 * Traversal function for the "attribute" direction
5033 * TODO: support DTD inherited default attributes
5034 *
5035 * Returns the next element following that axis
5036 */
5037xmlNodePtr
5038xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005039 if (ctxt->context->node == NULL)
5040 return(NULL);
5041 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5042 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005043 if (cur == NULL) {
5044 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5045 return(NULL);
5046 return((xmlNodePtr)ctxt->context->node->properties);
5047 }
5048 return((xmlNodePtr)cur->next);
5049}
5050
5051/************************************************************************
5052 * *
5053 * NodeTest Functions *
5054 * *
5055 ************************************************************************/
5056
Owen Taylor3473f882001-02-23 17:55:21 +00005057#define IS_FUNCTION 200
5058
Owen Taylor3473f882001-02-23 17:55:21 +00005059
5060/************************************************************************
5061 * *
5062 * Implicit tree core function library *
5063 * *
5064 ************************************************************************/
5065
5066/**
5067 * xmlXPathRoot:
5068 * @ctxt: the XPath Parser context
5069 *
5070 * Initialize the context to the root of the document
5071 */
5072void
5073xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5074 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5075 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5076}
5077
5078/************************************************************************
5079 * *
5080 * The explicit core function library *
5081 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5082 * *
5083 ************************************************************************/
5084
5085
5086/**
5087 * xmlXPathLastFunction:
5088 * @ctxt: the XPath Parser context
5089 * @nargs: the number of arguments
5090 *
5091 * Implement the last() XPath function
5092 * number last()
5093 * The last function returns the number of nodes in the context node list.
5094 */
5095void
5096xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5097 CHECK_ARITY(0);
5098 if (ctxt->context->contextSize >= 0) {
5099 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5100#ifdef DEBUG_EXPR
5101 xmlGenericError(xmlGenericErrorContext,
5102 "last() : %d\n", ctxt->context->contextSize);
5103#endif
5104 } else {
5105 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5106 }
5107}
5108
5109/**
5110 * xmlXPathPositionFunction:
5111 * @ctxt: the XPath Parser context
5112 * @nargs: the number of arguments
5113 *
5114 * Implement the position() XPath function
5115 * number position()
5116 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005117 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005118 * will be equal to last().
5119 */
5120void
5121xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5122 CHECK_ARITY(0);
5123 if (ctxt->context->proximityPosition >= 0) {
5124 valuePush(ctxt,
5125 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5126#ifdef DEBUG_EXPR
5127 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5128 ctxt->context->proximityPosition);
5129#endif
5130 } else {
5131 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5132 }
5133}
5134
5135/**
5136 * xmlXPathCountFunction:
5137 * @ctxt: the XPath Parser context
5138 * @nargs: the number of arguments
5139 *
5140 * Implement the count() XPath function
5141 * number count(node-set)
5142 */
5143void
5144xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5145 xmlXPathObjectPtr cur;
5146
5147 CHECK_ARITY(1);
5148 if ((ctxt->value == NULL) ||
5149 ((ctxt->value->type != XPATH_NODESET) &&
5150 (ctxt->value->type != XPATH_XSLT_TREE)))
5151 XP_ERROR(XPATH_INVALID_TYPE);
5152 cur = valuePop(ctxt);
5153
Daniel Veillard911f49a2001-04-07 15:39:35 +00005154 if ((cur == NULL) || (cur->nodesetval == NULL))
5155 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005156 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005157 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005158 } else {
5159 if ((cur->nodesetval->nodeNr != 1) ||
5160 (cur->nodesetval->nodeTab == NULL)) {
5161 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5162 } else {
5163 xmlNodePtr tmp;
5164 int i = 0;
5165
5166 tmp = cur->nodesetval->nodeTab[0];
5167 if (tmp != NULL) {
5168 tmp = tmp->children;
5169 while (tmp != NULL) {
5170 tmp = tmp->next;
5171 i++;
5172 }
5173 }
5174 valuePush(ctxt, xmlXPathNewFloat((double) i));
5175 }
5176 }
Owen Taylor3473f882001-02-23 17:55:21 +00005177 xmlXPathFreeObject(cur);
5178}
5179
5180/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005181 * xmlXPathGetElementsByIds:
5182 * @doc: the document
5183 * @ids: a whitespace separated list of IDs
5184 *
5185 * Selects elements by their unique ID.
5186 *
5187 * Returns a node-set of selected elements.
5188 */
5189static xmlNodeSetPtr
5190xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5191 xmlNodeSetPtr ret;
5192 const xmlChar *cur = ids;
5193 xmlChar *ID;
5194 xmlAttrPtr attr;
5195 xmlNodePtr elem = NULL;
5196
5197 ret = xmlXPathNodeSetCreate(NULL);
5198
5199 while (IS_BLANK(*cur)) cur++;
5200 while (*cur != 0) {
5201 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5202 (*cur == '.') || (*cur == '-') ||
5203 (*cur == '_') || (*cur == ':') ||
5204 (IS_COMBINING(*cur)) ||
5205 (IS_EXTENDER(*cur)))
5206 cur++;
5207
5208 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5209
5210 ID = xmlStrndup(ids, cur - ids);
5211 attr = xmlGetID(doc, ID);
5212 if (attr != NULL) {
5213 elem = attr->parent;
5214 xmlXPathNodeSetAdd(ret, elem);
5215 }
5216 if (ID != NULL)
5217 xmlFree(ID);
5218
5219 while (IS_BLANK(*cur)) cur++;
5220 ids = cur;
5221 }
5222 return(ret);
5223}
5224
5225/**
Owen Taylor3473f882001-02-23 17:55:21 +00005226 * xmlXPathIdFunction:
5227 * @ctxt: the XPath Parser context
5228 * @nargs: the number of arguments
5229 *
5230 * Implement the id() XPath function
5231 * node-set id(object)
5232 * The id function selects elements by their unique ID
5233 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5234 * then the result is the union of the result of applying id to the
5235 * string value of each of the nodes in the argument node-set. When the
5236 * argument to id is of any other type, the argument is converted to a
5237 * string as if by a call to the string function; the string is split
5238 * into a whitespace-separated list of tokens (whitespace is any sequence
5239 * of characters matching the production S); the result is a node-set
5240 * containing the elements in the same document as the context node that
5241 * have a unique ID equal to any of the tokens in the list.
5242 */
5243void
5244xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005245 xmlChar *tokens;
5246 xmlNodeSetPtr ret;
5247 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005248
5249 CHECK_ARITY(1);
5250 obj = valuePop(ctxt);
5251 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5252 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005253 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005254 int i;
5255
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005256 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005257
Daniel Veillard911f49a2001-04-07 15:39:35 +00005258 if (obj->nodesetval != NULL) {
5259 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005260 tokens =
5261 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5262 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5263 ret = xmlXPathNodeSetMerge(ret, ns);
5264 xmlXPathFreeNodeSet(ns);
5265 if (tokens != NULL)
5266 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005267 }
Owen Taylor3473f882001-02-23 17:55:21 +00005268 }
5269
5270 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005271 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005272 return;
5273 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005274 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005275
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005276 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5277 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005278
Owen Taylor3473f882001-02-23 17:55:21 +00005279 xmlXPathFreeObject(obj);
5280 return;
5281}
5282
5283/**
5284 * xmlXPathLocalNameFunction:
5285 * @ctxt: the XPath Parser context
5286 * @nargs: the number of arguments
5287 *
5288 * Implement the local-name() XPath function
5289 * string local-name(node-set?)
5290 * The local-name function returns a string containing the local part
5291 * of the name of the node in the argument node-set that is first in
5292 * document order. If the node-set is empty or the first node has no
5293 * name, an empty string is returned. If the argument is omitted it
5294 * defaults to the context node.
5295 */
5296void
5297xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5298 xmlXPathObjectPtr cur;
5299
5300 if (nargs == 0) {
5301 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5302 nargs = 1;
5303 }
5304
5305 CHECK_ARITY(1);
5306 if ((ctxt->value == NULL) ||
5307 ((ctxt->value->type != XPATH_NODESET) &&
5308 (ctxt->value->type != XPATH_XSLT_TREE)))
5309 XP_ERROR(XPATH_INVALID_TYPE);
5310 cur = valuePop(ctxt);
5311
Daniel Veillard911f49a2001-04-07 15:39:35 +00005312 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005313 valuePush(ctxt, xmlXPathNewCString(""));
5314 } else {
5315 int i = 0; /* Should be first in document order !!!!! */
5316 switch (cur->nodesetval->nodeTab[i]->type) {
5317 case XML_ELEMENT_NODE:
5318 case XML_ATTRIBUTE_NODE:
5319 case XML_PI_NODE:
5320 valuePush(ctxt,
5321 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5322 break;
5323 case XML_NAMESPACE_DECL:
5324 valuePush(ctxt, xmlXPathNewString(
5325 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5326 break;
5327 default:
5328 valuePush(ctxt, xmlXPathNewCString(""));
5329 }
5330 }
5331 xmlXPathFreeObject(cur);
5332}
5333
5334/**
5335 * xmlXPathNamespaceURIFunction:
5336 * @ctxt: the XPath Parser context
5337 * @nargs: the number of arguments
5338 *
5339 * Implement the namespace-uri() XPath function
5340 * string namespace-uri(node-set?)
5341 * The namespace-uri function returns a string containing the
5342 * namespace URI of the expanded name of the node in the argument
5343 * node-set that is first in document order. If the node-set is empty,
5344 * the first node has no name, or the expanded name has no namespace
5345 * URI, an empty string is returned. If the argument is omitted it
5346 * defaults to the context node.
5347 */
5348void
5349xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5350 xmlXPathObjectPtr cur;
5351
5352 if (nargs == 0) {
5353 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5354 nargs = 1;
5355 }
5356 CHECK_ARITY(1);
5357 if ((ctxt->value == NULL) ||
5358 ((ctxt->value->type != XPATH_NODESET) &&
5359 (ctxt->value->type != XPATH_XSLT_TREE)))
5360 XP_ERROR(XPATH_INVALID_TYPE);
5361 cur = valuePop(ctxt);
5362
Daniel Veillard911f49a2001-04-07 15:39:35 +00005363 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005364 valuePush(ctxt, xmlXPathNewCString(""));
5365 } else {
5366 int i = 0; /* Should be first in document order !!!!! */
5367 switch (cur->nodesetval->nodeTab[i]->type) {
5368 case XML_ELEMENT_NODE:
5369 case XML_ATTRIBUTE_NODE:
5370 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5371 valuePush(ctxt, xmlXPathNewCString(""));
5372 else
5373 valuePush(ctxt, xmlXPathNewString(
5374 cur->nodesetval->nodeTab[i]->ns->href));
5375 break;
5376 default:
5377 valuePush(ctxt, xmlXPathNewCString(""));
5378 }
5379 }
5380 xmlXPathFreeObject(cur);
5381}
5382
5383/**
5384 * xmlXPathNameFunction:
5385 * @ctxt: the XPath Parser context
5386 * @nargs: the number of arguments
5387 *
5388 * Implement the name() XPath function
5389 * string name(node-set?)
5390 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005391 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005392 * order. The QName must represent the name with respect to the namespace
5393 * declarations in effect on the node whose name is being represented.
5394 * Typically, this will be the form in which the name occurred in the XML
5395 * source. This need not be the case if there are namespace declarations
5396 * in effect on the node that associate multiple prefixes with the same
5397 * namespace. However, an implementation may include information about
5398 * the original prefix in its representation of nodes; in this case, an
5399 * implementation can ensure that the returned string is always the same
5400 * as the QName used in the XML source. If the argument it omitted it
5401 * defaults to the context node.
5402 * Libxml keep the original prefix so the "real qualified name" used is
5403 * returned.
5404 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005405static void
Daniel Veillard04383752001-07-08 14:27:15 +00005406xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5407{
Owen Taylor3473f882001-02-23 17:55:21 +00005408 xmlXPathObjectPtr cur;
5409
5410 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005411 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5412 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005413 }
5414
5415 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005416 if ((ctxt->value == NULL) ||
5417 ((ctxt->value->type != XPATH_NODESET) &&
5418 (ctxt->value->type != XPATH_XSLT_TREE)))
5419 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005420 cur = valuePop(ctxt);
5421
Daniel Veillard911f49a2001-04-07 15:39:35 +00005422 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005423 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005424 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005425 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005426
Daniel Veillard04383752001-07-08 14:27:15 +00005427 switch (cur->nodesetval->nodeTab[i]->type) {
5428 case XML_ELEMENT_NODE:
5429 case XML_ATTRIBUTE_NODE:
5430 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5431 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5432 valuePush(ctxt,
5433 xmlXPathNewString(cur->nodesetval->
5434 nodeTab[i]->name));
5435
5436 else {
5437 char name[2000];
5438
5439 snprintf(name, sizeof(name), "%s:%s",
5440 (char *) cur->nodesetval->nodeTab[i]->ns->
5441 prefix,
5442 (char *) cur->nodesetval->nodeTab[i]->name);
5443 name[sizeof(name) - 1] = 0;
5444 valuePush(ctxt, xmlXPathNewCString(name));
5445 }
5446 break;
5447 default:
5448 valuePush(ctxt,
5449 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5450 xmlXPathLocalNameFunction(ctxt, 1);
5451 }
Owen Taylor3473f882001-02-23 17:55:21 +00005452 }
5453 xmlXPathFreeObject(cur);
5454}
5455
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005456
5457/**
Owen Taylor3473f882001-02-23 17:55:21 +00005458 * xmlXPathStringFunction:
5459 * @ctxt: the XPath Parser context
5460 * @nargs: the number of arguments
5461 *
5462 * Implement the string() XPath function
5463 * string string(object?)
5464 * he string function converts an object to a string as follows:
5465 * - A node-set is converted to a string by returning the value of
5466 * the node in the node-set that is first in document order.
5467 * If the node-set is empty, an empty string is returned.
5468 * - A number is converted to a string as follows
5469 * + NaN is converted to the string NaN
5470 * + positive zero is converted to the string 0
5471 * + negative zero is converted to the string 0
5472 * + positive infinity is converted to the string Infinity
5473 * + negative infinity is converted to the string -Infinity
5474 * + if the number is an integer, the number is represented in
5475 * decimal form as a Number with no decimal point and no leading
5476 * zeros, preceded by a minus sign (-) if the number is negative
5477 * + otherwise, the number is represented in decimal form as a
5478 * Number including a decimal point with at least one digit
5479 * before the decimal point and at least one digit after the
5480 * decimal point, preceded by a minus sign (-) if the number
5481 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005482 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005483 * before the decimal point; beyond the one required digit
5484 * after the decimal point there must be as many, but only as
5485 * many, more digits as are needed to uniquely distinguish the
5486 * number from all other IEEE 754 numeric values.
5487 * - The boolean false value is converted to the string false.
5488 * The boolean true value is converted to the string true.
5489 *
5490 * If the argument is omitted, it defaults to a node-set with the
5491 * context node as its only member.
5492 */
5493void
5494xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5495 xmlXPathObjectPtr cur;
5496
5497 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005498 valuePush(ctxt,
5499 xmlXPathWrapString(
5500 xmlXPathCastNodeToString(ctxt->context->node)));
5501 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005502 }
5503
5504 CHECK_ARITY(1);
5505 cur = valuePop(ctxt);
5506 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005507 cur = xmlXPathConvertString(cur);
5508 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005509}
5510
5511/**
5512 * xmlXPathStringLengthFunction:
5513 * @ctxt: the XPath Parser context
5514 * @nargs: the number of arguments
5515 *
5516 * Implement the string-length() XPath function
5517 * number string-length(string?)
5518 * The string-length returns the number of characters in the string
5519 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5520 * the context node converted to a string, in other words the value
5521 * of the context node.
5522 */
5523void
5524xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5525 xmlXPathObjectPtr cur;
5526
5527 if (nargs == 0) {
5528 if (ctxt->context->node == NULL) {
5529 valuePush(ctxt, xmlXPathNewFloat(0));
5530 } else {
5531 xmlChar *content;
5532
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005533 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005534 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005535 xmlFree(content);
5536 }
5537 return;
5538 }
5539 CHECK_ARITY(1);
5540 CAST_TO_STRING;
5541 CHECK_TYPE(XPATH_STRING);
5542 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005543 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005544 xmlXPathFreeObject(cur);
5545}
5546
5547/**
5548 * xmlXPathConcatFunction:
5549 * @ctxt: the XPath Parser context
5550 * @nargs: the number of arguments
5551 *
5552 * Implement the concat() XPath function
5553 * string concat(string, string, string*)
5554 * The concat function returns the concatenation of its arguments.
5555 */
5556void
5557xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5558 xmlXPathObjectPtr cur, newobj;
5559 xmlChar *tmp;
5560
5561 if (nargs < 2) {
5562 CHECK_ARITY(2);
5563 }
5564
5565 CAST_TO_STRING;
5566 cur = valuePop(ctxt);
5567 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5568 xmlXPathFreeObject(cur);
5569 return;
5570 }
5571 nargs--;
5572
5573 while (nargs > 0) {
5574 CAST_TO_STRING;
5575 newobj = valuePop(ctxt);
5576 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5577 xmlXPathFreeObject(newobj);
5578 xmlXPathFreeObject(cur);
5579 XP_ERROR(XPATH_INVALID_TYPE);
5580 }
5581 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5582 newobj->stringval = cur->stringval;
5583 cur->stringval = tmp;
5584
5585 xmlXPathFreeObject(newobj);
5586 nargs--;
5587 }
5588 valuePush(ctxt, cur);
5589}
5590
5591/**
5592 * xmlXPathContainsFunction:
5593 * @ctxt: the XPath Parser context
5594 * @nargs: the number of arguments
5595 *
5596 * Implement the contains() XPath function
5597 * boolean contains(string, string)
5598 * The contains function returns true if the first argument string
5599 * contains the second argument string, and otherwise returns false.
5600 */
5601void
5602xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5603 xmlXPathObjectPtr hay, needle;
5604
5605 CHECK_ARITY(2);
5606 CAST_TO_STRING;
5607 CHECK_TYPE(XPATH_STRING);
5608 needle = valuePop(ctxt);
5609 CAST_TO_STRING;
5610 hay = valuePop(ctxt);
5611 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5612 xmlXPathFreeObject(hay);
5613 xmlXPathFreeObject(needle);
5614 XP_ERROR(XPATH_INVALID_TYPE);
5615 }
5616 if (xmlStrstr(hay->stringval, needle->stringval))
5617 valuePush(ctxt, xmlXPathNewBoolean(1));
5618 else
5619 valuePush(ctxt, xmlXPathNewBoolean(0));
5620 xmlXPathFreeObject(hay);
5621 xmlXPathFreeObject(needle);
5622}
5623
5624/**
5625 * xmlXPathStartsWithFunction:
5626 * @ctxt: the XPath Parser context
5627 * @nargs: the number of arguments
5628 *
5629 * Implement the starts-with() XPath function
5630 * boolean starts-with(string, string)
5631 * The starts-with function returns true if the first argument string
5632 * starts with the second argument string, and otherwise returns false.
5633 */
5634void
5635xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5636 xmlXPathObjectPtr hay, needle;
5637 int n;
5638
5639 CHECK_ARITY(2);
5640 CAST_TO_STRING;
5641 CHECK_TYPE(XPATH_STRING);
5642 needle = valuePop(ctxt);
5643 CAST_TO_STRING;
5644 hay = valuePop(ctxt);
5645 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5646 xmlXPathFreeObject(hay);
5647 xmlXPathFreeObject(needle);
5648 XP_ERROR(XPATH_INVALID_TYPE);
5649 }
5650 n = xmlStrlen(needle->stringval);
5651 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5652 valuePush(ctxt, xmlXPathNewBoolean(0));
5653 else
5654 valuePush(ctxt, xmlXPathNewBoolean(1));
5655 xmlXPathFreeObject(hay);
5656 xmlXPathFreeObject(needle);
5657}
5658
5659/**
5660 * xmlXPathSubstringFunction:
5661 * @ctxt: the XPath Parser context
5662 * @nargs: the number of arguments
5663 *
5664 * Implement the substring() XPath function
5665 * string substring(string, number, number?)
5666 * The substring function returns the substring of the first argument
5667 * starting at the position specified in the second argument with
5668 * length specified in the third argument. For example,
5669 * substring("12345",2,3) returns "234". If the third argument is not
5670 * specified, it returns the substring starting at the position specified
5671 * in the second argument and continuing to the end of the string. For
5672 * example, substring("12345",2) returns "2345". More precisely, each
5673 * character in the string (see [3.6 Strings]) is considered to have a
5674 * numeric position: the position of the first character is 1, the position
5675 * of the second character is 2 and so on. The returned substring contains
5676 * those characters for which the position of the character is greater than
5677 * or equal to the second argument and, if the third argument is specified,
5678 * less than the sum of the second and third arguments; the comparisons
5679 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5680 * - substring("12345", 1.5, 2.6) returns "234"
5681 * - substring("12345", 0, 3) returns "12"
5682 * - substring("12345", 0 div 0, 3) returns ""
5683 * - substring("12345", 1, 0 div 0) returns ""
5684 * - substring("12345", -42, 1 div 0) returns "12345"
5685 * - substring("12345", -1 div 0, 1 div 0) returns ""
5686 */
5687void
5688xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5689 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005690 double le=0, in;
5691 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005692 xmlChar *ret;
5693
Owen Taylor3473f882001-02-23 17:55:21 +00005694 if (nargs < 2) {
5695 CHECK_ARITY(2);
5696 }
5697 if (nargs > 3) {
5698 CHECK_ARITY(3);
5699 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005700 /*
5701 * take care of possible last (position) argument
5702 */
Owen Taylor3473f882001-02-23 17:55:21 +00005703 if (nargs == 3) {
5704 CAST_TO_NUMBER;
5705 CHECK_TYPE(XPATH_NUMBER);
5706 len = valuePop(ctxt);
5707 le = len->floatval;
5708 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005709 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005710
Owen Taylor3473f882001-02-23 17:55:21 +00005711 CAST_TO_NUMBER;
5712 CHECK_TYPE(XPATH_NUMBER);
5713 start = valuePop(ctxt);
5714 in = start->floatval;
5715 xmlXPathFreeObject(start);
5716 CAST_TO_STRING;
5717 CHECK_TYPE(XPATH_STRING);
5718 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005719 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005720
Daniel Veillard97ac1312001-05-30 19:14:17 +00005721 /*
5722 * If last pos not present, calculate last position
5723 */
5724 if (nargs != 3)
5725 le = m;
5726
5727 /*
5728 * To meet our requirements, initial index calculations
5729 * must be done before we convert to integer format
5730 *
5731 * First we normalize indices
5732 */
5733 in -= 1.0;
5734 le += in;
5735 if (in < 0.0)
5736 in = 0.0;
5737 if (le > (double)m)
5738 le = (double)m;
5739
5740 /*
5741 * Now we go to integer form, rounding up
5742 */
Owen Taylor3473f882001-02-23 17:55:21 +00005743 i = (int) in;
5744 if (((double)i) != in) i++;
5745
Owen Taylor3473f882001-02-23 17:55:21 +00005746 l = (int) le;
5747 if (((double)l) != le) l++;
5748
Daniel Veillard97ac1312001-05-30 19:14:17 +00005749 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005750
5751 /* number of chars to copy */
5752 l -= i;
5753
Daniel Veillard97ac1312001-05-30 19:14:17 +00005754 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005755 if (ret == NULL)
5756 valuePush(ctxt, xmlXPathNewCString(""));
5757 else {
5758 valuePush(ctxt, xmlXPathNewString(ret));
5759 xmlFree(ret);
5760 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005761
Owen Taylor3473f882001-02-23 17:55:21 +00005762 xmlXPathFreeObject(str);
5763}
5764
5765/**
5766 * xmlXPathSubstringBeforeFunction:
5767 * @ctxt: the XPath Parser context
5768 * @nargs: the number of arguments
5769 *
5770 * Implement the substring-before() XPath function
5771 * string substring-before(string, string)
5772 * The substring-before function returns the substring of the first
5773 * argument string that precedes the first occurrence of the second
5774 * argument string in the first argument string, or the empty string
5775 * if the first argument string does not contain the second argument
5776 * string. For example, substring-before("1999/04/01","/") returns 1999.
5777 */
5778void
5779xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5780 xmlXPathObjectPtr str;
5781 xmlXPathObjectPtr find;
5782 xmlBufferPtr target;
5783 const xmlChar *point;
5784 int offset;
5785
5786 CHECK_ARITY(2);
5787 CAST_TO_STRING;
5788 find = valuePop(ctxt);
5789 CAST_TO_STRING;
5790 str = valuePop(ctxt);
5791
5792 target = xmlBufferCreate();
5793 if (target) {
5794 point = xmlStrstr(str->stringval, find->stringval);
5795 if (point) {
5796 offset = (int)(point - str->stringval);
5797 xmlBufferAdd(target, str->stringval, offset);
5798 }
5799 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5800 xmlBufferFree(target);
5801 }
5802
5803 xmlXPathFreeObject(str);
5804 xmlXPathFreeObject(find);
5805}
5806
5807/**
5808 * xmlXPathSubstringAfterFunction:
5809 * @ctxt: the XPath Parser context
5810 * @nargs: the number of arguments
5811 *
5812 * Implement the substring-after() XPath function
5813 * string substring-after(string, string)
5814 * The substring-after function returns the substring of the first
5815 * argument string that follows the first occurrence of the second
5816 * argument string in the first argument string, or the empty stringi
5817 * if the first argument string does not contain the second argument
5818 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5819 * and substring-after("1999/04/01","19") returns 99/04/01.
5820 */
5821void
5822xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5823 xmlXPathObjectPtr str;
5824 xmlXPathObjectPtr find;
5825 xmlBufferPtr target;
5826 const xmlChar *point;
5827 int offset;
5828
5829 CHECK_ARITY(2);
5830 CAST_TO_STRING;
5831 find = valuePop(ctxt);
5832 CAST_TO_STRING;
5833 str = valuePop(ctxt);
5834
5835 target = xmlBufferCreate();
5836 if (target) {
5837 point = xmlStrstr(str->stringval, find->stringval);
5838 if (point) {
5839 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5840 xmlBufferAdd(target, &str->stringval[offset],
5841 xmlStrlen(str->stringval) - offset);
5842 }
5843 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5844 xmlBufferFree(target);
5845 }
5846
5847 xmlXPathFreeObject(str);
5848 xmlXPathFreeObject(find);
5849}
5850
5851/**
5852 * xmlXPathNormalizeFunction:
5853 * @ctxt: the XPath Parser context
5854 * @nargs: the number of arguments
5855 *
5856 * Implement the normalize-space() XPath function
5857 * string normalize-space(string?)
5858 * The normalize-space function returns the argument string with white
5859 * space normalized by stripping leading and trailing whitespace
5860 * and replacing sequences of whitespace characters by a single
5861 * space. Whitespace characters are the same allowed by the S production
5862 * in XML. If the argument is omitted, it defaults to the context
5863 * node converted to a string, in other words the value of the context node.
5864 */
5865void
5866xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5867 xmlXPathObjectPtr obj = NULL;
5868 xmlChar *source = NULL;
5869 xmlBufferPtr target;
5870 xmlChar blank;
5871
5872 if (nargs == 0) {
5873 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005874 valuePush(ctxt,
5875 xmlXPathWrapString(
5876 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005877 nargs = 1;
5878 }
5879
5880 CHECK_ARITY(1);
5881 CAST_TO_STRING;
5882 CHECK_TYPE(XPATH_STRING);
5883 obj = valuePop(ctxt);
5884 source = obj->stringval;
5885
5886 target = xmlBufferCreate();
5887 if (target && source) {
5888
5889 /* Skip leading whitespaces */
5890 while (IS_BLANK(*source))
5891 source++;
5892
5893 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5894 blank = 0;
5895 while (*source) {
5896 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005897 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005898 } else {
5899 if (blank) {
5900 xmlBufferAdd(target, &blank, 1);
5901 blank = 0;
5902 }
5903 xmlBufferAdd(target, source, 1);
5904 }
5905 source++;
5906 }
5907
5908 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5909 xmlBufferFree(target);
5910 }
5911 xmlXPathFreeObject(obj);
5912}
5913
5914/**
5915 * xmlXPathTranslateFunction:
5916 * @ctxt: the XPath Parser context
5917 * @nargs: the number of arguments
5918 *
5919 * Implement the translate() XPath function
5920 * string translate(string, string, string)
5921 * The translate function returns the first argument string with
5922 * occurrences of characters in the second argument string replaced
5923 * by the character at the corresponding position in the third argument
5924 * string. For example, translate("bar","abc","ABC") returns the string
5925 * BAr. If there is a character in the second argument string with no
5926 * character at a corresponding position in the third argument string
5927 * (because the second argument string is longer than the third argument
5928 * string), then occurrences of that character in the first argument
5929 * string are removed. For example, translate("--aaa--","abc-","ABC")
5930 * returns "AAA". If a character occurs more than once in second
5931 * argument string, then the first occurrence determines the replacement
5932 * character. If the third argument string is longer than the second
5933 * argument string, then excess characters are ignored.
5934 */
5935void
5936xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005937 xmlXPathObjectPtr str;
5938 xmlXPathObjectPtr from;
5939 xmlXPathObjectPtr to;
5940 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005941 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005942 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005943 xmlChar *point;
5944 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005945
Daniel Veillarde043ee12001-04-16 14:08:07 +00005946 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005947
Daniel Veillarde043ee12001-04-16 14:08:07 +00005948 CAST_TO_STRING;
5949 to = valuePop(ctxt);
5950 CAST_TO_STRING;
5951 from = valuePop(ctxt);
5952 CAST_TO_STRING;
5953 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005954
Daniel Veillarde043ee12001-04-16 14:08:07 +00005955 target = xmlBufferCreate();
5956 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005957 max = xmlUTF8Strlen(to->stringval);
5958 for (cptr = str->stringval; (ch=*cptr); ) {
5959 offset = xmlUTF8Strloc(from->stringval, cptr);
5960 if (offset >= 0) {
5961 if (offset < max) {
5962 point = xmlUTF8Strpos(to->stringval, offset);
5963 if (point)
5964 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5965 }
5966 } else
5967 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5968
5969 /* Step to next character in input */
5970 cptr++;
5971 if ( ch & 0x80 ) {
5972 /* if not simple ascii, verify proper format */
5973 if ( (ch & 0xc0) != 0xc0 ) {
5974 xmlGenericError(xmlGenericErrorContext,
5975 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5976 break;
5977 }
5978 /* then skip over remaining bytes for this char */
5979 while ( (ch <<= 1) & 0x80 )
5980 if ( (*cptr++ & 0xc0) != 0x80 ) {
5981 xmlGenericError(xmlGenericErrorContext,
5982 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5983 break;
5984 }
5985 if (ch & 0x80) /* must have had error encountered */
5986 break;
5987 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005988 }
Owen Taylor3473f882001-02-23 17:55:21 +00005989 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005990 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5991 xmlBufferFree(target);
5992 xmlXPathFreeObject(str);
5993 xmlXPathFreeObject(from);
5994 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005995}
5996
5997/**
5998 * xmlXPathBooleanFunction:
5999 * @ctxt: the XPath Parser context
6000 * @nargs: the number of arguments
6001 *
6002 * Implement the boolean() XPath function
6003 * boolean boolean(object)
6004 * he boolean function converts its argument to a boolean as follows:
6005 * - a number is true if and only if it is neither positive or
6006 * negative zero nor NaN
6007 * - a node-set is true if and only if it is non-empty
6008 * - a string is true if and only if its length is non-zero
6009 */
6010void
6011xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6012 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006013
6014 CHECK_ARITY(1);
6015 cur = valuePop(ctxt);
6016 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006017 cur = xmlXPathConvertBoolean(cur);
6018 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006019}
6020
6021/**
6022 * xmlXPathNotFunction:
6023 * @ctxt: the XPath Parser context
6024 * @nargs: the number of arguments
6025 *
6026 * Implement the not() XPath function
6027 * boolean not(boolean)
6028 * The not function returns true if its argument is false,
6029 * and false otherwise.
6030 */
6031void
6032xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6033 CHECK_ARITY(1);
6034 CAST_TO_BOOLEAN;
6035 CHECK_TYPE(XPATH_BOOLEAN);
6036 ctxt->value->boolval = ! ctxt->value->boolval;
6037}
6038
6039/**
6040 * xmlXPathTrueFunction:
6041 * @ctxt: the XPath Parser context
6042 * @nargs: the number of arguments
6043 *
6044 * Implement the true() XPath function
6045 * boolean true()
6046 */
6047void
6048xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6049 CHECK_ARITY(0);
6050 valuePush(ctxt, xmlXPathNewBoolean(1));
6051}
6052
6053/**
6054 * xmlXPathFalseFunction:
6055 * @ctxt: the XPath Parser context
6056 * @nargs: the number of arguments
6057 *
6058 * Implement the false() XPath function
6059 * boolean false()
6060 */
6061void
6062xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6063 CHECK_ARITY(0);
6064 valuePush(ctxt, xmlXPathNewBoolean(0));
6065}
6066
6067/**
6068 * xmlXPathLangFunction:
6069 * @ctxt: the XPath Parser context
6070 * @nargs: the number of arguments
6071 *
6072 * Implement the lang() XPath function
6073 * boolean lang(string)
6074 * The lang function returns true or false depending on whether the
6075 * language of the context node as specified by xml:lang attributes
6076 * is the same as or is a sublanguage of the language specified by
6077 * the argument string. The language of the context node is determined
6078 * by the value of the xml:lang attribute on the context node, or, if
6079 * the context node has no xml:lang attribute, by the value of the
6080 * xml:lang attribute on the nearest ancestor of the context node that
6081 * has an xml:lang attribute. If there is no such attribute, then lang
6082 * returns false. If there is such an attribute, then lang returns
6083 * true if the attribute value is equal to the argument ignoring case,
6084 * or if there is some suffix starting with - such that the attribute
6085 * value is equal to the argument ignoring that suffix of the attribute
6086 * value and ignoring case.
6087 */
6088void
6089xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6090 xmlXPathObjectPtr val;
6091 const xmlChar *theLang;
6092 const xmlChar *lang;
6093 int ret = 0;
6094 int i;
6095
6096 CHECK_ARITY(1);
6097 CAST_TO_STRING;
6098 CHECK_TYPE(XPATH_STRING);
6099 val = valuePop(ctxt);
6100 lang = val->stringval;
6101 theLang = xmlNodeGetLang(ctxt->context->node);
6102 if ((theLang != NULL) && (lang != NULL)) {
6103 for (i = 0;lang[i] != 0;i++)
6104 if (toupper(lang[i]) != toupper(theLang[i]))
6105 goto not_equal;
6106 ret = 1;
6107 }
6108not_equal:
6109 xmlXPathFreeObject(val);
6110 valuePush(ctxt, xmlXPathNewBoolean(ret));
6111}
6112
6113/**
6114 * xmlXPathNumberFunction:
6115 * @ctxt: the XPath Parser context
6116 * @nargs: the number of arguments
6117 *
6118 * Implement the number() XPath function
6119 * number number(object?)
6120 */
6121void
6122xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6123 xmlXPathObjectPtr cur;
6124 double res;
6125
6126 if (nargs == 0) {
6127 if (ctxt->context->node == NULL) {
6128 valuePush(ctxt, xmlXPathNewFloat(0.0));
6129 } else {
6130 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6131
6132 res = xmlXPathStringEvalNumber(content);
6133 valuePush(ctxt, xmlXPathNewFloat(res));
6134 xmlFree(content);
6135 }
6136 return;
6137 }
6138
6139 CHECK_ARITY(1);
6140 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006141 cur = xmlXPathConvertNumber(cur);
6142 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006143}
6144
6145/**
6146 * xmlXPathSumFunction:
6147 * @ctxt: the XPath Parser context
6148 * @nargs: the number of arguments
6149 *
6150 * Implement the sum() XPath function
6151 * number sum(node-set)
6152 * The sum function returns the sum of the values of the nodes in
6153 * the argument node-set.
6154 */
6155void
6156xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6157 xmlXPathObjectPtr cur;
6158 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006159 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006160
6161 CHECK_ARITY(1);
6162 if ((ctxt->value == NULL) ||
6163 ((ctxt->value->type != XPATH_NODESET) &&
6164 (ctxt->value->type != XPATH_XSLT_TREE)))
6165 XP_ERROR(XPATH_INVALID_TYPE);
6166 cur = valuePop(ctxt);
6167
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006168 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006169 valuePush(ctxt, xmlXPathNewFloat(0.0));
6170 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006171 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6172 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006173 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006174 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006175 }
6176 xmlXPathFreeObject(cur);
6177}
6178
6179/**
6180 * xmlXPathFloorFunction:
6181 * @ctxt: the XPath Parser context
6182 * @nargs: the number of arguments
6183 *
6184 * Implement the floor() XPath function
6185 * number floor(number)
6186 * The floor function returns the largest (closest to positive infinity)
6187 * number that is not greater than the argument and that is an integer.
6188 */
6189void
6190xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6191 CHECK_ARITY(1);
6192 CAST_TO_NUMBER;
6193 CHECK_TYPE(XPATH_NUMBER);
6194#if 0
6195 ctxt->value->floatval = floor(ctxt->value->floatval);
6196#else
6197 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6198 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6199#endif
6200}
6201
6202/**
6203 * xmlXPathCeilingFunction:
6204 * @ctxt: the XPath Parser context
6205 * @nargs: the number of arguments
6206 *
6207 * Implement the ceiling() XPath function
6208 * number ceiling(number)
6209 * The ceiling function returns the smallest (closest to negative infinity)
6210 * number that is not less than the argument and that is an integer.
6211 */
6212void
6213xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6214 double f;
6215
6216 CHECK_ARITY(1);
6217 CAST_TO_NUMBER;
6218 CHECK_TYPE(XPATH_NUMBER);
6219
6220#if 0
6221 ctxt->value->floatval = ceil(ctxt->value->floatval);
6222#else
6223 f = (double)((int) ctxt->value->floatval);
6224 if (f != ctxt->value->floatval)
6225 ctxt->value->floatval = f + 1;
6226#endif
6227}
6228
6229/**
6230 * xmlXPathRoundFunction:
6231 * @ctxt: the XPath Parser context
6232 * @nargs: the number of arguments
6233 *
6234 * Implement the round() XPath function
6235 * number round(number)
6236 * The round function returns the number that is closest to the
6237 * argument and that is an integer. If there are two such numbers,
6238 * then the one that is even is returned.
6239 */
6240void
6241xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6242 double f;
6243
6244 CHECK_ARITY(1);
6245 CAST_TO_NUMBER;
6246 CHECK_TYPE(XPATH_NUMBER);
6247
Daniel Veillardcda96922001-08-21 10:56:31 +00006248 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6249 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6250 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006251 (ctxt->value->floatval == 0.0))
6252 return;
6253
6254#if 0
6255 f = floor(ctxt->value->floatval);
6256#else
6257 f = (double)((int) ctxt->value->floatval);
6258#endif
6259 if (ctxt->value->floatval < f + 0.5)
6260 ctxt->value->floatval = f;
6261 else
6262 ctxt->value->floatval = f + 1;
6263}
6264
6265/************************************************************************
6266 * *
6267 * The Parser *
6268 * *
6269 ************************************************************************/
6270
6271/*
6272 * a couple of forward declarations since we use a recursive call based
6273 * implementation.
6274 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006275static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006276static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006277static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006278#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006279static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6280#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006281#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006282static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006283#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006284static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6285 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006286
6287/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006288 * xmlXPathCurrentChar:
6289 * @ctxt: the XPath parser context
6290 * @cur: pointer to the beginning of the char
6291 * @len: pointer to the length of the char read
6292 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006293 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006294 * bytes in the input buffer.
6295 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006296 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006297 */
6298
6299static int
6300xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6301 unsigned char c;
6302 unsigned int val;
6303 const xmlChar *cur;
6304
6305 if (ctxt == NULL)
6306 return(0);
6307 cur = ctxt->cur;
6308
6309 /*
6310 * We are supposed to handle UTF8, check it's valid
6311 * From rfc2044: encoding of the Unicode values on UTF-8:
6312 *
6313 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6314 * 0000 0000-0000 007F 0xxxxxxx
6315 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6316 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6317 *
6318 * Check for the 0x110000 limit too
6319 */
6320 c = *cur;
6321 if (c & 0x80) {
6322 if ((cur[1] & 0xc0) != 0x80)
6323 goto encoding_error;
6324 if ((c & 0xe0) == 0xe0) {
6325
6326 if ((cur[2] & 0xc0) != 0x80)
6327 goto encoding_error;
6328 if ((c & 0xf0) == 0xf0) {
6329 if (((c & 0xf8) != 0xf0) ||
6330 ((cur[3] & 0xc0) != 0x80))
6331 goto encoding_error;
6332 /* 4-byte code */
6333 *len = 4;
6334 val = (cur[0] & 0x7) << 18;
6335 val |= (cur[1] & 0x3f) << 12;
6336 val |= (cur[2] & 0x3f) << 6;
6337 val |= cur[3] & 0x3f;
6338 } else {
6339 /* 3-byte code */
6340 *len = 3;
6341 val = (cur[0] & 0xf) << 12;
6342 val |= (cur[1] & 0x3f) << 6;
6343 val |= cur[2] & 0x3f;
6344 }
6345 } else {
6346 /* 2-byte code */
6347 *len = 2;
6348 val = (cur[0] & 0x1f) << 6;
6349 val |= cur[1] & 0x3f;
6350 }
6351 if (!IS_CHAR(val)) {
6352 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6353 }
6354 return(val);
6355 } else {
6356 /* 1-byte code */
6357 *len = 1;
6358 return((int) *cur);
6359 }
6360encoding_error:
6361 /*
6362 * If we detect an UTF8 error that probably mean that the
6363 * input encoding didn't get properly advertized in the
6364 * declaration header. Report the error and switch the encoding
6365 * to ISO-Latin-1 (if you don't like this policy, just declare the
6366 * encoding !)
6367 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006368 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006369 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006370}
6371
6372/**
Owen Taylor3473f882001-02-23 17:55:21 +00006373 * xmlXPathParseNCName:
6374 * @ctxt: the XPath Parser context
6375 *
6376 * parse an XML namespace non qualified name.
6377 *
6378 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6379 *
6380 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6381 * CombiningChar | Extender
6382 *
6383 * Returns the namespace name or NULL
6384 */
6385
6386xmlChar *
6387xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006388 const xmlChar *in;
6389 xmlChar *ret;
6390 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006391
Daniel Veillard2156a562001-04-28 12:24:34 +00006392 /*
6393 * Accelerator for simple ASCII names
6394 */
6395 in = ctxt->cur;
6396 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6397 ((*in >= 0x41) && (*in <= 0x5A)) ||
6398 (*in == '_')) {
6399 in++;
6400 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6401 ((*in >= 0x41) && (*in <= 0x5A)) ||
6402 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006403 (*in == '_') || (*in == '.') ||
6404 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006405 in++;
6406 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6407 (*in == '[') || (*in == ']') || (*in == ':') ||
6408 (*in == '@') || (*in == '*')) {
6409 count = in - ctxt->cur;
6410 if (count == 0)
6411 return(NULL);
6412 ret = xmlStrndup(ctxt->cur, count);
6413 ctxt->cur = in;
6414 return(ret);
6415 }
6416 }
6417 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006418}
6419
Daniel Veillard2156a562001-04-28 12:24:34 +00006420
Owen Taylor3473f882001-02-23 17:55:21 +00006421/**
6422 * xmlXPathParseQName:
6423 * @ctxt: the XPath Parser context
6424 * @prefix: a xmlChar **
6425 *
6426 * parse an XML qualified name
6427 *
6428 * [NS 5] QName ::= (Prefix ':')? LocalPart
6429 *
6430 * [NS 6] Prefix ::= NCName
6431 *
6432 * [NS 7] LocalPart ::= NCName
6433 *
6434 * Returns the function returns the local part, and prefix is updated
6435 * to get the Prefix if any.
6436 */
6437
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006438static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006439xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6440 xmlChar *ret = NULL;
6441
6442 *prefix = NULL;
6443 ret = xmlXPathParseNCName(ctxt);
6444 if (CUR == ':') {
6445 *prefix = ret;
6446 NEXT;
6447 ret = xmlXPathParseNCName(ctxt);
6448 }
6449 return(ret);
6450}
6451
6452/**
6453 * xmlXPathParseName:
6454 * @ctxt: the XPath Parser context
6455 *
6456 * parse an XML name
6457 *
6458 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6459 * CombiningChar | Extender
6460 *
6461 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6462 *
6463 * Returns the namespace name or NULL
6464 */
6465
6466xmlChar *
6467xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006468 const xmlChar *in;
6469 xmlChar *ret;
6470 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006471
Daniel Veillard61d80a22001-04-27 17:13:01 +00006472 /*
6473 * Accelerator for simple ASCII names
6474 */
6475 in = ctxt->cur;
6476 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6477 ((*in >= 0x41) && (*in <= 0x5A)) ||
6478 (*in == '_') || (*in == ':')) {
6479 in++;
6480 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6481 ((*in >= 0x41) && (*in <= 0x5A)) ||
6482 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006483 (*in == '_') || (*in == '-') ||
6484 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006485 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006486 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006487 count = in - ctxt->cur;
6488 ret = xmlStrndup(ctxt->cur, count);
6489 ctxt->cur = in;
6490 return(ret);
6491 }
6492 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006493 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006494}
6495
Daniel Veillard61d80a22001-04-27 17:13:01 +00006496static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006497xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006498 xmlChar buf[XML_MAX_NAMELEN + 5];
6499 int len = 0, l;
6500 int c;
6501
6502 /*
6503 * Handler for more complex cases
6504 */
6505 c = CUR_CHAR(l);
6506 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006507 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6508 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006509 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006510 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006511 return(NULL);
6512 }
6513
6514 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6515 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6516 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006517 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006518 (IS_COMBINING(c)) ||
6519 (IS_EXTENDER(c)))) {
6520 COPY_BUF(l,buf,len,c);
6521 NEXTL(l);
6522 c = CUR_CHAR(l);
6523 if (len >= XML_MAX_NAMELEN) {
6524 /*
6525 * Okay someone managed to make a huge name, so he's ready to pay
6526 * for the processing speed.
6527 */
6528 xmlChar *buffer;
6529 int max = len * 2;
6530
6531 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6532 if (buffer == NULL) {
6533 XP_ERROR0(XPATH_MEMORY_ERROR);
6534 }
6535 memcpy(buffer, buf, len);
6536 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6537 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006538 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006539 (IS_COMBINING(c)) ||
6540 (IS_EXTENDER(c))) {
6541 if (len + 10 > max) {
6542 max *= 2;
6543 buffer = (xmlChar *) xmlRealloc(buffer,
6544 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006545 if (buffer == NULL) {
6546 XP_ERROR0(XPATH_MEMORY_ERROR);
6547 }
6548 }
6549 COPY_BUF(l,buffer,len,c);
6550 NEXTL(l);
6551 c = CUR_CHAR(l);
6552 }
6553 buffer[len] = 0;
6554 return(buffer);
6555 }
6556 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006557 if (len == 0)
6558 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006559 return(xmlStrndup(buf, len));
6560}
Owen Taylor3473f882001-02-23 17:55:21 +00006561/**
6562 * xmlXPathStringEvalNumber:
6563 * @str: A string to scan
6564 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006565 * [30a] Float ::= Number ('e' Digits?)?
6566 *
Owen Taylor3473f882001-02-23 17:55:21 +00006567 * [30] Number ::= Digits ('.' Digits?)?
6568 * | '.' Digits
6569 * [31] Digits ::= [0-9]+
6570 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006571 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006572 * In complement of the Number expression, this function also handles
6573 * negative values : '-' Number.
6574 *
6575 * Returns the double value.
6576 */
6577double
6578xmlXPathStringEvalNumber(const xmlChar *str) {
6579 const xmlChar *cur = str;
6580 double ret = 0.0;
6581 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006582 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006583 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006584 int exponent = 0;
6585 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006586#ifdef __GNUC__
6587 unsigned long tmp = 0;
6588#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006589
Owen Taylor3473f882001-02-23 17:55:21 +00006590 while (IS_BLANK(*cur)) cur++;
6591 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6592 return(xmlXPathNAN);
6593 }
6594 if (*cur == '-') {
6595 isneg = 1;
6596 cur++;
6597 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006598
6599#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006600 /*
Daniel Veillardb06c6142001-08-27 14:26:30 +00006601 * tmp is a workaround against a gcc compiler bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006602 */
Owen Taylor3473f882001-02-23 17:55:21 +00006603 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006604 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006605 ok = 1;
6606 cur++;
6607 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006608 ret = (double) tmp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006609#else
6610 while ((*cur >= '0') && (*cur <= '9')) {
6611 ret = ret * 10 + (*cur - '0');
6612 ok = 1;
6613 cur++;
6614 }
6615#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006616
Owen Taylor3473f882001-02-23 17:55:21 +00006617 if (*cur == '.') {
6618 cur++;
6619 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6620 return(xmlXPathNAN);
6621 }
6622 while ((*cur >= '0') && (*cur <= '9')) {
6623 mult /= 10;
6624 ret = ret + (*cur - '0') * mult;
6625 cur++;
6626 }
6627 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006628 if ((*cur == 'e') || (*cur == 'E')) {
6629 cur++;
6630 if (*cur == '-') {
6631 is_exponent_negative = 1;
6632 cur++;
6633 }
6634 while ((*cur >= '0') && (*cur <= '9')) {
6635 exponent = exponent * 10 + (*cur - '0');
6636 cur++;
6637 }
6638 }
Owen Taylor3473f882001-02-23 17:55:21 +00006639 while (IS_BLANK(*cur)) cur++;
6640 if (*cur != 0) return(xmlXPathNAN);
6641 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006642 if (is_exponent_negative) exponent = -exponent;
6643 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006644 return(ret);
6645}
6646
6647/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006648 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006649 * @ctxt: the XPath Parser context
6650 *
6651 * [30] Number ::= Digits ('.' Digits?)?
6652 * | '.' Digits
6653 * [31] Digits ::= [0-9]+
6654 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006655 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006656 *
6657 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006658static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006659xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6660{
Owen Taylor3473f882001-02-23 17:55:21 +00006661 double ret = 0.0;
6662 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006663 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006664 int exponent = 0;
6665 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006666
6667 CHECK_ERROR;
6668 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6669 XP_ERROR(XPATH_NUMBER_ERROR);
6670 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006671 /*
6672 * Try to work around a gcc optimizer bug
6673 */
Owen Taylor3473f882001-02-23 17:55:21 +00006674 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006675 tmp = tmp * 10 + (CUR - '0');
6676 ok = 1;
6677 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006678 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006679 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006680 if (CUR == '.') {
6681 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006682 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6683 XP_ERROR(XPATH_NUMBER_ERROR);
6684 }
6685 while ((CUR >= '0') && (CUR <= '9')) {
6686 mult /= 10;
6687 ret = ret + (CUR - '0') * mult;
6688 NEXT;
6689 }
Owen Taylor3473f882001-02-23 17:55:21 +00006690 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006691 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006692 NEXT;
6693 if (CUR == '-') {
6694 is_exponent_negative = 1;
6695 NEXT;
6696 }
6697 while ((CUR >= '0') && (CUR <= '9')) {
6698 exponent = exponent * 10 + (CUR - '0');
6699 NEXT;
6700 }
6701 if (is_exponent_negative)
6702 exponent = -exponent;
6703 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006704 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006705 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006706 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006707}
6708
6709/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006710 * xmlXPathParseLiteral:
6711 * @ctxt: the XPath Parser context
6712 *
6713 * Parse a Literal
6714 *
6715 * [29] Literal ::= '"' [^"]* '"'
6716 * | "'" [^']* "'"
6717 *
6718 * Returns the value found or NULL in case of error
6719 */
6720static xmlChar *
6721xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6722 const xmlChar *q;
6723 xmlChar *ret = NULL;
6724
6725 if (CUR == '"') {
6726 NEXT;
6727 q = CUR_PTR;
6728 while ((IS_CHAR(CUR)) && (CUR != '"'))
6729 NEXT;
6730 if (!IS_CHAR(CUR)) {
6731 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6732 } else {
6733 ret = xmlStrndup(q, CUR_PTR - q);
6734 NEXT;
6735 }
6736 } else if (CUR == '\'') {
6737 NEXT;
6738 q = CUR_PTR;
6739 while ((IS_CHAR(CUR)) && (CUR != '\''))
6740 NEXT;
6741 if (!IS_CHAR(CUR)) {
6742 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6743 } else {
6744 ret = xmlStrndup(q, CUR_PTR - q);
6745 NEXT;
6746 }
6747 } else {
6748 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6749 }
6750 return(ret);
6751}
6752
6753/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006754 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006755 * @ctxt: the XPath Parser context
6756 *
6757 * Parse a Literal and push it on the stack.
6758 *
6759 * [29] Literal ::= '"' [^"]* '"'
6760 * | "'" [^']* "'"
6761 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006762 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006763 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006764static void
6765xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006766 const xmlChar *q;
6767 xmlChar *ret = NULL;
6768
6769 if (CUR == '"') {
6770 NEXT;
6771 q = CUR_PTR;
6772 while ((IS_CHAR(CUR)) && (CUR != '"'))
6773 NEXT;
6774 if (!IS_CHAR(CUR)) {
6775 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6776 } else {
6777 ret = xmlStrndup(q, CUR_PTR - q);
6778 NEXT;
6779 }
6780 } else if (CUR == '\'') {
6781 NEXT;
6782 q = CUR_PTR;
6783 while ((IS_CHAR(CUR)) && (CUR != '\''))
6784 NEXT;
6785 if (!IS_CHAR(CUR)) {
6786 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6787 } else {
6788 ret = xmlStrndup(q, CUR_PTR - q);
6789 NEXT;
6790 }
6791 } else {
6792 XP_ERROR(XPATH_START_LITERAL_ERROR);
6793 }
6794 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006795 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6796 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006797 xmlFree(ret);
6798}
6799
6800/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006801 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006802 * @ctxt: the XPath Parser context
6803 *
6804 * Parse a VariableReference, evaluate it and push it on the stack.
6805 *
6806 * The variable bindings consist of a mapping from variable names
6807 * to variable values. The value of a variable is an object, which
6808 * of any of the types that are possible for the value of an expression,
6809 * and may also be of additional types not specified here.
6810 *
6811 * Early evaluation is possible since:
6812 * The variable bindings [...] used to evaluate a subexpression are
6813 * always the same as those used to evaluate the containing expression.
6814 *
6815 * [36] VariableReference ::= '$' QName
6816 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006817static void
6818xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006819 xmlChar *name;
6820 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006821
6822 SKIP_BLANKS;
6823 if (CUR != '$') {
6824 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6825 }
6826 NEXT;
6827 name = xmlXPathParseQName(ctxt, &prefix);
6828 if (name == NULL) {
6829 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6830 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006831 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006832 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6833 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006834 SKIP_BLANKS;
6835}
6836
6837/**
6838 * xmlXPathIsNodeType:
6839 * @ctxt: the XPath Parser context
6840 * @name: a name string
6841 *
6842 * Is the name given a NodeType one.
6843 *
6844 * [38] NodeType ::= 'comment'
6845 * | 'text'
6846 * | 'processing-instruction'
6847 * | 'node'
6848 *
6849 * Returns 1 if true 0 otherwise
6850 */
6851int
6852xmlXPathIsNodeType(const xmlChar *name) {
6853 if (name == NULL)
6854 return(0);
6855
Daniel Veillard1971ee22002-01-31 20:29:19 +00006856 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00006857 return(1);
6858 if (xmlStrEqual(name, BAD_CAST "text"))
6859 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00006860 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00006861 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00006862 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00006863 return(1);
6864 return(0);
6865}
6866
6867/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006868 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006869 * @ctxt: the XPath Parser context
6870 *
6871 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6872 * [17] Argument ::= Expr
6873 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006874 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006875 * pushed on the stack
6876 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006877static void
6878xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006879 xmlChar *name;
6880 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006881 int nbargs = 0;
6882
6883 name = xmlXPathParseQName(ctxt, &prefix);
6884 if (name == NULL) {
6885 XP_ERROR(XPATH_EXPR_ERROR);
6886 }
6887 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006888#ifdef DEBUG_EXPR
6889 if (prefix == NULL)
6890 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6891 name);
6892 else
6893 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6894 prefix, name);
6895#endif
6896
Owen Taylor3473f882001-02-23 17:55:21 +00006897 if (CUR != '(') {
6898 XP_ERROR(XPATH_EXPR_ERROR);
6899 }
6900 NEXT;
6901 SKIP_BLANKS;
6902
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006903 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006904 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006905 int op1 = ctxt->comp->last;
6906 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006907 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006908 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006909 nbargs++;
6910 if (CUR == ')') break;
6911 if (CUR != ',') {
6912 XP_ERROR(XPATH_EXPR_ERROR);
6913 }
6914 NEXT;
6915 SKIP_BLANKS;
6916 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006917 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6918 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006919 NEXT;
6920 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006921}
6922
6923/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006924 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006925 * @ctxt: the XPath Parser context
6926 *
6927 * [15] PrimaryExpr ::= VariableReference
6928 * | '(' Expr ')'
6929 * | Literal
6930 * | Number
6931 * | FunctionCall
6932 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006933 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006934 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006935static void
6936xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006937 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006938 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006939 else if (CUR == '(') {
6940 NEXT;
6941 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006942 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006943 if (CUR != ')') {
6944 XP_ERROR(XPATH_EXPR_ERROR);
6945 }
6946 NEXT;
6947 SKIP_BLANKS;
6948 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006949 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006950 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006951 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006952 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006953 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006954 }
6955 SKIP_BLANKS;
6956}
6957
6958/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006959 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006960 * @ctxt: the XPath Parser context
6961 *
6962 * [20] FilterExpr ::= PrimaryExpr
6963 * | FilterExpr Predicate
6964 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006965 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006966 * Square brackets are used to filter expressions in the same way that
6967 * they are used in location paths. It is an error if the expression to
6968 * be filtered does not evaluate to a node-set. The context node list
6969 * used for evaluating the expression in square brackets is the node-set
6970 * to be filtered listed in document order.
6971 */
6972
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006973static void
6974xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6975 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006976 CHECK_ERROR;
6977 SKIP_BLANKS;
6978
6979 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006980 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006981 SKIP_BLANKS;
6982 }
6983
6984
6985}
6986
6987/**
6988 * xmlXPathScanName:
6989 * @ctxt: the XPath Parser context
6990 *
6991 * Trickery: parse an XML name but without consuming the input flow
6992 * Needed to avoid insanity in the parser state.
6993 *
6994 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6995 * CombiningChar | Extender
6996 *
6997 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6998 *
6999 * [6] Names ::= Name (S Name)*
7000 *
7001 * Returns the Name parsed or NULL
7002 */
7003
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007004static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007005xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7006 xmlChar buf[XML_MAX_NAMELEN];
7007 int len = 0;
7008
7009 SKIP_BLANKS;
7010 if (!IS_LETTER(CUR) && (CUR != '_') &&
7011 (CUR != ':')) {
7012 return(NULL);
7013 }
7014
7015 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7016 (NXT(len) == '.') || (NXT(len) == '-') ||
7017 (NXT(len) == '_') || (NXT(len) == ':') ||
7018 (IS_COMBINING(NXT(len))) ||
7019 (IS_EXTENDER(NXT(len)))) {
7020 buf[len] = NXT(len);
7021 len++;
7022 if (len >= XML_MAX_NAMELEN) {
7023 xmlGenericError(xmlGenericErrorContext,
7024 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7025 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7026 (NXT(len) == '.') || (NXT(len) == '-') ||
7027 (NXT(len) == '_') || (NXT(len) == ':') ||
7028 (IS_COMBINING(NXT(len))) ||
7029 (IS_EXTENDER(NXT(len))))
7030 len++;
7031 break;
7032 }
7033 }
7034 return(xmlStrndup(buf, len));
7035}
7036
7037/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007038 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007039 * @ctxt: the XPath Parser context
7040 *
7041 * [19] PathExpr ::= LocationPath
7042 * | FilterExpr
7043 * | FilterExpr '/' RelativeLocationPath
7044 * | FilterExpr '//' RelativeLocationPath
7045 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007046 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007047 * The / operator and // operators combine an arbitrary expression
7048 * and a relative location path. It is an error if the expression
7049 * does not evaluate to a node-set.
7050 * The / operator does composition in the same way as when / is
7051 * used in a location path. As in location paths, // is short for
7052 * /descendant-or-self::node()/.
7053 */
7054
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007055static void
7056xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007057 int lc = 1; /* Should we branch to LocationPath ? */
7058 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7059
7060 SKIP_BLANKS;
7061 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7062 (CUR == '\'') || (CUR == '"')) {
7063 lc = 0;
7064 } else if (CUR == '*') {
7065 /* relative or absolute location path */
7066 lc = 1;
7067 } else if (CUR == '/') {
7068 /* relative or absolute location path */
7069 lc = 1;
7070 } else if (CUR == '@') {
7071 /* relative abbreviated attribute location path */
7072 lc = 1;
7073 } else if (CUR == '.') {
7074 /* relative abbreviated attribute location path */
7075 lc = 1;
7076 } else {
7077 /*
7078 * Problem is finding if we have a name here whether it's:
7079 * - a nodetype
7080 * - a function call in which case it's followed by '('
7081 * - an axis in which case it's followed by ':'
7082 * - a element name
7083 * We do an a priori analysis here rather than having to
7084 * maintain parsed token content through the recursive function
7085 * calls. This looks uglier but makes the code quite easier to
7086 * read/write/debug.
7087 */
7088 SKIP_BLANKS;
7089 name = xmlXPathScanName(ctxt);
7090 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7091#ifdef DEBUG_STEP
7092 xmlGenericError(xmlGenericErrorContext,
7093 "PathExpr: Axis\n");
7094#endif
7095 lc = 1;
7096 xmlFree(name);
7097 } else if (name != NULL) {
7098 int len =xmlStrlen(name);
7099 int blank = 0;
7100
7101
7102 while (NXT(len) != 0) {
7103 if (NXT(len) == '/') {
7104 /* element name */
7105#ifdef DEBUG_STEP
7106 xmlGenericError(xmlGenericErrorContext,
7107 "PathExpr: AbbrRelLocation\n");
7108#endif
7109 lc = 1;
7110 break;
7111 } else if (IS_BLANK(NXT(len))) {
7112 /* skip to next */
7113 blank = 1;
7114 } else if (NXT(len) == ':') {
7115#ifdef DEBUG_STEP
7116 xmlGenericError(xmlGenericErrorContext,
7117 "PathExpr: AbbrRelLocation\n");
7118#endif
7119 lc = 1;
7120 break;
7121 } else if ((NXT(len) == '(')) {
7122 /* Note Type or Function */
7123 if (xmlXPathIsNodeType(name)) {
7124#ifdef DEBUG_STEP
7125 xmlGenericError(xmlGenericErrorContext,
7126 "PathExpr: Type search\n");
7127#endif
7128 lc = 1;
7129 } else {
7130#ifdef DEBUG_STEP
7131 xmlGenericError(xmlGenericErrorContext,
7132 "PathExpr: function call\n");
7133#endif
7134 lc = 0;
7135 }
7136 break;
7137 } else if ((NXT(len) == '[')) {
7138 /* element name */
7139#ifdef DEBUG_STEP
7140 xmlGenericError(xmlGenericErrorContext,
7141 "PathExpr: AbbrRelLocation\n");
7142#endif
7143 lc = 1;
7144 break;
7145 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7146 (NXT(len) == '=')) {
7147 lc = 1;
7148 break;
7149 } else {
7150 lc = 1;
7151 break;
7152 }
7153 len++;
7154 }
7155 if (NXT(len) == 0) {
7156#ifdef DEBUG_STEP
7157 xmlGenericError(xmlGenericErrorContext,
7158 "PathExpr: AbbrRelLocation\n");
7159#endif
7160 /* element name */
7161 lc = 1;
7162 }
7163 xmlFree(name);
7164 } else {
7165 /* make sure all cases are covered explicitely */
7166 XP_ERROR(XPATH_EXPR_ERROR);
7167 }
7168 }
7169
7170 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007171 if (CUR == '/') {
7172 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7173 } else {
7174 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007175 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007176 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007177 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007178 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007179 CHECK_ERROR;
7180 if ((CUR == '/') && (NXT(1) == '/')) {
7181 SKIP(2);
7182 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007183
7184 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7185 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7186 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7187
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007188 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007189 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007190 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007191 }
7192 }
7193 SKIP_BLANKS;
7194}
7195
7196/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007197 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007198 * @ctxt: the XPath Parser context
7199 *
7200 * [18] UnionExpr ::= PathExpr
7201 * | UnionExpr '|' PathExpr
7202 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007203 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007204 */
7205
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007206static void
7207xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7208 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007209 CHECK_ERROR;
7210 SKIP_BLANKS;
7211 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007212 int op1 = ctxt->comp->last;
7213 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007214
7215 NEXT;
7216 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007217 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007218
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007219 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7220
Owen Taylor3473f882001-02-23 17:55:21 +00007221 SKIP_BLANKS;
7222 }
Owen Taylor3473f882001-02-23 17:55:21 +00007223}
7224
7225/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007226 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007227 * @ctxt: the XPath Parser context
7228 *
7229 * [27] UnaryExpr ::= UnionExpr
7230 * | '-' UnaryExpr
7231 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007232 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007233 */
7234
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007235static void
7236xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007237 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007238 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007239
7240 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007241 while (CUR == '-') {
7242 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007243 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007244 NEXT;
7245 SKIP_BLANKS;
7246 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007247
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007248 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007249 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007250 if (found) {
7251 if (minus)
7252 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7253 else
7254 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007255 }
7256}
7257
7258/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007259 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007260 * @ctxt: the XPath Parser context
7261 *
7262 * [26] MultiplicativeExpr ::= UnaryExpr
7263 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7264 * | MultiplicativeExpr 'div' UnaryExpr
7265 * | MultiplicativeExpr 'mod' UnaryExpr
7266 * [34] MultiplyOperator ::= '*'
7267 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007268 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007269 */
7270
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007271static void
7272xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7273 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007274 CHECK_ERROR;
7275 SKIP_BLANKS;
7276 while ((CUR == '*') ||
7277 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7278 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7279 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007280 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007281
7282 if (CUR == '*') {
7283 op = 0;
7284 NEXT;
7285 } else if (CUR == 'd') {
7286 op = 1;
7287 SKIP(3);
7288 } else if (CUR == 'm') {
7289 op = 2;
7290 SKIP(3);
7291 }
7292 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007293 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007294 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007295 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007296 SKIP_BLANKS;
7297 }
7298}
7299
7300/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007301 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007302 * @ctxt: the XPath Parser context
7303 *
7304 * [25] AdditiveExpr ::= MultiplicativeExpr
7305 * | AdditiveExpr '+' MultiplicativeExpr
7306 * | AdditiveExpr '-' MultiplicativeExpr
7307 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007308 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007309 */
7310
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007311static void
7312xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007313
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007314 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007315 CHECK_ERROR;
7316 SKIP_BLANKS;
7317 while ((CUR == '+') || (CUR == '-')) {
7318 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007319 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007320
7321 if (CUR == '+') plus = 1;
7322 else plus = 0;
7323 NEXT;
7324 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007325 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007326 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007327 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007328 SKIP_BLANKS;
7329 }
7330}
7331
7332/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007333 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007334 * @ctxt: the XPath Parser context
7335 *
7336 * [24] RelationalExpr ::= AdditiveExpr
7337 * | RelationalExpr '<' AdditiveExpr
7338 * | RelationalExpr '>' AdditiveExpr
7339 * | RelationalExpr '<=' AdditiveExpr
7340 * | RelationalExpr '>=' AdditiveExpr
7341 *
7342 * A <= B > C is allowed ? Answer from James, yes with
7343 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7344 * which is basically what got implemented.
7345 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007346 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007347 * on the stack
7348 */
7349
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007350static void
7351xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7352 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007353 CHECK_ERROR;
7354 SKIP_BLANKS;
7355 while ((CUR == '<') ||
7356 (CUR == '>') ||
7357 ((CUR == '<') && (NXT(1) == '=')) ||
7358 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007359 int inf, strict;
7360 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007361
7362 if (CUR == '<') inf = 1;
7363 else inf = 0;
7364 if (NXT(1) == '=') strict = 0;
7365 else strict = 1;
7366 NEXT;
7367 if (!strict) NEXT;
7368 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007369 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007370 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007371 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007372 SKIP_BLANKS;
7373 }
7374}
7375
7376/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007377 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007378 * @ctxt: the XPath Parser context
7379 *
7380 * [23] EqualityExpr ::= RelationalExpr
7381 * | EqualityExpr '=' RelationalExpr
7382 * | EqualityExpr '!=' RelationalExpr
7383 *
7384 * A != B != C is allowed ? Answer from James, yes with
7385 * (RelationalExpr = RelationalExpr) = RelationalExpr
7386 * (RelationalExpr != RelationalExpr) != RelationalExpr
7387 * which is basically what got implemented.
7388 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007389 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007390 *
7391 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007392static void
7393xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7394 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007395 CHECK_ERROR;
7396 SKIP_BLANKS;
7397 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007398 int eq;
7399 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007400
7401 if (CUR == '=') eq = 1;
7402 else eq = 0;
7403 NEXT;
7404 if (!eq) NEXT;
7405 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007406 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007407 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007408 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007409 SKIP_BLANKS;
7410 }
7411}
7412
7413/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007414 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007415 * @ctxt: the XPath Parser context
7416 *
7417 * [22] AndExpr ::= EqualityExpr
7418 * | AndExpr 'and' EqualityExpr
7419 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007420 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007421 *
7422 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007423static void
7424xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7425 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007426 CHECK_ERROR;
7427 SKIP_BLANKS;
7428 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007429 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007430 SKIP(3);
7431 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007432 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007433 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007434 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007435 SKIP_BLANKS;
7436 }
7437}
7438
7439/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007440 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007441 * @ctxt: the XPath Parser context
7442 *
7443 * [14] Expr ::= OrExpr
7444 * [21] OrExpr ::= AndExpr
7445 * | OrExpr 'or' AndExpr
7446 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007447 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007448 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007449static void
7450xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7451 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007452 CHECK_ERROR;
7453 SKIP_BLANKS;
7454 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007455 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007456 SKIP(2);
7457 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007458 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007459 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007460 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7461 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007462 SKIP_BLANKS;
7463 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007464 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7465 /* more ops could be optimized too */
7466 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7467 }
Owen Taylor3473f882001-02-23 17:55:21 +00007468}
7469
7470/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007471 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007472 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007473 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007474 *
7475 * [8] Predicate ::= '[' PredicateExpr ']'
7476 * [9] PredicateExpr ::= Expr
7477 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007478 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007479 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007480static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007481xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007482 int op1 = ctxt->comp->last;
7483
7484 SKIP_BLANKS;
7485 if (CUR != '[') {
7486 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7487 }
7488 NEXT;
7489 SKIP_BLANKS;
7490
7491 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007492 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007493 CHECK_ERROR;
7494
7495 if (CUR != ']') {
7496 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7497 }
7498
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007499 if (filter)
7500 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7501 else
7502 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007503
7504 NEXT;
7505 SKIP_BLANKS;
7506}
7507
7508/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007509 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007510 * @ctxt: the XPath Parser context
7511 * @test: pointer to a xmlXPathTestVal
7512 * @type: pointer to a xmlXPathTypeVal
7513 * @prefix: placeholder for a possible name prefix
7514 *
7515 * [7] NodeTest ::= NameTest
7516 * | NodeType '(' ')'
7517 * | 'processing-instruction' '(' Literal ')'
7518 *
7519 * [37] NameTest ::= '*'
7520 * | NCName ':' '*'
7521 * | QName
7522 * [38] NodeType ::= 'comment'
7523 * | 'text'
7524 * | 'processing-instruction'
7525 * | 'node'
7526 *
7527 * Returns the name found and update @test, @type and @prefix appropriately
7528 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007529static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007530xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7531 xmlXPathTypeVal *type, const xmlChar **prefix,
7532 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007533 int blanks;
7534
7535 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7536 STRANGE;
7537 return(NULL);
7538 }
7539 *type = 0;
7540 *test = 0;
7541 *prefix = NULL;
7542 SKIP_BLANKS;
7543
7544 if ((name == NULL) && (CUR == '*')) {
7545 /*
7546 * All elements
7547 */
7548 NEXT;
7549 *test = NODE_TEST_ALL;
7550 return(NULL);
7551 }
7552
7553 if (name == NULL)
7554 name = xmlXPathParseNCName(ctxt);
7555 if (name == NULL) {
7556 XP_ERROR0(XPATH_EXPR_ERROR);
7557 }
7558
7559 blanks = IS_BLANK(CUR);
7560 SKIP_BLANKS;
7561 if (CUR == '(') {
7562 NEXT;
7563 /*
7564 * NodeType or PI search
7565 */
7566 if (xmlStrEqual(name, BAD_CAST "comment"))
7567 *type = NODE_TYPE_COMMENT;
7568 else if (xmlStrEqual(name, BAD_CAST "node"))
7569 *type = NODE_TYPE_NODE;
7570 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7571 *type = NODE_TYPE_PI;
7572 else if (xmlStrEqual(name, BAD_CAST "text"))
7573 *type = NODE_TYPE_TEXT;
7574 else {
7575 if (name != NULL)
7576 xmlFree(name);
7577 XP_ERROR0(XPATH_EXPR_ERROR);
7578 }
7579
7580 *test = NODE_TEST_TYPE;
7581
7582 SKIP_BLANKS;
7583 if (*type == NODE_TYPE_PI) {
7584 /*
7585 * Specific case: search a PI by name.
7586 */
Owen Taylor3473f882001-02-23 17:55:21 +00007587 if (name != NULL)
7588 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007589 name = NULL;
7590 if (CUR != ')') {
7591 name = xmlXPathParseLiteral(ctxt);
7592 CHECK_ERROR 0;
7593 SKIP_BLANKS;
7594 }
Owen Taylor3473f882001-02-23 17:55:21 +00007595 }
7596 if (CUR != ')') {
7597 if (name != NULL)
7598 xmlFree(name);
7599 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7600 }
7601 NEXT;
7602 return(name);
7603 }
7604 *test = NODE_TEST_NAME;
7605 if ((!blanks) && (CUR == ':')) {
7606 NEXT;
7607
7608 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007609 * Since currently the parser context don't have a
7610 * namespace list associated:
7611 * The namespace name for this prefix can be computed
7612 * only at evaluation time. The compilation is done
7613 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007614 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007615#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007616 *prefix = xmlXPathNsLookup(ctxt->context, name);
7617 if (name != NULL)
7618 xmlFree(name);
7619 if (*prefix == NULL) {
7620 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7621 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007622#else
7623 *prefix = name;
7624#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007625
7626 if (CUR == '*') {
7627 /*
7628 * All elements
7629 */
7630 NEXT;
7631 *test = NODE_TEST_ALL;
7632 return(NULL);
7633 }
7634
7635 name = xmlXPathParseNCName(ctxt);
7636 if (name == NULL) {
7637 XP_ERROR0(XPATH_EXPR_ERROR);
7638 }
7639 }
7640 return(name);
7641}
7642
7643/**
7644 * xmlXPathIsAxisName:
7645 * @name: a preparsed name token
7646 *
7647 * [6] AxisName ::= 'ancestor'
7648 * | 'ancestor-or-self'
7649 * | 'attribute'
7650 * | 'child'
7651 * | 'descendant'
7652 * | 'descendant-or-self'
7653 * | 'following'
7654 * | 'following-sibling'
7655 * | 'namespace'
7656 * | 'parent'
7657 * | 'preceding'
7658 * | 'preceding-sibling'
7659 * | 'self'
7660 *
7661 * Returns the axis or 0
7662 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007663static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007664xmlXPathIsAxisName(const xmlChar *name) {
7665 xmlXPathAxisVal ret = 0;
7666 switch (name[0]) {
7667 case 'a':
7668 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7669 ret = AXIS_ANCESTOR;
7670 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7671 ret = AXIS_ANCESTOR_OR_SELF;
7672 if (xmlStrEqual(name, BAD_CAST "attribute"))
7673 ret = AXIS_ATTRIBUTE;
7674 break;
7675 case 'c':
7676 if (xmlStrEqual(name, BAD_CAST "child"))
7677 ret = AXIS_CHILD;
7678 break;
7679 case 'd':
7680 if (xmlStrEqual(name, BAD_CAST "descendant"))
7681 ret = AXIS_DESCENDANT;
7682 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7683 ret = AXIS_DESCENDANT_OR_SELF;
7684 break;
7685 case 'f':
7686 if (xmlStrEqual(name, BAD_CAST "following"))
7687 ret = AXIS_FOLLOWING;
7688 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7689 ret = AXIS_FOLLOWING_SIBLING;
7690 break;
7691 case 'n':
7692 if (xmlStrEqual(name, BAD_CAST "namespace"))
7693 ret = AXIS_NAMESPACE;
7694 break;
7695 case 'p':
7696 if (xmlStrEqual(name, BAD_CAST "parent"))
7697 ret = AXIS_PARENT;
7698 if (xmlStrEqual(name, BAD_CAST "preceding"))
7699 ret = AXIS_PRECEDING;
7700 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7701 ret = AXIS_PRECEDING_SIBLING;
7702 break;
7703 case 's':
7704 if (xmlStrEqual(name, BAD_CAST "self"))
7705 ret = AXIS_SELF;
7706 break;
7707 }
7708 return(ret);
7709}
7710
7711/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007712 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007713 * @ctxt: the XPath Parser context
7714 *
7715 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7716 * | AbbreviatedStep
7717 *
7718 * [12] AbbreviatedStep ::= '.' | '..'
7719 *
7720 * [5] AxisSpecifier ::= AxisName '::'
7721 * | AbbreviatedAxisSpecifier
7722 *
7723 * [13] AbbreviatedAxisSpecifier ::= '@'?
7724 *
7725 * Modified for XPtr range support as:
7726 *
7727 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7728 * | AbbreviatedStep
7729 * | 'range-to' '(' Expr ')' Predicate*
7730 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007731 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007732 * A location step of . is short for self::node(). This is
7733 * particularly useful in conjunction with //. For example, the
7734 * location path .//para is short for
7735 * self::node()/descendant-or-self::node()/child::para
7736 * and so will select all para descendant elements of the context
7737 * node.
7738 * Similarly, a location step of .. is short for parent::node().
7739 * For example, ../title is short for parent::node()/child::title
7740 * and so will select the title children of the parent of the context
7741 * node.
7742 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007743static void
7744xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007745#ifdef LIBXML_XPTR_ENABLED
7746 int rangeto = 0;
7747 int op2 = -1;
7748#endif
7749
Owen Taylor3473f882001-02-23 17:55:21 +00007750 SKIP_BLANKS;
7751 if ((CUR == '.') && (NXT(1) == '.')) {
7752 SKIP(2);
7753 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007754 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7755 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007756 } else if (CUR == '.') {
7757 NEXT;
7758 SKIP_BLANKS;
7759 } else {
7760 xmlChar *name = NULL;
7761 const xmlChar *prefix = NULL;
7762 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007763 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007764 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007765 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007766
7767 /*
7768 * The modification needed for XPointer change to the production
7769 */
7770#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007771 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007772 name = xmlXPathParseNCName(ctxt);
7773 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007774 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007775 xmlFree(name);
7776 SKIP_BLANKS;
7777 if (CUR != '(') {
7778 XP_ERROR(XPATH_EXPR_ERROR);
7779 }
7780 NEXT;
7781 SKIP_BLANKS;
7782
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007783 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007784 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007785 CHECK_ERROR;
7786
7787 SKIP_BLANKS;
7788 if (CUR != ')') {
7789 XP_ERROR(XPATH_EXPR_ERROR);
7790 }
7791 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007792 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007793 goto eval_predicates;
7794 }
7795 }
7796#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007797 if (CUR == '*') {
7798 axis = AXIS_CHILD;
7799 } else {
7800 if (name == NULL)
7801 name = xmlXPathParseNCName(ctxt);
7802 if (name != NULL) {
7803 axis = xmlXPathIsAxisName(name);
7804 if (axis != 0) {
7805 SKIP_BLANKS;
7806 if ((CUR == ':') && (NXT(1) == ':')) {
7807 SKIP(2);
7808 xmlFree(name);
7809 name = NULL;
7810 } else {
7811 /* an element name can conflict with an axis one :-\ */
7812 axis = AXIS_CHILD;
7813 }
Owen Taylor3473f882001-02-23 17:55:21 +00007814 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007815 axis = AXIS_CHILD;
7816 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007817 } else if (CUR == '@') {
7818 NEXT;
7819 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007820 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007821 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007822 }
Owen Taylor3473f882001-02-23 17:55:21 +00007823 }
7824
7825 CHECK_ERROR;
7826
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007827 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007828 if (test == 0)
7829 return;
7830
7831#ifdef DEBUG_STEP
7832 xmlGenericError(xmlGenericErrorContext,
7833 "Basis : computing new set\n");
7834#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007835
Owen Taylor3473f882001-02-23 17:55:21 +00007836#ifdef DEBUG_STEP
7837 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007838 if (ctxt->value == NULL)
7839 xmlGenericError(xmlGenericErrorContext, "no value\n");
7840 else if (ctxt->value->nodesetval == NULL)
7841 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7842 else
7843 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007844#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007845
7846eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007847 op1 = ctxt->comp->last;
7848 ctxt->comp->last = -1;
7849
Owen Taylor3473f882001-02-23 17:55:21 +00007850 SKIP_BLANKS;
7851 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007852 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007853 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007854
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007855#ifdef LIBXML_XPTR_ENABLED
7856 if (rangeto) {
7857 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7858 } else
7859#endif
7860 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7861 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007862
Owen Taylor3473f882001-02-23 17:55:21 +00007863 }
7864#ifdef DEBUG_STEP
7865 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007866 if (ctxt->value == NULL)
7867 xmlGenericError(xmlGenericErrorContext, "no value\n");
7868 else if (ctxt->value->nodesetval == NULL)
7869 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7870 else
7871 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7872 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007873#endif
7874}
7875
7876/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007877 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007878 * @ctxt: the XPath Parser context
7879 *
7880 * [3] RelativeLocationPath ::= Step
7881 * | RelativeLocationPath '/' Step
7882 * | AbbreviatedRelativeLocationPath
7883 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007885 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007886 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007887static void
Owen Taylor3473f882001-02-23 17:55:21 +00007888#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007889xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007890#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007891xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007892#endif
7893(xmlXPathParserContextPtr ctxt) {
7894 SKIP_BLANKS;
7895 if ((CUR == '/') && (NXT(1) == '/')) {
7896 SKIP(2);
7897 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007898 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7899 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007900 } else if (CUR == '/') {
7901 NEXT;
7902 SKIP_BLANKS;
7903 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007904 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007905 SKIP_BLANKS;
7906 while (CUR == '/') {
7907 if ((CUR == '/') && (NXT(1) == '/')) {
7908 SKIP(2);
7909 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007910 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007911 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007912 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007913 } else if (CUR == '/') {
7914 NEXT;
7915 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007916 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007917 }
7918 SKIP_BLANKS;
7919 }
7920}
7921
7922/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007923 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007924 * @ctxt: the XPath Parser context
7925 *
7926 * [1] LocationPath ::= RelativeLocationPath
7927 * | AbsoluteLocationPath
7928 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7929 * | AbbreviatedAbsoluteLocationPath
7930 * [10] AbbreviatedAbsoluteLocationPath ::=
7931 * '//' RelativeLocationPath
7932 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007933 * Compile a location path
7934 *
Owen Taylor3473f882001-02-23 17:55:21 +00007935 * // is short for /descendant-or-self::node()/. For example,
7936 * //para is short for /descendant-or-self::node()/child::para and
7937 * so will select any para element in the document (even a para element
7938 * that is a document element will be selected by //para since the
7939 * document element node is a child of the root node); div//para is
7940 * short for div/descendant-or-self::node()/child::para and so will
7941 * select all para descendants of div children.
7942 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007943static void
7944xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007945 SKIP_BLANKS;
7946 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007947 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007948 } else {
7949 while (CUR == '/') {
7950 if ((CUR == '/') && (NXT(1) == '/')) {
7951 SKIP(2);
7952 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007953 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7954 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007955 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007956 } else if (CUR == '/') {
7957 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007958 SKIP_BLANKS;
7959 if ((CUR != 0 ) &&
7960 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7961 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007962 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007963 }
7964 }
7965 }
7966}
7967
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007968/************************************************************************
7969 * *
7970 * XPath precompiled expression evaluation *
7971 * *
7972 ************************************************************************/
7973
Daniel Veillardf06307e2001-07-03 10:35:50 +00007974static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007975xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7976
7977/**
7978 * xmlXPathNodeCollectAndTest:
7979 * @ctxt: the XPath Parser context
7980 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007981 * @first: pointer to the first element in document order
7982 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007983 *
7984 * This is the function implementing a step: based on the current list
7985 * of nodes, it builds up a new list, looking at all nodes under that
7986 * axis and selecting them it also do the predicate filtering
7987 *
7988 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007989 *
7990 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007991 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007992static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007993xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007994 xmlXPathStepOpPtr op,
7995 xmlNodePtr * first, xmlNodePtr * last)
7996{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007997 xmlXPathAxisVal axis = op->value;
7998 xmlXPathTestVal test = op->value2;
7999 xmlXPathTypeVal type = op->value3;
8000 const xmlChar *prefix = op->value4;
8001 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008002 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008003
8004#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008005 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008006#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008007 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008008 xmlNodeSetPtr ret, list;
8009 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008010 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008011 xmlNodePtr cur = NULL;
8012 xmlXPathObjectPtr obj;
8013 xmlNodeSetPtr nodelist;
8014 xmlNodePtr tmp;
8015
Daniel Veillardf06307e2001-07-03 10:35:50 +00008016 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008017 obj = valuePop(ctxt);
8018 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008019 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008020 URI = xmlXPathNsLookup(ctxt->context, prefix);
8021 if (URI == NULL)
8022 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008023 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008024#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008025 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008026#endif
8027 switch (axis) {
8028 case AXIS_ANCESTOR:
8029#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008030 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008031#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008032 first = NULL;
8033 next = xmlXPathNextAncestor;
8034 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008035 case AXIS_ANCESTOR_OR_SELF:
8036#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008037 xmlGenericError(xmlGenericErrorContext,
8038 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008039#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008040 first = NULL;
8041 next = xmlXPathNextAncestorOrSelf;
8042 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008043 case AXIS_ATTRIBUTE:
8044#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008045 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008046#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008047 first = NULL;
8048 last = NULL;
8049 next = xmlXPathNextAttribute;
8050 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008051 case AXIS_CHILD:
8052#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008053 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008054#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008055 last = NULL;
8056 next = xmlXPathNextChild;
8057 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008058 case AXIS_DESCENDANT:
8059#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008060 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008061#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008062 last = NULL;
8063 next = xmlXPathNextDescendant;
8064 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008065 case AXIS_DESCENDANT_OR_SELF:
8066#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008067 xmlGenericError(xmlGenericErrorContext,
8068 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008069#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008070 last = NULL;
8071 next = xmlXPathNextDescendantOrSelf;
8072 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008073 case AXIS_FOLLOWING:
8074#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008075 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008076#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008077 last = NULL;
8078 next = xmlXPathNextFollowing;
8079 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008080 case AXIS_FOLLOWING_SIBLING:
8081#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008082 xmlGenericError(xmlGenericErrorContext,
8083 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008084#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008085 last = NULL;
8086 next = xmlXPathNextFollowingSibling;
8087 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008088 case AXIS_NAMESPACE:
8089#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008090 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008091#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008092 first = NULL;
8093 last = NULL;
8094 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8095 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008096 case AXIS_PARENT:
8097#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008098 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008099#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008100 first = NULL;
8101 next = xmlXPathNextParent;
8102 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008103 case AXIS_PRECEDING:
8104#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008105 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008106#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008107 first = NULL;
8108 next = xmlXPathNextPrecedingInternal;
8109 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008110 case AXIS_PRECEDING_SIBLING:
8111#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008112 xmlGenericError(xmlGenericErrorContext,
8113 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008114#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008115 first = NULL;
8116 next = xmlXPathNextPrecedingSibling;
8117 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008118 case AXIS_SELF:
8119#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008120 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008121#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008122 first = NULL;
8123 last = NULL;
8124 next = xmlXPathNextSelf;
8125 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008126 }
8127 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008128 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008129
8130 nodelist = obj->nodesetval;
8131 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008132 xmlXPathFreeObject(obj);
8133 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8134 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008135 }
8136 addNode = xmlXPathNodeSetAddUnique;
8137 ret = NULL;
8138#ifdef DEBUG_STEP
8139 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008140 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008141 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008142 case NODE_TEST_NONE:
8143 xmlGenericError(xmlGenericErrorContext,
8144 " searching for none !!!\n");
8145 break;
8146 case NODE_TEST_TYPE:
8147 xmlGenericError(xmlGenericErrorContext,
8148 " searching for type %d\n", type);
8149 break;
8150 case NODE_TEST_PI:
8151 xmlGenericError(xmlGenericErrorContext,
8152 " searching for PI !!!\n");
8153 break;
8154 case NODE_TEST_ALL:
8155 xmlGenericError(xmlGenericErrorContext,
8156 " searching for *\n");
8157 break;
8158 case NODE_TEST_NS:
8159 xmlGenericError(xmlGenericErrorContext,
8160 " searching for namespace %s\n",
8161 prefix);
8162 break;
8163 case NODE_TEST_NAME:
8164 xmlGenericError(xmlGenericErrorContext,
8165 " searching for name %s\n", name);
8166 if (prefix != NULL)
8167 xmlGenericError(xmlGenericErrorContext,
8168 " with namespace %s\n", prefix);
8169 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008170 }
8171 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8172#endif
8173 /*
8174 * 2.3 Node Tests
8175 * - For the attribute axis, the principal node type is attribute.
8176 * - For the namespace axis, the principal node type is namespace.
8177 * - For other axes, the principal node type is element.
8178 *
8179 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008180 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008181 * select all element children of the context node
8182 */
8183 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008184 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008185 ctxt->context->node = nodelist->nodeTab[i];
8186
Daniel Veillardf06307e2001-07-03 10:35:50 +00008187 cur = NULL;
8188 list = xmlXPathNodeSetCreate(NULL);
8189 do {
8190 cur = next(ctxt, cur);
8191 if (cur == NULL)
8192 break;
8193 if ((first != NULL) && (*first == cur))
8194 break;
8195 if (((t % 256) == 0) &&
8196 (first != NULL) && (*first != NULL) &&
8197 (xmlXPathCmpNodes(*first, cur) >= 0))
8198 break;
8199 if ((last != NULL) && (*last == cur))
8200 break;
8201 if (((t % 256) == 0) &&
8202 (last != NULL) && (*last != NULL) &&
8203 (xmlXPathCmpNodes(cur, *last) >= 0))
8204 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008205 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008206#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008207 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8208#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008209 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008210 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008211 ctxt->context->node = tmp;
8212 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008213 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008214 if ((cur->type == type) ||
8215 ((type == NODE_TYPE_NODE) &&
8216 ((cur->type == XML_DOCUMENT_NODE) ||
8217 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8218 (cur->type == XML_ELEMENT_NODE) ||
8219 (cur->type == XML_PI_NODE) ||
8220 (cur->type == XML_COMMENT_NODE) ||
8221 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008222 (cur->type == XML_TEXT_NODE))) ||
8223 ((type == NODE_TYPE_TEXT) &&
8224 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008225#ifdef DEBUG_STEP
8226 n++;
8227#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008228 addNode(list, cur);
8229 }
8230 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008231 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008232 if (cur->type == XML_PI_NODE) {
8233 if ((name != NULL) &&
8234 (!xmlStrEqual(name, cur->name)))
8235 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008236#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008237 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008238#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008239 addNode(list, cur);
8240 }
8241 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008242 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008243 if (axis == AXIS_ATTRIBUTE) {
8244 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008245#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008246 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008247#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008248 addNode(list, cur);
8249 }
8250 } else if (axis == AXIS_NAMESPACE) {
8251 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008252#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008253 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008254#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008255 addNode(list, cur);
8256 }
8257 } else {
8258 if (cur->type == XML_ELEMENT_NODE) {
8259 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008260#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008261 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008262#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008263 addNode(list, cur);
8264 } else if ((cur->ns != NULL) &&
8265 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008266#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008267 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008268#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008269 addNode(list, cur);
8270 }
8271 }
8272 }
8273 break;
8274 case NODE_TEST_NS:{
8275 TODO;
8276 break;
8277 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008278 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008279 switch (cur->type) {
8280 case XML_ELEMENT_NODE:
8281 if (xmlStrEqual(name, cur->name)) {
8282 if (prefix == NULL) {
8283 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008284#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008285 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008286#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008287 addNode(list, cur);
8288 }
8289 } else {
8290 if ((cur->ns != NULL) &&
8291 (xmlStrEqual(URI,
8292 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008293#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008294 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008295#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008296 addNode(list, cur);
8297 }
8298 }
8299 }
8300 break;
8301 case XML_ATTRIBUTE_NODE:{
8302 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008303
Daniel Veillardf06307e2001-07-03 10:35:50 +00008304 if (xmlStrEqual(name, attr->name)) {
8305 if (prefix == NULL) {
8306 if ((attr->ns == NULL) ||
8307 (attr->ns->prefix == NULL)) {
8308#ifdef DEBUG_STEP
8309 n++;
8310#endif
8311 addNode(list,
8312 (xmlNodePtr) attr);
8313 }
8314 } else {
8315 if ((attr->ns != NULL) &&
8316 (xmlStrEqual(URI,
8317 attr->ns->
8318 href))) {
8319#ifdef DEBUG_STEP
8320 n++;
8321#endif
8322 addNode(list,
8323 (xmlNodePtr) attr);
8324 }
8325 }
8326 }
8327 break;
8328 }
8329 case XML_NAMESPACE_DECL:
8330 if (cur->type == XML_NAMESPACE_DECL) {
8331 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008332
Daniel Veillardf06307e2001-07-03 10:35:50 +00008333 if ((ns->prefix != NULL) && (name != NULL)
8334 && (xmlStrEqual(ns->prefix, name))) {
8335#ifdef DEBUG_STEP
8336 n++;
8337#endif
8338 addNode(list, cur);
8339 }
8340 }
8341 break;
8342 default:
8343 break;
8344 }
8345 break;
8346 break;
8347 }
8348 } while (cur != NULL);
8349
8350 /*
8351 * If there is some predicate filtering do it now
8352 */
8353 if (op->ch2 != -1) {
8354 xmlXPathObjectPtr obj2;
8355
8356 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8357 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8358 CHECK_TYPE0(XPATH_NODESET);
8359 obj2 = valuePop(ctxt);
8360 list = obj2->nodesetval;
8361 obj2->nodesetval = NULL;
8362 xmlXPathFreeObject(obj2);
8363 }
8364 if (ret == NULL) {
8365 ret = list;
8366 } else {
8367 ret = xmlXPathNodeSetMerge(ret, list);
8368 xmlXPathFreeNodeSet(list);
8369 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008370 }
8371 ctxt->context->node = tmp;
8372#ifdef DEBUG_STEP
8373 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008374 "\nExamined %d nodes, found %d nodes at that step\n",
8375 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008376#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008377 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008378 if ((obj->boolval) && (obj->user != NULL)) {
8379 ctxt->value->boolval = 1;
8380 ctxt->value->user = obj->user;
8381 obj->user = NULL;
8382 obj->boolval = 0;
8383 }
8384 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008385 return(t);
8386}
8387
8388/**
8389 * xmlXPathNodeCollectAndTestNth:
8390 * @ctxt: the XPath Parser context
8391 * @op: the XPath precompiled step operation
8392 * @indx: the index to collect
8393 * @first: pointer to the first element in document order
8394 * @last: pointer to the last element in document order
8395 *
8396 * This is the function implementing a step: based on the current list
8397 * of nodes, it builds up a new list, looking at all nodes under that
8398 * axis and selecting them it also do the predicate filtering
8399 *
8400 * Pushes the new NodeSet resulting from the search.
8401 * Returns the number of node traversed
8402 */
8403static int
8404xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8405 xmlXPathStepOpPtr op, int indx,
8406 xmlNodePtr * first, xmlNodePtr * last)
8407{
8408 xmlXPathAxisVal axis = op->value;
8409 xmlXPathTestVal test = op->value2;
8410 xmlXPathTypeVal type = op->value3;
8411 const xmlChar *prefix = op->value4;
8412 const xmlChar *name = op->value5;
8413 const xmlChar *URI = NULL;
8414 int n = 0, t = 0;
8415
8416 int i;
8417 xmlNodeSetPtr list;
8418 xmlXPathTraversalFunction next = NULL;
8419 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8420 xmlNodePtr cur = NULL;
8421 xmlXPathObjectPtr obj;
8422 xmlNodeSetPtr nodelist;
8423 xmlNodePtr tmp;
8424
8425 CHECK_TYPE0(XPATH_NODESET);
8426 obj = valuePop(ctxt);
8427 addNode = xmlXPathNodeSetAdd;
8428 if (prefix != NULL) {
8429 URI = xmlXPathNsLookup(ctxt->context, prefix);
8430 if (URI == NULL)
8431 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8432 }
8433#ifdef DEBUG_STEP_NTH
8434 xmlGenericError(xmlGenericErrorContext, "new step : ");
8435 if (first != NULL) {
8436 if (*first != NULL)
8437 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8438 (*first)->name);
8439 else
8440 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8441 }
8442 if (last != NULL) {
8443 if (*last != NULL)
8444 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8445 (*last)->name);
8446 else
8447 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8448 }
8449#endif
8450 switch (axis) {
8451 case AXIS_ANCESTOR:
8452#ifdef DEBUG_STEP_NTH
8453 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8454#endif
8455 first = NULL;
8456 next = xmlXPathNextAncestor;
8457 break;
8458 case AXIS_ANCESTOR_OR_SELF:
8459#ifdef DEBUG_STEP_NTH
8460 xmlGenericError(xmlGenericErrorContext,
8461 "axis 'ancestors-or-self' ");
8462#endif
8463 first = NULL;
8464 next = xmlXPathNextAncestorOrSelf;
8465 break;
8466 case AXIS_ATTRIBUTE:
8467#ifdef DEBUG_STEP_NTH
8468 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8469#endif
8470 first = NULL;
8471 last = NULL;
8472 next = xmlXPathNextAttribute;
8473 break;
8474 case AXIS_CHILD:
8475#ifdef DEBUG_STEP_NTH
8476 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8477#endif
8478 last = NULL;
8479 next = xmlXPathNextChild;
8480 break;
8481 case AXIS_DESCENDANT:
8482#ifdef DEBUG_STEP_NTH
8483 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8484#endif
8485 last = NULL;
8486 next = xmlXPathNextDescendant;
8487 break;
8488 case AXIS_DESCENDANT_OR_SELF:
8489#ifdef DEBUG_STEP_NTH
8490 xmlGenericError(xmlGenericErrorContext,
8491 "axis 'descendant-or-self' ");
8492#endif
8493 last = NULL;
8494 next = xmlXPathNextDescendantOrSelf;
8495 break;
8496 case AXIS_FOLLOWING:
8497#ifdef DEBUG_STEP_NTH
8498 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8499#endif
8500 last = NULL;
8501 next = xmlXPathNextFollowing;
8502 break;
8503 case AXIS_FOLLOWING_SIBLING:
8504#ifdef DEBUG_STEP_NTH
8505 xmlGenericError(xmlGenericErrorContext,
8506 "axis 'following-siblings' ");
8507#endif
8508 last = NULL;
8509 next = xmlXPathNextFollowingSibling;
8510 break;
8511 case AXIS_NAMESPACE:
8512#ifdef DEBUG_STEP_NTH
8513 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8514#endif
8515 last = NULL;
8516 first = NULL;
8517 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8518 break;
8519 case AXIS_PARENT:
8520#ifdef DEBUG_STEP_NTH
8521 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8522#endif
8523 first = NULL;
8524 next = xmlXPathNextParent;
8525 break;
8526 case AXIS_PRECEDING:
8527#ifdef DEBUG_STEP_NTH
8528 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8529#endif
8530 first = NULL;
8531 next = xmlXPathNextPrecedingInternal;
8532 break;
8533 case AXIS_PRECEDING_SIBLING:
8534#ifdef DEBUG_STEP_NTH
8535 xmlGenericError(xmlGenericErrorContext,
8536 "axis 'preceding-sibling' ");
8537#endif
8538 first = NULL;
8539 next = xmlXPathNextPrecedingSibling;
8540 break;
8541 case AXIS_SELF:
8542#ifdef DEBUG_STEP_NTH
8543 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8544#endif
8545 first = NULL;
8546 last = NULL;
8547 next = xmlXPathNextSelf;
8548 break;
8549 }
8550 if (next == NULL)
8551 return(0);
8552
8553 nodelist = obj->nodesetval;
8554 if (nodelist == NULL) {
8555 xmlXPathFreeObject(obj);
8556 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8557 return(0);
8558 }
8559 addNode = xmlXPathNodeSetAddUnique;
8560#ifdef DEBUG_STEP_NTH
8561 xmlGenericError(xmlGenericErrorContext,
8562 " context contains %d nodes\n", nodelist->nodeNr);
8563 switch (test) {
8564 case NODE_TEST_NONE:
8565 xmlGenericError(xmlGenericErrorContext,
8566 " searching for none !!!\n");
8567 break;
8568 case NODE_TEST_TYPE:
8569 xmlGenericError(xmlGenericErrorContext,
8570 " searching for type %d\n", type);
8571 break;
8572 case NODE_TEST_PI:
8573 xmlGenericError(xmlGenericErrorContext,
8574 " searching for PI !!!\n");
8575 break;
8576 case NODE_TEST_ALL:
8577 xmlGenericError(xmlGenericErrorContext,
8578 " searching for *\n");
8579 break;
8580 case NODE_TEST_NS:
8581 xmlGenericError(xmlGenericErrorContext,
8582 " searching for namespace %s\n",
8583 prefix);
8584 break;
8585 case NODE_TEST_NAME:
8586 xmlGenericError(xmlGenericErrorContext,
8587 " searching for name %s\n", name);
8588 if (prefix != NULL)
8589 xmlGenericError(xmlGenericErrorContext,
8590 " with namespace %s\n", prefix);
8591 break;
8592 }
8593 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8594#endif
8595 /*
8596 * 2.3 Node Tests
8597 * - For the attribute axis, the principal node type is attribute.
8598 * - For the namespace axis, the principal node type is namespace.
8599 * - For other axes, the principal node type is element.
8600 *
8601 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008602 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008603 * select all element children of the context node
8604 */
8605 tmp = ctxt->context->node;
8606 list = xmlXPathNodeSetCreate(NULL);
8607 for (i = 0; i < nodelist->nodeNr; i++) {
8608 ctxt->context->node = nodelist->nodeTab[i];
8609
8610 cur = NULL;
8611 n = 0;
8612 do {
8613 cur = next(ctxt, cur);
8614 if (cur == NULL)
8615 break;
8616 if ((first != NULL) && (*first == cur))
8617 break;
8618 if (((t % 256) == 0) &&
8619 (first != NULL) && (*first != NULL) &&
8620 (xmlXPathCmpNodes(*first, cur) >= 0))
8621 break;
8622 if ((last != NULL) && (*last == cur))
8623 break;
8624 if (((t % 256) == 0) &&
8625 (last != NULL) && (*last != NULL) &&
8626 (xmlXPathCmpNodes(cur, *last) >= 0))
8627 break;
8628 t++;
8629 switch (test) {
8630 case NODE_TEST_NONE:
8631 ctxt->context->node = tmp;
8632 STRANGE return(0);
8633 case NODE_TEST_TYPE:
8634 if ((cur->type == type) ||
8635 ((type == NODE_TYPE_NODE) &&
8636 ((cur->type == XML_DOCUMENT_NODE) ||
8637 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8638 (cur->type == XML_ELEMENT_NODE) ||
8639 (cur->type == XML_PI_NODE) ||
8640 (cur->type == XML_COMMENT_NODE) ||
8641 (cur->type == XML_CDATA_SECTION_NODE) ||
8642 (cur->type == XML_TEXT_NODE)))) {
8643 n++;
8644 if (n == indx)
8645 addNode(list, cur);
8646 }
8647 break;
8648 case NODE_TEST_PI:
8649 if (cur->type == XML_PI_NODE) {
8650 if ((name != NULL) &&
8651 (!xmlStrEqual(name, cur->name)))
8652 break;
8653 n++;
8654 if (n == indx)
8655 addNode(list, cur);
8656 }
8657 break;
8658 case NODE_TEST_ALL:
8659 if (axis == AXIS_ATTRIBUTE) {
8660 if (cur->type == XML_ATTRIBUTE_NODE) {
8661 n++;
8662 if (n == indx)
8663 addNode(list, cur);
8664 }
8665 } else if (axis == AXIS_NAMESPACE) {
8666 if (cur->type == XML_NAMESPACE_DECL) {
8667 n++;
8668 if (n == indx)
8669 addNode(list, cur);
8670 }
8671 } else {
8672 if (cur->type == XML_ELEMENT_NODE) {
8673 if (prefix == NULL) {
8674 n++;
8675 if (n == indx)
8676 addNode(list, cur);
8677 } else if ((cur->ns != NULL) &&
8678 (xmlStrEqual(URI, cur->ns->href))) {
8679 n++;
8680 if (n == indx)
8681 addNode(list, cur);
8682 }
8683 }
8684 }
8685 break;
8686 case NODE_TEST_NS:{
8687 TODO;
8688 break;
8689 }
8690 case NODE_TEST_NAME:
8691 switch (cur->type) {
8692 case XML_ELEMENT_NODE:
8693 if (xmlStrEqual(name, cur->name)) {
8694 if (prefix == NULL) {
8695 if (cur->ns == NULL) {
8696 n++;
8697 if (n == indx)
8698 addNode(list, cur);
8699 }
8700 } else {
8701 if ((cur->ns != NULL) &&
8702 (xmlStrEqual(URI,
8703 cur->ns->href))) {
8704 n++;
8705 if (n == indx)
8706 addNode(list, cur);
8707 }
8708 }
8709 }
8710 break;
8711 case XML_ATTRIBUTE_NODE:{
8712 xmlAttrPtr attr = (xmlAttrPtr) cur;
8713
8714 if (xmlStrEqual(name, attr->name)) {
8715 if (prefix == NULL) {
8716 if ((attr->ns == NULL) ||
8717 (attr->ns->prefix == NULL)) {
8718 n++;
8719 if (n == indx)
8720 addNode(list, cur);
8721 }
8722 } else {
8723 if ((attr->ns != NULL) &&
8724 (xmlStrEqual(URI,
8725 attr->ns->
8726 href))) {
8727 n++;
8728 if (n == indx)
8729 addNode(list, cur);
8730 }
8731 }
8732 }
8733 break;
8734 }
8735 case XML_NAMESPACE_DECL:
8736 if (cur->type == XML_NAMESPACE_DECL) {
8737 xmlNsPtr ns = (xmlNsPtr) cur;
8738
8739 if ((ns->prefix != NULL) && (name != NULL)
8740 && (xmlStrEqual(ns->prefix, name))) {
8741 n++;
8742 if (n == indx)
8743 addNode(list, cur);
8744 }
8745 }
8746 break;
8747 default:
8748 break;
8749 }
8750 break;
8751 break;
8752 }
8753 } while (n < indx);
8754 }
8755 ctxt->context->node = tmp;
8756#ifdef DEBUG_STEP_NTH
8757 xmlGenericError(xmlGenericErrorContext,
8758 "\nExamined %d nodes, found %d nodes at that step\n",
8759 t, list->nodeNr);
8760#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008761 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008762 if ((obj->boolval) && (obj->user != NULL)) {
8763 ctxt->value->boolval = 1;
8764 ctxt->value->user = obj->user;
8765 obj->user = NULL;
8766 obj->boolval = 0;
8767 }
8768 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008769 return(t);
8770}
8771
8772/**
8773 * xmlXPathCompOpEvalFirst:
8774 * @ctxt: the XPath parser context with the compiled expression
8775 * @op: an XPath compiled operation
8776 * @first: the first elem found so far
8777 *
8778 * Evaluate the Precompiled XPath operation searching only the first
8779 * element in document order
8780 *
8781 * Returns the number of examined objects.
8782 */
8783static int
8784xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8785 xmlXPathStepOpPtr op, xmlNodePtr * first)
8786{
8787 int total = 0, cur;
8788 xmlXPathCompExprPtr comp;
8789 xmlXPathObjectPtr arg1, arg2;
8790
Daniel Veillard556c6682001-10-06 09:59:51 +00008791 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008792 comp = ctxt->comp;
8793 switch (op->op) {
8794 case XPATH_OP_END:
8795 return (0);
8796 case XPATH_OP_UNION:
8797 total =
8798 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8799 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008800 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008801 if ((ctxt->value != NULL)
8802 && (ctxt->value->type == XPATH_NODESET)
8803 && (ctxt->value->nodesetval != NULL)
8804 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8805 /*
8806 * limit tree traversing to first node in the result
8807 */
8808 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8809 *first = ctxt->value->nodesetval->nodeTab[0];
8810 }
8811 cur =
8812 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8813 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008814 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008815 CHECK_TYPE0(XPATH_NODESET);
8816 arg2 = valuePop(ctxt);
8817
8818 CHECK_TYPE0(XPATH_NODESET);
8819 arg1 = valuePop(ctxt);
8820
8821 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8822 arg2->nodesetval);
8823 valuePush(ctxt, arg1);
8824 xmlXPathFreeObject(arg2);
8825 /* optimizer */
8826 if (total > cur)
8827 xmlXPathCompSwap(op);
8828 return (total + cur);
8829 case XPATH_OP_ROOT:
8830 xmlXPathRoot(ctxt);
8831 return (0);
8832 case XPATH_OP_NODE:
8833 if (op->ch1 != -1)
8834 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008835 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008836 if (op->ch2 != -1)
8837 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008838 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008839 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8840 return (total);
8841 case XPATH_OP_RESET:
8842 if (op->ch1 != -1)
8843 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008844 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008845 if (op->ch2 != -1)
8846 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008847 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008848 ctxt->context->node = NULL;
8849 return (total);
8850 case XPATH_OP_COLLECT:{
8851 if (op->ch1 == -1)
8852 return (total);
8853
8854 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008855 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008856
8857 /*
8858 * Optimization for [n] selection where n is a number
8859 */
8860 if ((op->ch2 != -1) &&
8861 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8862 (comp->steps[op->ch2].ch1 == -1) &&
8863 (comp->steps[op->ch2].ch2 != -1) &&
8864 (comp->steps[comp->steps[op->ch2].ch2].op ==
8865 XPATH_OP_VALUE)) {
8866 xmlXPathObjectPtr val;
8867
8868 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8869 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8870 int indx = (int) val->floatval;
8871
8872 if (val->floatval == (float) indx) {
8873 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8874 first, NULL);
8875 return (total);
8876 }
8877 }
8878 }
8879 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8880 return (total);
8881 }
8882 case XPATH_OP_VALUE:
8883 valuePush(ctxt,
8884 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8885 return (0);
8886 case XPATH_OP_SORT:
8887 if (op->ch1 != -1)
8888 total +=
8889 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8890 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008891 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008892 if ((ctxt->value != NULL)
8893 && (ctxt->value->type == XPATH_NODESET)
8894 && (ctxt->value->nodesetval != NULL))
8895 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8896 return (total);
8897 default:
8898 return (xmlXPathCompOpEval(ctxt, op));
8899 }
8900}
8901
8902/**
8903 * xmlXPathCompOpEvalLast:
8904 * @ctxt: the XPath parser context with the compiled expression
8905 * @op: an XPath compiled operation
8906 * @last: the last elem found so far
8907 *
8908 * Evaluate the Precompiled XPath operation searching only the last
8909 * element in document order
8910 *
8911 * Returns the number of node traversed
8912 */
8913static int
8914xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8915 xmlNodePtr * last)
8916{
8917 int total = 0, cur;
8918 xmlXPathCompExprPtr comp;
8919 xmlXPathObjectPtr arg1, arg2;
8920
Daniel Veillard556c6682001-10-06 09:59:51 +00008921 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008922 comp = ctxt->comp;
8923 switch (op->op) {
8924 case XPATH_OP_END:
8925 return (0);
8926 case XPATH_OP_UNION:
8927 total =
8928 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008929 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008930 if ((ctxt->value != NULL)
8931 && (ctxt->value->type == XPATH_NODESET)
8932 && (ctxt->value->nodesetval != NULL)
8933 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8934 /*
8935 * limit tree traversing to first node in the result
8936 */
8937 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8938 *last =
8939 ctxt->value->nodesetval->nodeTab[ctxt->value->
8940 nodesetval->nodeNr -
8941 1];
8942 }
8943 cur =
8944 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008945 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008946 if ((ctxt->value != NULL)
8947 && (ctxt->value->type == XPATH_NODESET)
8948 && (ctxt->value->nodesetval != NULL)
8949 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8950 }
8951 CHECK_TYPE0(XPATH_NODESET);
8952 arg2 = valuePop(ctxt);
8953
8954 CHECK_TYPE0(XPATH_NODESET);
8955 arg1 = valuePop(ctxt);
8956
8957 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8958 arg2->nodesetval);
8959 valuePush(ctxt, arg1);
8960 xmlXPathFreeObject(arg2);
8961 /* optimizer */
8962 if (total > cur)
8963 xmlXPathCompSwap(op);
8964 return (total + cur);
8965 case XPATH_OP_ROOT:
8966 xmlXPathRoot(ctxt);
8967 return (0);
8968 case XPATH_OP_NODE:
8969 if (op->ch1 != -1)
8970 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008971 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972 if (op->ch2 != -1)
8973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008974 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8976 return (total);
8977 case XPATH_OP_RESET:
8978 if (op->ch1 != -1)
8979 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008980 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 if (op->ch2 != -1)
8982 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008983 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008984 ctxt->context->node = NULL;
8985 return (total);
8986 case XPATH_OP_COLLECT:{
8987 if (op->ch1 == -1)
8988 return (0);
8989
8990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008991 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992
8993 /*
8994 * Optimization for [n] selection where n is a number
8995 */
8996 if ((op->ch2 != -1) &&
8997 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8998 (comp->steps[op->ch2].ch1 == -1) &&
8999 (comp->steps[op->ch2].ch2 != -1) &&
9000 (comp->steps[comp->steps[op->ch2].ch2].op ==
9001 XPATH_OP_VALUE)) {
9002 xmlXPathObjectPtr val;
9003
9004 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9005 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9006 int indx = (int) val->floatval;
9007
9008 if (val->floatval == (float) indx) {
9009 total +=
9010 xmlXPathNodeCollectAndTestNth(ctxt, op,
9011 indx, NULL,
9012 last);
9013 return (total);
9014 }
9015 }
9016 }
9017 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9018 return (total);
9019 }
9020 case XPATH_OP_VALUE:
9021 valuePush(ctxt,
9022 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9023 return (0);
9024 case XPATH_OP_SORT:
9025 if (op->ch1 != -1)
9026 total +=
9027 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9028 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009029 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009030 if ((ctxt->value != NULL)
9031 && (ctxt->value->type == XPATH_NODESET)
9032 && (ctxt->value->nodesetval != NULL))
9033 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9034 return (total);
9035 default:
9036 return (xmlXPathCompOpEval(ctxt, op));
9037 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009038}
9039
Owen Taylor3473f882001-02-23 17:55:21 +00009040/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009041 * xmlXPathCompOpEval:
9042 * @ctxt: the XPath parser context with the compiled expression
9043 * @op: an XPath compiled operation
9044 *
9045 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009047 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009048static int
9049xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9050{
9051 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009052 int equal, ret;
9053 xmlXPathCompExprPtr comp;
9054 xmlXPathObjectPtr arg1, arg2;
9055
Daniel Veillard556c6682001-10-06 09:59:51 +00009056 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009057 comp = ctxt->comp;
9058 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009059 case XPATH_OP_END:
9060 return (0);
9061 case XPATH_OP_AND:
9062 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009063 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 xmlXPathBooleanFunction(ctxt, 1);
9065 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9066 return (total);
9067 arg2 = valuePop(ctxt);
9068 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009069 if (ctxt->error) {
9070 xmlXPathFreeObject(arg2);
9071 return(0);
9072 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009073 xmlXPathBooleanFunction(ctxt, 1);
9074 arg1 = valuePop(ctxt);
9075 arg1->boolval &= arg2->boolval;
9076 valuePush(ctxt, arg1);
9077 xmlXPathFreeObject(arg2);
9078 return (total);
9079 case XPATH_OP_OR:
9080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009081 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 xmlXPathBooleanFunction(ctxt, 1);
9083 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9084 return (total);
9085 arg2 = valuePop(ctxt);
9086 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009087 if (ctxt->error) {
9088 xmlXPathFreeObject(arg2);
9089 return(0);
9090 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009091 xmlXPathBooleanFunction(ctxt, 1);
9092 arg1 = valuePop(ctxt);
9093 arg1->boolval |= arg2->boolval;
9094 valuePush(ctxt, arg1);
9095 xmlXPathFreeObject(arg2);
9096 return (total);
9097 case XPATH_OP_EQUAL:
9098 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009099 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009101 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009102 equal = xmlXPathEqualValues(ctxt);
9103 if (op->value)
9104 valuePush(ctxt, xmlXPathNewBoolean(equal));
9105 else
9106 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9107 return (total);
9108 case XPATH_OP_CMP:
9109 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009110 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009112 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009113 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9114 valuePush(ctxt, xmlXPathNewBoolean(ret));
9115 return (total);
9116 case XPATH_OP_PLUS:
9117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009118 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009119 if (op->ch2 != -1)
9120 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009121 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009122 if (op->value == 0)
9123 xmlXPathSubValues(ctxt);
9124 else if (op->value == 1)
9125 xmlXPathAddValues(ctxt);
9126 else if (op->value == 2)
9127 xmlXPathValueFlipSign(ctxt);
9128 else if (op->value == 3) {
9129 CAST_TO_NUMBER;
9130 CHECK_TYPE0(XPATH_NUMBER);
9131 }
9132 return (total);
9133 case XPATH_OP_MULT:
9134 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009135 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009137 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 if (op->value == 0)
9139 xmlXPathMultValues(ctxt);
9140 else if (op->value == 1)
9141 xmlXPathDivValues(ctxt);
9142 else if (op->value == 2)
9143 xmlXPathModValues(ctxt);
9144 return (total);
9145 case XPATH_OP_UNION:
9146 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009147 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009149 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009150 CHECK_TYPE0(XPATH_NODESET);
9151 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009152
Daniel Veillardf06307e2001-07-03 10:35:50 +00009153 CHECK_TYPE0(XPATH_NODESET);
9154 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009155
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9157 arg2->nodesetval);
9158 valuePush(ctxt, arg1);
9159 xmlXPathFreeObject(arg2);
9160 return (total);
9161 case XPATH_OP_ROOT:
9162 xmlXPathRoot(ctxt);
9163 return (total);
9164 case XPATH_OP_NODE:
9165 if (op->ch1 != -1)
9166 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009167 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 if (op->ch2 != -1)
9169 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009170 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009171 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9172 return (total);
9173 case XPATH_OP_RESET:
9174 if (op->ch1 != -1)
9175 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009176 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009177 if (op->ch2 != -1)
9178 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009179 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 ctxt->context->node = NULL;
9181 return (total);
9182 case XPATH_OP_COLLECT:{
9183 if (op->ch1 == -1)
9184 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009185
Daniel Veillardf06307e2001-07-03 10:35:50 +00009186 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009187 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009188
Daniel Veillardf06307e2001-07-03 10:35:50 +00009189 /*
9190 * Optimization for [n] selection where n is a number
9191 */
9192 if ((op->ch2 != -1) &&
9193 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9194 (comp->steps[op->ch2].ch1 == -1) &&
9195 (comp->steps[op->ch2].ch2 != -1) &&
9196 (comp->steps[comp->steps[op->ch2].ch2].op ==
9197 XPATH_OP_VALUE)) {
9198 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009199
Daniel Veillardf06307e2001-07-03 10:35:50 +00009200 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9201 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9202 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009203
Daniel Veillardf06307e2001-07-03 10:35:50 +00009204 if (val->floatval == (float) indx) {
9205 total +=
9206 xmlXPathNodeCollectAndTestNth(ctxt, op,
9207 indx, NULL,
9208 NULL);
9209 return (total);
9210 }
9211 }
9212 }
9213 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9214 return (total);
9215 }
9216 case XPATH_OP_VALUE:
9217 valuePush(ctxt,
9218 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9219 return (total);
9220 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009221 xmlXPathObjectPtr val;
9222
Daniel Veillardf06307e2001-07-03 10:35:50 +00009223 if (op->ch1 != -1)
9224 total +=
9225 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009226 if (op->value5 == NULL) {
9227 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9228 if (val == NULL) {
9229 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9230 return(0);
9231 }
9232 valuePush(ctxt, val);
9233 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009234 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009235
Daniel Veillardf06307e2001-07-03 10:35:50 +00009236 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9237 if (URI == NULL) {
9238 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009239 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009240 op->value4, op->value5);
9241 return (total);
9242 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009243 val = xmlXPathVariableLookupNS(ctxt->context,
9244 op->value4, URI);
9245 if (val == NULL) {
9246 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9247 return(0);
9248 }
9249 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009250 }
9251 return (total);
9252 }
9253 case XPATH_OP_FUNCTION:{
9254 xmlXPathFunction func;
9255 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009256 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009257
9258 if (op->ch1 != -1)
9259 total +=
9260 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009261 if (ctxt->valueNr < op->value) {
9262 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009263 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009264 ctxt->error = XPATH_INVALID_OPERAND;
9265 return (total);
9266 }
9267 for (i = 0; i < op->value; i++)
9268 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9269 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009270 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009271 ctxt->error = XPATH_INVALID_OPERAND;
9272 return (total);
9273 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009274 if (op->cache != NULL)
9275 func = (xmlXPathFunction) op->cache;
9276 else {
9277 const xmlChar *URI = NULL;
9278
9279 if (op->value5 == NULL)
9280 func =
9281 xmlXPathFunctionLookup(ctxt->context,
9282 op->value4);
9283 else {
9284 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9285 if (URI == NULL) {
9286 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009287 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009288 op->value4, op->value5);
9289 return (total);
9290 }
9291 func = xmlXPathFunctionLookupNS(ctxt->context,
9292 op->value4, URI);
9293 }
9294 if (func == NULL) {
9295 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009296 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009297 op->value4);
9298 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009299 }
9300 op->cache = (void *) func;
9301 op->cacheURI = (void *) URI;
9302 }
9303 oldFunc = ctxt->context->function;
9304 oldFuncURI = ctxt->context->functionURI;
9305 ctxt->context->function = op->value4;
9306 ctxt->context->functionURI = op->cacheURI;
9307 func(ctxt, op->value);
9308 ctxt->context->function = oldFunc;
9309 ctxt->context->functionURI = oldFuncURI;
9310 return (total);
9311 }
9312 case XPATH_OP_ARG:
9313 if (op->ch1 != -1)
9314 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009315 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009316 if (op->ch2 != -1)
9317 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 return (total);
9320 case XPATH_OP_PREDICATE:
9321 case XPATH_OP_FILTER:{
9322 xmlXPathObjectPtr res;
9323 xmlXPathObjectPtr obj, tmp;
9324 xmlNodeSetPtr newset = NULL;
9325 xmlNodeSetPtr oldset;
9326 xmlNodePtr oldnode;
9327 int i;
9328
9329 /*
9330 * Optimization for ()[1] selection i.e. the first elem
9331 */
9332 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9333 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9334 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9335 xmlXPathObjectPtr val;
9336
9337 val = comp->steps[op->ch2].value4;
9338 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9339 (val->floatval == 1.0)) {
9340 xmlNodePtr first = NULL;
9341
9342 total +=
9343 xmlXPathCompOpEvalFirst(ctxt,
9344 &comp->steps[op->ch1],
9345 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009346 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009347 /*
9348 * The nodeset should be in document order,
9349 * Keep only the first value
9350 */
9351 if ((ctxt->value != NULL) &&
9352 (ctxt->value->type == XPATH_NODESET) &&
9353 (ctxt->value->nodesetval != NULL) &&
9354 (ctxt->value->nodesetval->nodeNr > 1))
9355 ctxt->value->nodesetval->nodeNr = 1;
9356 return (total);
9357 }
9358 }
9359 /*
9360 * Optimization for ()[last()] selection i.e. the last elem
9361 */
9362 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9363 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9364 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9365 int f = comp->steps[op->ch2].ch1;
9366
9367 if ((f != -1) &&
9368 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9369 (comp->steps[f].value5 == NULL) &&
9370 (comp->steps[f].value == 0) &&
9371 (comp->steps[f].value4 != NULL) &&
9372 (xmlStrEqual
9373 (comp->steps[f].value4, BAD_CAST "last"))) {
9374 xmlNodePtr last = NULL;
9375
9376 total +=
9377 xmlXPathCompOpEvalLast(ctxt,
9378 &comp->steps[op->ch1],
9379 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009380 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009381 /*
9382 * The nodeset should be in document order,
9383 * Keep only the last value
9384 */
9385 if ((ctxt->value != NULL) &&
9386 (ctxt->value->type == XPATH_NODESET) &&
9387 (ctxt->value->nodesetval != NULL) &&
9388 (ctxt->value->nodesetval->nodeTab != NULL) &&
9389 (ctxt->value->nodesetval->nodeNr > 1)) {
9390 ctxt->value->nodesetval->nodeTab[0] =
9391 ctxt->value->nodesetval->nodeTab[ctxt->
9392 value->
9393 nodesetval->
9394 nodeNr -
9395 1];
9396 ctxt->value->nodesetval->nodeNr = 1;
9397 }
9398 return (total);
9399 }
9400 }
9401
9402 if (op->ch1 != -1)
9403 total +=
9404 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009405 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009406 if (op->ch2 == -1)
9407 return (total);
9408 if (ctxt->value == NULL)
9409 return (total);
9410
9411 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009412
9413#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009414 /*
9415 * Hum are we filtering the result of an XPointer expression
9416 */
9417 if (ctxt->value->type == XPATH_LOCATIONSET) {
9418 xmlLocationSetPtr newlocset = NULL;
9419 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009420
Daniel Veillardf06307e2001-07-03 10:35:50 +00009421 /*
9422 * Extract the old locset, and then evaluate the result of the
9423 * expression for all the element in the locset. use it to grow
9424 * up a new locset.
9425 */
9426 CHECK_TYPE0(XPATH_LOCATIONSET);
9427 obj = valuePop(ctxt);
9428 oldlocset = obj->user;
9429 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009430
Daniel Veillardf06307e2001-07-03 10:35:50 +00009431 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9432 ctxt->context->contextSize = 0;
9433 ctxt->context->proximityPosition = 0;
9434 if (op->ch2 != -1)
9435 total +=
9436 xmlXPathCompOpEval(ctxt,
9437 &comp->steps[op->ch2]);
9438 res = valuePop(ctxt);
9439 if (res != NULL)
9440 xmlXPathFreeObject(res);
9441 valuePush(ctxt, obj);
9442 CHECK_ERROR0;
9443 return (total);
9444 }
9445 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009446
Daniel Veillardf06307e2001-07-03 10:35:50 +00009447 for (i = 0; i < oldlocset->locNr; i++) {
9448 /*
9449 * Run the evaluation with a node list made of a
9450 * single item in the nodelocset.
9451 */
9452 ctxt->context->node = oldlocset->locTab[i]->user;
9453 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9454 valuePush(ctxt, tmp);
9455 ctxt->context->contextSize = oldlocset->locNr;
9456 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009457
Daniel Veillardf06307e2001-07-03 10:35:50 +00009458 if (op->ch2 != -1)
9459 total +=
9460 xmlXPathCompOpEval(ctxt,
9461 &comp->steps[op->ch2]);
9462 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009463
Daniel Veillardf06307e2001-07-03 10:35:50 +00009464 /*
9465 * The result of the evaluation need to be tested to
9466 * decided whether the filter succeeded or not
9467 */
9468 res = valuePop(ctxt);
9469 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9470 xmlXPtrLocationSetAdd(newlocset,
9471 xmlXPathObjectCopy
9472 (oldlocset->locTab[i]));
9473 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009474
Daniel Veillardf06307e2001-07-03 10:35:50 +00009475 /*
9476 * Cleanup
9477 */
9478 if (res != NULL)
9479 xmlXPathFreeObject(res);
9480 if (ctxt->value == tmp) {
9481 res = valuePop(ctxt);
9482 xmlXPathFreeObject(res);
9483 }
9484
9485 ctxt->context->node = NULL;
9486 }
9487
9488 /*
9489 * The result is used as the new evaluation locset.
9490 */
9491 xmlXPathFreeObject(obj);
9492 ctxt->context->node = NULL;
9493 ctxt->context->contextSize = -1;
9494 ctxt->context->proximityPosition = -1;
9495 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9496 ctxt->context->node = oldnode;
9497 return (total);
9498 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009499#endif /* LIBXML_XPTR_ENABLED */
9500
Daniel Veillardf06307e2001-07-03 10:35:50 +00009501 /*
9502 * Extract the old set, and then evaluate the result of the
9503 * expression for all the element in the set. use it to grow
9504 * up a new set.
9505 */
9506 CHECK_TYPE0(XPATH_NODESET);
9507 obj = valuePop(ctxt);
9508 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009509
Daniel Veillardf06307e2001-07-03 10:35:50 +00009510 oldnode = ctxt->context->node;
9511 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009512
Daniel Veillardf06307e2001-07-03 10:35:50 +00009513 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9514 ctxt->context->contextSize = 0;
9515 ctxt->context->proximityPosition = 0;
9516 if (op->ch2 != -1)
9517 total +=
9518 xmlXPathCompOpEval(ctxt,
9519 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009520 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 res = valuePop(ctxt);
9522 if (res != NULL)
9523 xmlXPathFreeObject(res);
9524 valuePush(ctxt, obj);
9525 ctxt->context->node = oldnode;
9526 CHECK_ERROR0;
9527 } else {
9528 /*
9529 * Initialize the new set.
9530 */
9531 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009532
Daniel Veillardf06307e2001-07-03 10:35:50 +00009533 for (i = 0; i < oldset->nodeNr; i++) {
9534 /*
9535 * Run the evaluation with a node list made of
9536 * a single item in the nodeset.
9537 */
9538 ctxt->context->node = oldset->nodeTab[i];
9539 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9540 valuePush(ctxt, tmp);
9541 ctxt->context->contextSize = oldset->nodeNr;
9542 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009543
Daniel Veillardf06307e2001-07-03 10:35:50 +00009544 if (op->ch2 != -1)
9545 total +=
9546 xmlXPathCompOpEval(ctxt,
9547 &comp->steps[op->ch2]);
9548 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009549
Daniel Veillardf06307e2001-07-03 10:35:50 +00009550 /*
9551 * The result of the evaluation need to be tested to
9552 * decided whether the filter succeeded or not
9553 */
9554 res = valuePop(ctxt);
9555 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9556 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9557 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009558
Daniel Veillardf06307e2001-07-03 10:35:50 +00009559 /*
9560 * Cleanup
9561 */
9562 if (res != NULL)
9563 xmlXPathFreeObject(res);
9564 if (ctxt->value == tmp) {
9565 res = valuePop(ctxt);
9566 xmlXPathFreeObject(res);
9567 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009568
Daniel Veillardf06307e2001-07-03 10:35:50 +00009569 ctxt->context->node = NULL;
9570 }
9571
9572 /*
9573 * The result is used as the new evaluation set.
9574 */
9575 xmlXPathFreeObject(obj);
9576 ctxt->context->node = NULL;
9577 ctxt->context->contextSize = -1;
9578 ctxt->context->proximityPosition = -1;
9579 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9580 }
9581 ctxt->context->node = oldnode;
9582 return (total);
9583 }
9584 case XPATH_OP_SORT:
9585 if (op->ch1 != -1)
9586 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009587 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009588 if ((ctxt->value != NULL) &&
9589 (ctxt->value->type == XPATH_NODESET) &&
9590 (ctxt->value->nodesetval != NULL))
9591 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9592 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009593#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009594 case XPATH_OP_RANGETO:{
9595 xmlXPathObjectPtr range;
9596 xmlXPathObjectPtr res, obj;
9597 xmlXPathObjectPtr tmp;
9598 xmlLocationSetPtr newset = NULL;
9599 xmlNodeSetPtr oldset;
9600 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009601
Daniel Veillardf06307e2001-07-03 10:35:50 +00009602 if (op->ch1 != -1)
9603 total +=
9604 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9605 if (op->ch2 == -1)
9606 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009607
Daniel Veillardf06307e2001-07-03 10:35:50 +00009608 CHECK_TYPE0(XPATH_NODESET);
9609 obj = valuePop(ctxt);
9610 oldset = obj->nodesetval;
9611 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009612
Daniel Veillardf06307e2001-07-03 10:35:50 +00009613 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009614
Daniel Veillardf06307e2001-07-03 10:35:50 +00009615 if (oldset != NULL) {
9616 for (i = 0; i < oldset->nodeNr; i++) {
9617 /*
9618 * Run the evaluation with a node list made of a single item
9619 * in the nodeset.
9620 */
9621 ctxt->context->node = oldset->nodeTab[i];
9622 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9623 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009624
Daniel Veillardf06307e2001-07-03 10:35:50 +00009625 if (op->ch2 != -1)
9626 total +=
9627 xmlXPathCompOpEval(ctxt,
9628 &comp->steps[op->ch2]);
9629 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009630
Daniel Veillardf06307e2001-07-03 10:35:50 +00009631 /*
9632 * The result of the evaluation need to be tested to
9633 * decided whether the filter succeeded or not
9634 */
9635 res = valuePop(ctxt);
9636 range =
9637 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9638 res);
9639 if (range != NULL) {
9640 xmlXPtrLocationSetAdd(newset, range);
9641 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009642
Daniel Veillardf06307e2001-07-03 10:35:50 +00009643 /*
9644 * Cleanup
9645 */
9646 if (res != NULL)
9647 xmlXPathFreeObject(res);
9648 if (ctxt->value == tmp) {
9649 res = valuePop(ctxt);
9650 xmlXPathFreeObject(res);
9651 }
9652
9653 ctxt->context->node = NULL;
9654 }
9655 }
9656
9657 /*
9658 * The result is used as the new evaluation set.
9659 */
9660 xmlXPathFreeObject(obj);
9661 ctxt->context->node = NULL;
9662 ctxt->context->contextSize = -1;
9663 ctxt->context->proximityPosition = -1;
9664 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9665 return (total);
9666 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009667#endif /* LIBXML_XPTR_ENABLED */
9668 }
9669 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009670 "XPath: unknown precompiled operation %d\n", op->op);
9671 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009672}
9673
9674/**
9675 * xmlXPathRunEval:
9676 * @ctxt: the XPath parser context with the compiled expression
9677 *
9678 * Evaluate the Precompiled XPath expression in the given context.
9679 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009680static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009681xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9682 xmlXPathCompExprPtr comp;
9683
9684 if ((ctxt == NULL) || (ctxt->comp == NULL))
9685 return;
9686
9687 if (ctxt->valueTab == NULL) {
9688 /* Allocate the value stack */
9689 ctxt->valueTab = (xmlXPathObjectPtr *)
9690 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9691 if (ctxt->valueTab == NULL) {
9692 xmlFree(ctxt);
9693 xmlGenericError(xmlGenericErrorContext,
9694 "xmlXPathRunEval: out of memory\n");
9695 return;
9696 }
9697 ctxt->valueNr = 0;
9698 ctxt->valueMax = 10;
9699 ctxt->value = NULL;
9700 }
9701 comp = ctxt->comp;
9702 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9703}
9704
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009705/************************************************************************
9706 * *
9707 * Public interfaces *
9708 * *
9709 ************************************************************************/
9710
9711/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009712 * xmlXPathEvalPredicate:
9713 * @ctxt: the XPath context
9714 * @res: the Predicate Expression evaluation result
9715 *
9716 * Evaluate a predicate result for the current node.
9717 * A PredicateExpr is evaluated by evaluating the Expr and converting
9718 * the result to a boolean. If the result is a number, the result will
9719 * be converted to true if the number is equal to the position of the
9720 * context node in the context node list (as returned by the position
9721 * function) and will be converted to false otherwise; if the result
9722 * is not a number, then the result will be converted as if by a call
9723 * to the boolean function.
9724 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009725 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009726 */
9727int
9728xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9729 if (res == NULL) return(0);
9730 switch (res->type) {
9731 case XPATH_BOOLEAN:
9732 return(res->boolval);
9733 case XPATH_NUMBER:
9734 return(res->floatval == ctxt->proximityPosition);
9735 case XPATH_NODESET:
9736 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009737 if (res->nodesetval == NULL)
9738 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009739 return(res->nodesetval->nodeNr != 0);
9740 case XPATH_STRING:
9741 return((res->stringval != NULL) &&
9742 (xmlStrlen(res->stringval) != 0));
9743 default:
9744 STRANGE
9745 }
9746 return(0);
9747}
9748
9749/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009750 * xmlXPathEvaluatePredicateResult:
9751 * @ctxt: the XPath Parser context
9752 * @res: the Predicate Expression evaluation result
9753 *
9754 * Evaluate a predicate result for the current node.
9755 * A PredicateExpr is evaluated by evaluating the Expr and converting
9756 * the result to a boolean. If the result is a number, the result will
9757 * be converted to true if the number is equal to the position of the
9758 * context node in the context node list (as returned by the position
9759 * function) and will be converted to false otherwise; if the result
9760 * is not a number, then the result will be converted as if by a call
9761 * to the boolean function.
9762 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009763 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009764 */
9765int
9766xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9767 xmlXPathObjectPtr res) {
9768 if (res == NULL) return(0);
9769 switch (res->type) {
9770 case XPATH_BOOLEAN:
9771 return(res->boolval);
9772 case XPATH_NUMBER:
9773 return(res->floatval == ctxt->context->proximityPosition);
9774 case XPATH_NODESET:
9775 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009776 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009777 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009778 return(res->nodesetval->nodeNr != 0);
9779 case XPATH_STRING:
9780 return((res->stringval != NULL) &&
9781 (xmlStrlen(res->stringval) != 0));
9782 default:
9783 STRANGE
9784 }
9785 return(0);
9786}
9787
9788/**
9789 * xmlXPathCompile:
9790 * @str: the XPath expression
9791 *
9792 * Compile an XPath expression
9793 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009794 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009795 * the caller has to free the object.
9796 */
9797xmlXPathCompExprPtr
9798xmlXPathCompile(const xmlChar *str) {
9799 xmlXPathParserContextPtr ctxt;
9800 xmlXPathCompExprPtr comp;
9801
9802 xmlXPathInit();
9803
9804 ctxt = xmlXPathNewParserContext(str, NULL);
9805 xmlXPathCompileExpr(ctxt);
9806
Daniel Veillard40af6492001-04-22 08:50:55 +00009807 if (*ctxt->cur != 0) {
9808 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9809 comp = NULL;
9810 } else {
9811 comp = ctxt->comp;
9812 ctxt->comp = NULL;
9813 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009814 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009815#ifdef DEBUG_EVAL_COUNTS
9816 if (comp != NULL) {
9817 comp->string = xmlStrdup(str);
9818 comp->nb = 0;
9819 }
9820#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009821 return(comp);
9822}
9823
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009824/**
9825 * xmlXPathCompiledEval:
9826 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009827 * @ctx: the XPath context
9828 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009829 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009830 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009831 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +00009832 * the caller has to free the object.
9833 */
9834xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009835xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009836 xmlXPathParserContextPtr ctxt;
9837 xmlXPathObjectPtr res, tmp, init = NULL;
9838 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00009839#ifndef LIBXML_THREAD_ENABLED
9840 static int reentance = 0;
9841#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009842
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009843 if ((comp == NULL) || (ctx == NULL))
9844 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009845 xmlXPathInit();
9846
9847 CHECK_CONTEXT(ctx)
9848
Daniel Veillard81463942001-10-16 12:34:39 +00009849#ifndef LIBXML_THREAD_ENABLED
9850 reentance++;
9851 if (reentance > 1)
9852 xmlXPathDisableOptimizer = 1;
9853#endif
9854
Daniel Veillardf06307e2001-07-03 10:35:50 +00009855#ifdef DEBUG_EVAL_COUNTS
9856 comp->nb++;
9857 if ((comp->string != NULL) && (comp->nb > 100)) {
9858 fprintf(stderr, "100 x %s\n", comp->string);
9859 comp->nb = 0;
9860 }
9861#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009862 ctxt = xmlXPathCompParserContext(comp, ctx);
9863 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009864
9865 if (ctxt->value == NULL) {
9866 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009867 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00009868 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009869 } else {
9870 res = valuePop(ctxt);
9871 }
9872
Daniel Veillardf06307e2001-07-03 10:35:50 +00009873
Owen Taylor3473f882001-02-23 17:55:21 +00009874 do {
9875 tmp = valuePop(ctxt);
9876 if (tmp != NULL) {
9877 if (tmp != init)
9878 stack++;
9879 xmlXPathFreeObject(tmp);
9880 }
9881 } while (tmp != NULL);
9882 if ((stack != 0) && (res != NULL)) {
9883 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009884 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +00009885 stack);
9886 }
9887 if (ctxt->error != XPATH_EXPRESSION_OK) {
9888 xmlXPathFreeObject(res);
9889 res = NULL;
9890 }
9891
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009892
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009893 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009894 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +00009895#ifndef LIBXML_THREAD_ENABLED
9896 reentance--;
9897#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009898 return(res);
9899}
9900
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009901/**
9902 * xmlXPathEvalExpr:
9903 * @ctxt: the XPath Parser context
9904 *
9905 * Parse and evaluate an XPath expression in the given context,
9906 * then push the result on the context stack
9907 */
9908void
9909xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9910 xmlXPathCompileExpr(ctxt);
9911 xmlXPathRunEval(ctxt);
9912}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009913
9914/**
9915 * xmlXPathEval:
9916 * @str: the XPath expression
9917 * @ctx: the XPath context
9918 *
9919 * Evaluate the XPath Location Path in the given context.
9920 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009921 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009922 * the caller has to free the object.
9923 */
9924xmlXPathObjectPtr
9925xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9926 xmlXPathParserContextPtr ctxt;
9927 xmlXPathObjectPtr res, tmp, init = NULL;
9928 int stack = 0;
9929
9930 xmlXPathInit();
9931
9932 CHECK_CONTEXT(ctx)
9933
9934 ctxt = xmlXPathNewParserContext(str, ctx);
9935 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009936
9937 if (ctxt->value == NULL) {
9938 xmlGenericError(xmlGenericErrorContext,
9939 "xmlXPathEval: evaluation failed\n");
9940 res = NULL;
9941 } else if (*ctxt->cur != 0) {
9942 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9943 res = NULL;
9944 } else {
9945 res = valuePop(ctxt);
9946 }
9947
9948 do {
9949 tmp = valuePop(ctxt);
9950 if (tmp != NULL) {
9951 if (tmp != init)
9952 stack++;
9953 xmlXPathFreeObject(tmp);
9954 }
9955 } while (tmp != NULL);
9956 if ((stack != 0) && (res != NULL)) {
9957 xmlGenericError(xmlGenericErrorContext,
9958 "xmlXPathEval: %d object left on the stack\n",
9959 stack);
9960 }
9961 if (ctxt->error != XPATH_EXPRESSION_OK) {
9962 xmlXPathFreeObject(res);
9963 res = NULL;
9964 }
9965
Owen Taylor3473f882001-02-23 17:55:21 +00009966 xmlXPathFreeParserContext(ctxt);
9967 return(res);
9968}
9969
9970/**
9971 * xmlXPathEvalExpression:
9972 * @str: the XPath expression
9973 * @ctxt: the XPath context
9974 *
9975 * Evaluate the XPath expression in the given context.
9976 *
9977 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9978 * the caller has to free the object.
9979 */
9980xmlXPathObjectPtr
9981xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9982 xmlXPathParserContextPtr pctxt;
9983 xmlXPathObjectPtr res, tmp;
9984 int stack = 0;
9985
9986 xmlXPathInit();
9987
9988 CHECK_CONTEXT(ctxt)
9989
9990 pctxt = xmlXPathNewParserContext(str, ctxt);
9991 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009992
9993 if (*pctxt->cur != 0) {
9994 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9995 res = NULL;
9996 } else {
9997 res = valuePop(pctxt);
9998 }
9999 do {
10000 tmp = valuePop(pctxt);
10001 if (tmp != NULL) {
10002 xmlXPathFreeObject(tmp);
10003 stack++;
10004 }
10005 } while (tmp != NULL);
10006 if ((stack != 0) && (res != NULL)) {
10007 xmlGenericError(xmlGenericErrorContext,
10008 "xmlXPathEvalExpression: %d object left on the stack\n",
10009 stack);
10010 }
10011 xmlXPathFreeParserContext(pctxt);
10012 return(res);
10013}
10014
10015/**
10016 * xmlXPathRegisterAllFunctions:
10017 * @ctxt: the XPath context
10018 *
10019 * Registers all default XPath functions in this context
10020 */
10021void
10022xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10023{
10024 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10025 xmlXPathBooleanFunction);
10026 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10027 xmlXPathCeilingFunction);
10028 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10029 xmlXPathCountFunction);
10030 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10031 xmlXPathConcatFunction);
10032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10033 xmlXPathContainsFunction);
10034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10035 xmlXPathIdFunction);
10036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10037 xmlXPathFalseFunction);
10038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10039 xmlXPathFloorFunction);
10040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10041 xmlXPathLastFunction);
10042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10043 xmlXPathLangFunction);
10044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10045 xmlXPathLocalNameFunction);
10046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10047 xmlXPathNotFunction);
10048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10049 xmlXPathNameFunction);
10050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10051 xmlXPathNamespaceURIFunction);
10052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10053 xmlXPathNormalizeFunction);
10054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10055 xmlXPathNumberFunction);
10056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10057 xmlXPathPositionFunction);
10058 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10059 xmlXPathRoundFunction);
10060 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10061 xmlXPathStringFunction);
10062 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10063 xmlXPathStringLengthFunction);
10064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10065 xmlXPathStartsWithFunction);
10066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10067 xmlXPathSubstringFunction);
10068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10069 xmlXPathSubstringBeforeFunction);
10070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10071 xmlXPathSubstringAfterFunction);
10072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10073 xmlXPathSumFunction);
10074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10075 xmlXPathTrueFunction);
10076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10077 xmlXPathTranslateFunction);
10078}
10079
10080#endif /* LIBXML_XPATH_ENABLED */