blob: 3464c924643247cfcee8547d456bcbbb44acf5dc [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);
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004428 if (val == 0) {
4429 if (ctxt->value->floatval == 0)
4430 ctxt->value->floatval = xmlXPathNAN;
4431 else if (ctxt->value->floatval > 0)
4432 ctxt->value->floatval = xmlXPathPINF;
4433 else if (ctxt->value->floatval < 0)
4434 ctxt->value->floatval = xmlXPathNINF;
4435 } else
4436 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004437}
4438
4439/**
4440 * xmlXPathModValues:
4441 * @ctxt: the XPath Parser context
4442 *
4443 * Implement the mod operation on XPath objects: @arg1 / @arg2
4444 * The numeric operators convert their operands to numbers as if
4445 * by calling the number function.
4446 */
4447void
4448xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4449 xmlXPathObjectPtr arg;
4450 int arg1, arg2;
4451
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004452 arg = valuePop(ctxt);
4453 if (arg == NULL)
4454 XP_ERROR(XPATH_INVALID_OPERAND);
4455 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004456 xmlXPathFreeObject(arg);
4457
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004458 CAST_TO_NUMBER;
4459 CHECK_TYPE(XPATH_NUMBER);
4460 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004461 if (arg2 == 0)
4462 ctxt->value->floatval = xmlXPathNAN;
4463 else
4464 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004465}
4466
4467/************************************************************************
4468 * *
4469 * The traversal functions *
4470 * *
4471 ************************************************************************/
4472
Owen Taylor3473f882001-02-23 17:55:21 +00004473/*
4474 * A traversal function enumerates nodes along an axis.
4475 * Initially it must be called with NULL, and it indicates
4476 * termination on the axis by returning NULL.
4477 */
4478typedef xmlNodePtr (*xmlXPathTraversalFunction)
4479 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4480
4481/**
4482 * xmlXPathNextSelf:
4483 * @ctxt: the XPath Parser context
4484 * @cur: the current node in the traversal
4485 *
4486 * Traversal function for the "self" direction
4487 * The self axis contains just the context node itself
4488 *
4489 * Returns the next element following that axis
4490 */
4491xmlNodePtr
4492xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4493 if (cur == NULL)
4494 return(ctxt->context->node);
4495 return(NULL);
4496}
4497
4498/**
4499 * xmlXPathNextChild:
4500 * @ctxt: the XPath Parser context
4501 * @cur: the current node in the traversal
4502 *
4503 * Traversal function for the "child" direction
4504 * The child axis contains the children of the context node in document order.
4505 *
4506 * Returns the next element following that axis
4507 */
4508xmlNodePtr
4509xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4510 if (cur == NULL) {
4511 if (ctxt->context->node == NULL) return(NULL);
4512 switch (ctxt->context->node->type) {
4513 case XML_ELEMENT_NODE:
4514 case XML_TEXT_NODE:
4515 case XML_CDATA_SECTION_NODE:
4516 case XML_ENTITY_REF_NODE:
4517 case XML_ENTITY_NODE:
4518 case XML_PI_NODE:
4519 case XML_COMMENT_NODE:
4520 case XML_NOTATION_NODE:
4521 case XML_DTD_NODE:
4522 return(ctxt->context->node->children);
4523 case XML_DOCUMENT_NODE:
4524 case XML_DOCUMENT_TYPE_NODE:
4525 case XML_DOCUMENT_FRAG_NODE:
4526 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004527#ifdef LIBXML_DOCB_ENABLED
4528 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004529#endif
4530 return(((xmlDocPtr) ctxt->context->node)->children);
4531 case XML_ELEMENT_DECL:
4532 case XML_ATTRIBUTE_DECL:
4533 case XML_ENTITY_DECL:
4534 case XML_ATTRIBUTE_NODE:
4535 case XML_NAMESPACE_DECL:
4536 case XML_XINCLUDE_START:
4537 case XML_XINCLUDE_END:
4538 return(NULL);
4539 }
4540 return(NULL);
4541 }
4542 if ((cur->type == XML_DOCUMENT_NODE) ||
4543 (cur->type == XML_HTML_DOCUMENT_NODE))
4544 return(NULL);
4545 return(cur->next);
4546}
4547
4548/**
4549 * xmlXPathNextDescendant:
4550 * @ctxt: the XPath Parser context
4551 * @cur: the current node in the traversal
4552 *
4553 * Traversal function for the "descendant" direction
4554 * the descendant axis contains the descendants of the context node in document
4555 * order; a descendant is a child or a child of a child and so on.
4556 *
4557 * Returns the next element following that axis
4558 */
4559xmlNodePtr
4560xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4561 if (cur == NULL) {
4562 if (ctxt->context->node == NULL)
4563 return(NULL);
4564 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4565 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4566 return(NULL);
4567
4568 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4569 return(ctxt->context->doc->children);
4570 return(ctxt->context->node->children);
4571 }
4572
Daniel Veillard567e1b42001-08-01 15:53:47 +00004573 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004574 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004575 return(cur->children);
4576 }
4577
4578 if (cur == ctxt->context->node) return(NULL);
4579
Owen Taylor3473f882001-02-23 17:55:21 +00004580 if (cur->next != NULL) return(cur->next);
4581
4582 do {
4583 cur = cur->parent;
4584 if (cur == NULL) return(NULL);
4585 if (cur == ctxt->context->node) return(NULL);
4586 if (cur->next != NULL) {
4587 cur = cur->next;
4588 return(cur);
4589 }
4590 } while (cur != NULL);
4591 return(cur);
4592}
4593
4594/**
4595 * xmlXPathNextDescendantOrSelf:
4596 * @ctxt: the XPath Parser context
4597 * @cur: the current node in the traversal
4598 *
4599 * Traversal function for the "descendant-or-self" direction
4600 * the descendant-or-self axis contains the context node and the descendants
4601 * of the context node in document order; thus the context node is the first
4602 * node on the axis, and the first child of the context node is the second node
4603 * on the axis
4604 *
4605 * Returns the next element following that axis
4606 */
4607xmlNodePtr
4608xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4609 if (cur == NULL) {
4610 if (ctxt->context->node == NULL)
4611 return(NULL);
4612 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4613 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4614 return(NULL);
4615 return(ctxt->context->node);
4616 }
4617
4618 return(xmlXPathNextDescendant(ctxt, cur));
4619}
4620
4621/**
4622 * xmlXPathNextParent:
4623 * @ctxt: the XPath Parser context
4624 * @cur: the current node in the traversal
4625 *
4626 * Traversal function for the "parent" direction
4627 * The parent axis contains the parent of the context node, if there is one.
4628 *
4629 * Returns the next element following that axis
4630 */
4631xmlNodePtr
4632xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4633 /*
4634 * the parent of an attribute or namespace node is the element
4635 * to which the attribute or namespace node is attached
4636 * Namespace handling !!!
4637 */
4638 if (cur == NULL) {
4639 if (ctxt->context->node == NULL) return(NULL);
4640 switch (ctxt->context->node->type) {
4641 case XML_ELEMENT_NODE:
4642 case XML_TEXT_NODE:
4643 case XML_CDATA_SECTION_NODE:
4644 case XML_ENTITY_REF_NODE:
4645 case XML_ENTITY_NODE:
4646 case XML_PI_NODE:
4647 case XML_COMMENT_NODE:
4648 case XML_NOTATION_NODE:
4649 case XML_DTD_NODE:
4650 case XML_ELEMENT_DECL:
4651 case XML_ATTRIBUTE_DECL:
4652 case XML_XINCLUDE_START:
4653 case XML_XINCLUDE_END:
4654 case XML_ENTITY_DECL:
4655 if (ctxt->context->node->parent == NULL)
4656 return((xmlNodePtr) ctxt->context->doc);
4657 return(ctxt->context->node->parent);
4658 case XML_ATTRIBUTE_NODE: {
4659 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4660
4661 return(att->parent);
4662 }
4663 case XML_DOCUMENT_NODE:
4664 case XML_DOCUMENT_TYPE_NODE:
4665 case XML_DOCUMENT_FRAG_NODE:
4666 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004667#ifdef LIBXML_DOCB_ENABLED
4668 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004669#endif
4670 return(NULL);
4671 case XML_NAMESPACE_DECL:
4672 /*
4673 * TODO !!! may require extending struct _xmlNs with
4674 * parent field
4675 * C.f. Infoset case...
4676 */
4677 return(NULL);
4678 }
4679 }
4680 return(NULL);
4681}
4682
4683/**
4684 * xmlXPathNextAncestor:
4685 * @ctxt: the XPath Parser context
4686 * @cur: the current node in the traversal
4687 *
4688 * Traversal function for the "ancestor" direction
4689 * the ancestor axis contains the ancestors of the context node; the ancestors
4690 * of the context node consist of the parent of context node and the parent's
4691 * parent and so on; the nodes are ordered in reverse document order; thus the
4692 * parent is the first node on the axis, and the parent's parent is the second
4693 * node on the axis
4694 *
4695 * Returns the next element following that axis
4696 */
4697xmlNodePtr
4698xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4699 /*
4700 * the parent of an attribute or namespace node is the element
4701 * to which the attribute or namespace node is attached
4702 * !!!!!!!!!!!!!
4703 */
4704 if (cur == NULL) {
4705 if (ctxt->context->node == NULL) return(NULL);
4706 switch (ctxt->context->node->type) {
4707 case XML_ELEMENT_NODE:
4708 case XML_TEXT_NODE:
4709 case XML_CDATA_SECTION_NODE:
4710 case XML_ENTITY_REF_NODE:
4711 case XML_ENTITY_NODE:
4712 case XML_PI_NODE:
4713 case XML_COMMENT_NODE:
4714 case XML_DTD_NODE:
4715 case XML_ELEMENT_DECL:
4716 case XML_ATTRIBUTE_DECL:
4717 case XML_ENTITY_DECL:
4718 case XML_NOTATION_NODE:
4719 case XML_XINCLUDE_START:
4720 case XML_XINCLUDE_END:
4721 if (ctxt->context->node->parent == NULL)
4722 return((xmlNodePtr) ctxt->context->doc);
4723 return(ctxt->context->node->parent);
4724 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004725 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004726
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004727 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004728 }
4729 case XML_DOCUMENT_NODE:
4730 case XML_DOCUMENT_TYPE_NODE:
4731 case XML_DOCUMENT_FRAG_NODE:
4732 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004733#ifdef LIBXML_DOCB_ENABLED
4734 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004735#endif
4736 return(NULL);
4737 case XML_NAMESPACE_DECL:
4738 /*
4739 * TODO !!! may require extending struct _xmlNs with
4740 * parent field
4741 * C.f. Infoset case...
4742 */
4743 return(NULL);
4744 }
4745 return(NULL);
4746 }
4747 if (cur == ctxt->context->doc->children)
4748 return((xmlNodePtr) ctxt->context->doc);
4749 if (cur == (xmlNodePtr) ctxt->context->doc)
4750 return(NULL);
4751 switch (cur->type) {
4752 case XML_ELEMENT_NODE:
4753 case XML_TEXT_NODE:
4754 case XML_CDATA_SECTION_NODE:
4755 case XML_ENTITY_REF_NODE:
4756 case XML_ENTITY_NODE:
4757 case XML_PI_NODE:
4758 case XML_COMMENT_NODE:
4759 case XML_NOTATION_NODE:
4760 case XML_DTD_NODE:
4761 case XML_ELEMENT_DECL:
4762 case XML_ATTRIBUTE_DECL:
4763 case XML_ENTITY_DECL:
4764 case XML_XINCLUDE_START:
4765 case XML_XINCLUDE_END:
4766 return(cur->parent);
4767 case XML_ATTRIBUTE_NODE: {
4768 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4769
4770 return(att->parent);
4771 }
4772 case XML_DOCUMENT_NODE:
4773 case XML_DOCUMENT_TYPE_NODE:
4774 case XML_DOCUMENT_FRAG_NODE:
4775 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004776#ifdef LIBXML_DOCB_ENABLED
4777 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004778#endif
4779 return(NULL);
4780 case XML_NAMESPACE_DECL:
4781 /*
4782 * TODO !!! may require extending struct _xmlNs with
4783 * parent field
4784 * C.f. Infoset case...
4785 */
4786 return(NULL);
4787 }
4788 return(NULL);
4789}
4790
4791/**
4792 * xmlXPathNextAncestorOrSelf:
4793 * @ctxt: the XPath Parser context
4794 * @cur: the current node in the traversal
4795 *
4796 * Traversal function for the "ancestor-or-self" direction
4797 * he ancestor-or-self axis contains the context node and ancestors of
4798 * the context node in reverse document order; thus the context node is
4799 * the first node on the axis, and the context node's parent the second;
4800 * parent here is defined the same as with the parent axis.
4801 *
4802 * Returns the next element following that axis
4803 */
4804xmlNodePtr
4805xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4806 if (cur == NULL)
4807 return(ctxt->context->node);
4808 return(xmlXPathNextAncestor(ctxt, cur));
4809}
4810
4811/**
4812 * xmlXPathNextFollowingSibling:
4813 * @ctxt: the XPath Parser context
4814 * @cur: the current node in the traversal
4815 *
4816 * Traversal function for the "following-sibling" direction
4817 * The following-sibling axis contains the following siblings of the context
4818 * node in document order.
4819 *
4820 * Returns the next element following that axis
4821 */
4822xmlNodePtr
4823xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4824 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4825 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4826 return(NULL);
4827 if (cur == (xmlNodePtr) ctxt->context->doc)
4828 return(NULL);
4829 if (cur == NULL)
4830 return(ctxt->context->node->next);
4831 return(cur->next);
4832}
4833
4834/**
4835 * xmlXPathNextPrecedingSibling:
4836 * @ctxt: the XPath Parser context
4837 * @cur: the current node in the traversal
4838 *
4839 * Traversal function for the "preceding-sibling" direction
4840 * The preceding-sibling axis contains the preceding siblings of the context
4841 * node in reverse document order; the first preceding sibling is first on the
4842 * axis; the sibling preceding that node is the second on the axis and so on.
4843 *
4844 * Returns the next element following that axis
4845 */
4846xmlNodePtr
4847xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4848 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4849 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4850 return(NULL);
4851 if (cur == (xmlNodePtr) ctxt->context->doc)
4852 return(NULL);
4853 if (cur == NULL)
4854 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004855 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4856 cur = cur->prev;
4857 if (cur == NULL)
4858 return(ctxt->context->node->prev);
4859 }
Owen Taylor3473f882001-02-23 17:55:21 +00004860 return(cur->prev);
4861}
4862
4863/**
4864 * xmlXPathNextFollowing:
4865 * @ctxt: the XPath Parser context
4866 * @cur: the current node in the traversal
4867 *
4868 * Traversal function for the "following" direction
4869 * The following axis contains all nodes in the same document as the context
4870 * node that are after the context node in document order, excluding any
4871 * descendants and excluding attribute nodes and namespace nodes; the nodes
4872 * are ordered in document order
4873 *
4874 * Returns the next element following that axis
4875 */
4876xmlNodePtr
4877xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4878 if (cur != NULL && cur->children != NULL)
4879 return cur->children ;
4880 if (cur == NULL) cur = ctxt->context->node;
4881 if (cur == NULL) return(NULL) ; /* ERROR */
4882 if (cur->next != NULL) return(cur->next) ;
4883 do {
4884 cur = cur->parent;
4885 if (cur == NULL) return(NULL);
4886 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4887 if (cur->next != NULL) return(cur->next);
4888 } while (cur != NULL);
4889 return(cur);
4890}
4891
4892/*
4893 * xmlXPathIsAncestor:
4894 * @ancestor: the ancestor node
4895 * @node: the current node
4896 *
4897 * Check that @ancestor is a @node's ancestor
4898 *
4899 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4900 */
4901static int
4902xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4903 if ((ancestor == NULL) || (node == NULL)) return(0);
4904 /* nodes need to be in the same document */
4905 if (ancestor->doc != node->doc) return(0);
4906 /* avoid searching if ancestor or node is the root node */
4907 if (ancestor == (xmlNodePtr) node->doc) return(1);
4908 if (node == (xmlNodePtr) ancestor->doc) return(0);
4909 while (node->parent != NULL) {
4910 if (node->parent == ancestor)
4911 return(1);
4912 node = node->parent;
4913 }
4914 return(0);
4915}
4916
4917/**
4918 * xmlXPathNextPreceding:
4919 * @ctxt: the XPath Parser context
4920 * @cur: the current node in the traversal
4921 *
4922 * Traversal function for the "preceding" direction
4923 * the preceding axis contains all nodes in the same document as the context
4924 * node that are before the context node in document order, excluding any
4925 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4926 * ordered in reverse document order
4927 *
4928 * Returns the next element following that axis
4929 */
4930xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004931xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4932{
Owen Taylor3473f882001-02-23 17:55:21 +00004933 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004934 cur = ctxt->context->node;
4935 if (cur == NULL)
4936 return (NULL);
4937 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4938 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004939 do {
4940 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004941 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4942 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004943 }
4944
4945 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004946 if (cur == NULL)
4947 return (NULL);
4948 if (cur == ctxt->context->doc->children)
4949 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004950 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004951 return (cur);
4952}
4953
4954/**
4955 * xmlXPathNextPrecedingInternal:
4956 * @ctxt: the XPath Parser context
4957 * @cur: the current node in the traversal
4958 *
4959 * Traversal function for the "preceding" direction
4960 * the preceding axis contains all nodes in the same document as the context
4961 * node that are before the context node in document order, excluding any
4962 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4963 * ordered in reverse document order
4964 * This is a faster implementation but internal only since it requires a
4965 * state kept in the parser context: ctxt->ancestor.
4966 *
4967 * Returns the next element following that axis
4968 */
4969static xmlNodePtr
4970xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4971 xmlNodePtr cur)
4972{
4973 if (cur == NULL) {
4974 cur = ctxt->context->node;
4975 if (cur == NULL)
4976 return (NULL);
4977 ctxt->ancestor = cur->parent;
4978 }
4979 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4980 cur = cur->prev;
4981 while (cur->prev == NULL) {
4982 cur = cur->parent;
4983 if (cur == NULL)
4984 return (NULL);
4985 if (cur == ctxt->context->doc->children)
4986 return (NULL);
4987 if (cur != ctxt->ancestor)
4988 return (cur);
4989 ctxt->ancestor = cur->parent;
4990 }
4991 cur = cur->prev;
4992 while (cur->last != NULL)
4993 cur = cur->last;
4994 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004995}
4996
4997/**
4998 * xmlXPathNextNamespace:
4999 * @ctxt: the XPath Parser context
5000 * @cur: the current attribute in the traversal
5001 *
5002 * Traversal function for the "namespace" direction
5003 * the namespace axis contains the namespace nodes of the context node;
5004 * the order of nodes on this axis is implementation-defined; the axis will
5005 * be empty unless the context node is an element
5006 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005007 * We keep the XML namespace node at the end of the list.
5008 *
Owen Taylor3473f882001-02-23 17:55:21 +00005009 * Returns the next element following that axis
5010 */
5011xmlNodePtr
5012xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005013 xmlNodePtr ret;
5014
Owen Taylor3473f882001-02-23 17:55:21 +00005015 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005016 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5017 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005018 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5019 if (ctxt->context->tmpNsList != NULL)
5020 xmlFree(ctxt->context->tmpNsList);
5021 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005022 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005023 if (ctxt->context->tmpNsList == NULL) return(NULL);
5024 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005025 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005026 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5027 if (ret == NULL) {
5028 xmlFree(ctxt->context->tmpNsList);
5029 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005030 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005031 }
5032 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005033}
5034
5035/**
5036 * xmlXPathNextAttribute:
5037 * @ctxt: the XPath Parser context
5038 * @cur: the current attribute in the traversal
5039 *
5040 * Traversal function for the "attribute" direction
5041 * TODO: support DTD inherited default attributes
5042 *
5043 * Returns the next element following that axis
5044 */
5045xmlNodePtr
5046xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005047 if (ctxt->context->node == NULL)
5048 return(NULL);
5049 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5050 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005051 if (cur == NULL) {
5052 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5053 return(NULL);
5054 return((xmlNodePtr)ctxt->context->node->properties);
5055 }
5056 return((xmlNodePtr)cur->next);
5057}
5058
5059/************************************************************************
5060 * *
5061 * NodeTest Functions *
5062 * *
5063 ************************************************************************/
5064
Owen Taylor3473f882001-02-23 17:55:21 +00005065#define IS_FUNCTION 200
5066
Owen Taylor3473f882001-02-23 17:55:21 +00005067
5068/************************************************************************
5069 * *
5070 * Implicit tree core function library *
5071 * *
5072 ************************************************************************/
5073
5074/**
5075 * xmlXPathRoot:
5076 * @ctxt: the XPath Parser context
5077 *
5078 * Initialize the context to the root of the document
5079 */
5080void
5081xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5082 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5083 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5084}
5085
5086/************************************************************************
5087 * *
5088 * The explicit core function library *
5089 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5090 * *
5091 ************************************************************************/
5092
5093
5094/**
5095 * xmlXPathLastFunction:
5096 * @ctxt: the XPath Parser context
5097 * @nargs: the number of arguments
5098 *
5099 * Implement the last() XPath function
5100 * number last()
5101 * The last function returns the number of nodes in the context node list.
5102 */
5103void
5104xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5105 CHECK_ARITY(0);
5106 if (ctxt->context->contextSize >= 0) {
5107 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5108#ifdef DEBUG_EXPR
5109 xmlGenericError(xmlGenericErrorContext,
5110 "last() : %d\n", ctxt->context->contextSize);
5111#endif
5112 } else {
5113 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5114 }
5115}
5116
5117/**
5118 * xmlXPathPositionFunction:
5119 * @ctxt: the XPath Parser context
5120 * @nargs: the number of arguments
5121 *
5122 * Implement the position() XPath function
5123 * number position()
5124 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005125 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005126 * will be equal to last().
5127 */
5128void
5129xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5130 CHECK_ARITY(0);
5131 if (ctxt->context->proximityPosition >= 0) {
5132 valuePush(ctxt,
5133 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5134#ifdef DEBUG_EXPR
5135 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5136 ctxt->context->proximityPosition);
5137#endif
5138 } else {
5139 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5140 }
5141}
5142
5143/**
5144 * xmlXPathCountFunction:
5145 * @ctxt: the XPath Parser context
5146 * @nargs: the number of arguments
5147 *
5148 * Implement the count() XPath function
5149 * number count(node-set)
5150 */
5151void
5152xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5153 xmlXPathObjectPtr cur;
5154
5155 CHECK_ARITY(1);
5156 if ((ctxt->value == NULL) ||
5157 ((ctxt->value->type != XPATH_NODESET) &&
5158 (ctxt->value->type != XPATH_XSLT_TREE)))
5159 XP_ERROR(XPATH_INVALID_TYPE);
5160 cur = valuePop(ctxt);
5161
Daniel Veillard911f49a2001-04-07 15:39:35 +00005162 if ((cur == NULL) || (cur->nodesetval == NULL))
5163 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005164 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005165 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005166 } else {
5167 if ((cur->nodesetval->nodeNr != 1) ||
5168 (cur->nodesetval->nodeTab == NULL)) {
5169 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5170 } else {
5171 xmlNodePtr tmp;
5172 int i = 0;
5173
5174 tmp = cur->nodesetval->nodeTab[0];
5175 if (tmp != NULL) {
5176 tmp = tmp->children;
5177 while (tmp != NULL) {
5178 tmp = tmp->next;
5179 i++;
5180 }
5181 }
5182 valuePush(ctxt, xmlXPathNewFloat((double) i));
5183 }
5184 }
Owen Taylor3473f882001-02-23 17:55:21 +00005185 xmlXPathFreeObject(cur);
5186}
5187
5188/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005189 * xmlXPathGetElementsByIds:
5190 * @doc: the document
5191 * @ids: a whitespace separated list of IDs
5192 *
5193 * Selects elements by their unique ID.
5194 *
5195 * Returns a node-set of selected elements.
5196 */
5197static xmlNodeSetPtr
5198xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5199 xmlNodeSetPtr ret;
5200 const xmlChar *cur = ids;
5201 xmlChar *ID;
5202 xmlAttrPtr attr;
5203 xmlNodePtr elem = NULL;
5204
5205 ret = xmlXPathNodeSetCreate(NULL);
5206
5207 while (IS_BLANK(*cur)) cur++;
5208 while (*cur != 0) {
5209 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5210 (*cur == '.') || (*cur == '-') ||
5211 (*cur == '_') || (*cur == ':') ||
5212 (IS_COMBINING(*cur)) ||
5213 (IS_EXTENDER(*cur)))
5214 cur++;
5215
5216 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5217
5218 ID = xmlStrndup(ids, cur - ids);
5219 attr = xmlGetID(doc, ID);
5220 if (attr != NULL) {
5221 elem = attr->parent;
5222 xmlXPathNodeSetAdd(ret, elem);
5223 }
5224 if (ID != NULL)
5225 xmlFree(ID);
5226
5227 while (IS_BLANK(*cur)) cur++;
5228 ids = cur;
5229 }
5230 return(ret);
5231}
5232
5233/**
Owen Taylor3473f882001-02-23 17:55:21 +00005234 * xmlXPathIdFunction:
5235 * @ctxt: the XPath Parser context
5236 * @nargs: the number of arguments
5237 *
5238 * Implement the id() XPath function
5239 * node-set id(object)
5240 * The id function selects elements by their unique ID
5241 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5242 * then the result is the union of the result of applying id to the
5243 * string value of each of the nodes in the argument node-set. When the
5244 * argument to id is of any other type, the argument is converted to a
5245 * string as if by a call to the string function; the string is split
5246 * into a whitespace-separated list of tokens (whitespace is any sequence
5247 * of characters matching the production S); the result is a node-set
5248 * containing the elements in the same document as the context node that
5249 * have a unique ID equal to any of the tokens in the list.
5250 */
5251void
5252xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005253 xmlChar *tokens;
5254 xmlNodeSetPtr ret;
5255 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005256
5257 CHECK_ARITY(1);
5258 obj = valuePop(ctxt);
5259 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5260 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005261 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005262 int i;
5263
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005264 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005265
Daniel Veillard911f49a2001-04-07 15:39:35 +00005266 if (obj->nodesetval != NULL) {
5267 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005268 tokens =
5269 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5270 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5271 ret = xmlXPathNodeSetMerge(ret, ns);
5272 xmlXPathFreeNodeSet(ns);
5273 if (tokens != NULL)
5274 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005275 }
Owen Taylor3473f882001-02-23 17:55:21 +00005276 }
5277
5278 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005279 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005280 return;
5281 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005282 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005283
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005284 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5285 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005286
Owen Taylor3473f882001-02-23 17:55:21 +00005287 xmlXPathFreeObject(obj);
5288 return;
5289}
5290
5291/**
5292 * xmlXPathLocalNameFunction:
5293 * @ctxt: the XPath Parser context
5294 * @nargs: the number of arguments
5295 *
5296 * Implement the local-name() XPath function
5297 * string local-name(node-set?)
5298 * The local-name function returns a string containing the local part
5299 * of the name of the node in the argument node-set that is first in
5300 * document order. If the node-set is empty or the first node has no
5301 * name, an empty string is returned. If the argument is omitted it
5302 * defaults to the context node.
5303 */
5304void
5305xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5306 xmlXPathObjectPtr cur;
5307
5308 if (nargs == 0) {
5309 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5310 nargs = 1;
5311 }
5312
5313 CHECK_ARITY(1);
5314 if ((ctxt->value == NULL) ||
5315 ((ctxt->value->type != XPATH_NODESET) &&
5316 (ctxt->value->type != XPATH_XSLT_TREE)))
5317 XP_ERROR(XPATH_INVALID_TYPE);
5318 cur = valuePop(ctxt);
5319
Daniel Veillard911f49a2001-04-07 15:39:35 +00005320 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005321 valuePush(ctxt, xmlXPathNewCString(""));
5322 } else {
5323 int i = 0; /* Should be first in document order !!!!! */
5324 switch (cur->nodesetval->nodeTab[i]->type) {
5325 case XML_ELEMENT_NODE:
5326 case XML_ATTRIBUTE_NODE:
5327 case XML_PI_NODE:
5328 valuePush(ctxt,
5329 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5330 break;
5331 case XML_NAMESPACE_DECL:
5332 valuePush(ctxt, xmlXPathNewString(
5333 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5334 break;
5335 default:
5336 valuePush(ctxt, xmlXPathNewCString(""));
5337 }
5338 }
5339 xmlXPathFreeObject(cur);
5340}
5341
5342/**
5343 * xmlXPathNamespaceURIFunction:
5344 * @ctxt: the XPath Parser context
5345 * @nargs: the number of arguments
5346 *
5347 * Implement the namespace-uri() XPath function
5348 * string namespace-uri(node-set?)
5349 * The namespace-uri function returns a string containing the
5350 * namespace URI of the expanded name of the node in the argument
5351 * node-set that is first in document order. If the node-set is empty,
5352 * the first node has no name, or the expanded name has no namespace
5353 * URI, an empty string is returned. If the argument is omitted it
5354 * defaults to the context node.
5355 */
5356void
5357xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5358 xmlXPathObjectPtr cur;
5359
5360 if (nargs == 0) {
5361 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5362 nargs = 1;
5363 }
5364 CHECK_ARITY(1);
5365 if ((ctxt->value == NULL) ||
5366 ((ctxt->value->type != XPATH_NODESET) &&
5367 (ctxt->value->type != XPATH_XSLT_TREE)))
5368 XP_ERROR(XPATH_INVALID_TYPE);
5369 cur = valuePop(ctxt);
5370
Daniel Veillard911f49a2001-04-07 15:39:35 +00005371 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005372 valuePush(ctxt, xmlXPathNewCString(""));
5373 } else {
5374 int i = 0; /* Should be first in document order !!!!! */
5375 switch (cur->nodesetval->nodeTab[i]->type) {
5376 case XML_ELEMENT_NODE:
5377 case XML_ATTRIBUTE_NODE:
5378 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5379 valuePush(ctxt, xmlXPathNewCString(""));
5380 else
5381 valuePush(ctxt, xmlXPathNewString(
5382 cur->nodesetval->nodeTab[i]->ns->href));
5383 break;
5384 default:
5385 valuePush(ctxt, xmlXPathNewCString(""));
5386 }
5387 }
5388 xmlXPathFreeObject(cur);
5389}
5390
5391/**
5392 * xmlXPathNameFunction:
5393 * @ctxt: the XPath Parser context
5394 * @nargs: the number of arguments
5395 *
5396 * Implement the name() XPath function
5397 * string name(node-set?)
5398 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005399 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005400 * order. The QName must represent the name with respect to the namespace
5401 * declarations in effect on the node whose name is being represented.
5402 * Typically, this will be the form in which the name occurred in the XML
5403 * source. This need not be the case if there are namespace declarations
5404 * in effect on the node that associate multiple prefixes with the same
5405 * namespace. However, an implementation may include information about
5406 * the original prefix in its representation of nodes; in this case, an
5407 * implementation can ensure that the returned string is always the same
5408 * as the QName used in the XML source. If the argument it omitted it
5409 * defaults to the context node.
5410 * Libxml keep the original prefix so the "real qualified name" used is
5411 * returned.
5412 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005413static void
Daniel Veillard04383752001-07-08 14:27:15 +00005414xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5415{
Owen Taylor3473f882001-02-23 17:55:21 +00005416 xmlXPathObjectPtr cur;
5417
5418 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005419 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5420 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005421 }
5422
5423 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005424 if ((ctxt->value == NULL) ||
5425 ((ctxt->value->type != XPATH_NODESET) &&
5426 (ctxt->value->type != XPATH_XSLT_TREE)))
5427 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005428 cur = valuePop(ctxt);
5429
Daniel Veillard911f49a2001-04-07 15:39:35 +00005430 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005431 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005432 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005433 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005434
Daniel Veillard04383752001-07-08 14:27:15 +00005435 switch (cur->nodesetval->nodeTab[i]->type) {
5436 case XML_ELEMENT_NODE:
5437 case XML_ATTRIBUTE_NODE:
5438 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5439 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5440 valuePush(ctxt,
5441 xmlXPathNewString(cur->nodesetval->
5442 nodeTab[i]->name));
5443
5444 else {
5445 char name[2000];
5446
5447 snprintf(name, sizeof(name), "%s:%s",
5448 (char *) cur->nodesetval->nodeTab[i]->ns->
5449 prefix,
5450 (char *) cur->nodesetval->nodeTab[i]->name);
5451 name[sizeof(name) - 1] = 0;
5452 valuePush(ctxt, xmlXPathNewCString(name));
5453 }
5454 break;
5455 default:
5456 valuePush(ctxt,
5457 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5458 xmlXPathLocalNameFunction(ctxt, 1);
5459 }
Owen Taylor3473f882001-02-23 17:55:21 +00005460 }
5461 xmlXPathFreeObject(cur);
5462}
5463
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005464
5465/**
Owen Taylor3473f882001-02-23 17:55:21 +00005466 * xmlXPathStringFunction:
5467 * @ctxt: the XPath Parser context
5468 * @nargs: the number of arguments
5469 *
5470 * Implement the string() XPath function
5471 * string string(object?)
5472 * he string function converts an object to a string as follows:
5473 * - A node-set is converted to a string by returning the value of
5474 * the node in the node-set that is first in document order.
5475 * If the node-set is empty, an empty string is returned.
5476 * - A number is converted to a string as follows
5477 * + NaN is converted to the string NaN
5478 * + positive zero is converted to the string 0
5479 * + negative zero is converted to the string 0
5480 * + positive infinity is converted to the string Infinity
5481 * + negative infinity is converted to the string -Infinity
5482 * + if the number is an integer, the number is represented in
5483 * decimal form as a Number with no decimal point and no leading
5484 * zeros, preceded by a minus sign (-) if the number is negative
5485 * + otherwise, the number is represented in decimal form as a
5486 * Number including a decimal point with at least one digit
5487 * before the decimal point and at least one digit after the
5488 * decimal point, preceded by a minus sign (-) if the number
5489 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005490 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005491 * before the decimal point; beyond the one required digit
5492 * after the decimal point there must be as many, but only as
5493 * many, more digits as are needed to uniquely distinguish the
5494 * number from all other IEEE 754 numeric values.
5495 * - The boolean false value is converted to the string false.
5496 * The boolean true value is converted to the string true.
5497 *
5498 * If the argument is omitted, it defaults to a node-set with the
5499 * context node as its only member.
5500 */
5501void
5502xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5503 xmlXPathObjectPtr cur;
5504
5505 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005506 valuePush(ctxt,
5507 xmlXPathWrapString(
5508 xmlXPathCastNodeToString(ctxt->context->node)));
5509 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005510 }
5511
5512 CHECK_ARITY(1);
5513 cur = valuePop(ctxt);
5514 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005515 cur = xmlXPathConvertString(cur);
5516 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005517}
5518
5519/**
5520 * xmlXPathStringLengthFunction:
5521 * @ctxt: the XPath Parser context
5522 * @nargs: the number of arguments
5523 *
5524 * Implement the string-length() XPath function
5525 * number string-length(string?)
5526 * The string-length returns the number of characters in the string
5527 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5528 * the context node converted to a string, in other words the value
5529 * of the context node.
5530 */
5531void
5532xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5533 xmlXPathObjectPtr cur;
5534
5535 if (nargs == 0) {
5536 if (ctxt->context->node == NULL) {
5537 valuePush(ctxt, xmlXPathNewFloat(0));
5538 } else {
5539 xmlChar *content;
5540
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005541 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005542 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005543 xmlFree(content);
5544 }
5545 return;
5546 }
5547 CHECK_ARITY(1);
5548 CAST_TO_STRING;
5549 CHECK_TYPE(XPATH_STRING);
5550 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005551 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005552 xmlXPathFreeObject(cur);
5553}
5554
5555/**
5556 * xmlXPathConcatFunction:
5557 * @ctxt: the XPath Parser context
5558 * @nargs: the number of arguments
5559 *
5560 * Implement the concat() XPath function
5561 * string concat(string, string, string*)
5562 * The concat function returns the concatenation of its arguments.
5563 */
5564void
5565xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5566 xmlXPathObjectPtr cur, newobj;
5567 xmlChar *tmp;
5568
5569 if (nargs < 2) {
5570 CHECK_ARITY(2);
5571 }
5572
5573 CAST_TO_STRING;
5574 cur = valuePop(ctxt);
5575 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5576 xmlXPathFreeObject(cur);
5577 return;
5578 }
5579 nargs--;
5580
5581 while (nargs > 0) {
5582 CAST_TO_STRING;
5583 newobj = valuePop(ctxt);
5584 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5585 xmlXPathFreeObject(newobj);
5586 xmlXPathFreeObject(cur);
5587 XP_ERROR(XPATH_INVALID_TYPE);
5588 }
5589 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5590 newobj->stringval = cur->stringval;
5591 cur->stringval = tmp;
5592
5593 xmlXPathFreeObject(newobj);
5594 nargs--;
5595 }
5596 valuePush(ctxt, cur);
5597}
5598
5599/**
5600 * xmlXPathContainsFunction:
5601 * @ctxt: the XPath Parser context
5602 * @nargs: the number of arguments
5603 *
5604 * Implement the contains() XPath function
5605 * boolean contains(string, string)
5606 * The contains function returns true if the first argument string
5607 * contains the second argument string, and otherwise returns false.
5608 */
5609void
5610xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5611 xmlXPathObjectPtr hay, needle;
5612
5613 CHECK_ARITY(2);
5614 CAST_TO_STRING;
5615 CHECK_TYPE(XPATH_STRING);
5616 needle = valuePop(ctxt);
5617 CAST_TO_STRING;
5618 hay = valuePop(ctxt);
5619 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5620 xmlXPathFreeObject(hay);
5621 xmlXPathFreeObject(needle);
5622 XP_ERROR(XPATH_INVALID_TYPE);
5623 }
5624 if (xmlStrstr(hay->stringval, needle->stringval))
5625 valuePush(ctxt, xmlXPathNewBoolean(1));
5626 else
5627 valuePush(ctxt, xmlXPathNewBoolean(0));
5628 xmlXPathFreeObject(hay);
5629 xmlXPathFreeObject(needle);
5630}
5631
5632/**
5633 * xmlXPathStartsWithFunction:
5634 * @ctxt: the XPath Parser context
5635 * @nargs: the number of arguments
5636 *
5637 * Implement the starts-with() XPath function
5638 * boolean starts-with(string, string)
5639 * The starts-with function returns true if the first argument string
5640 * starts with the second argument string, and otherwise returns false.
5641 */
5642void
5643xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5644 xmlXPathObjectPtr hay, needle;
5645 int n;
5646
5647 CHECK_ARITY(2);
5648 CAST_TO_STRING;
5649 CHECK_TYPE(XPATH_STRING);
5650 needle = valuePop(ctxt);
5651 CAST_TO_STRING;
5652 hay = valuePop(ctxt);
5653 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5654 xmlXPathFreeObject(hay);
5655 xmlXPathFreeObject(needle);
5656 XP_ERROR(XPATH_INVALID_TYPE);
5657 }
5658 n = xmlStrlen(needle->stringval);
5659 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5660 valuePush(ctxt, xmlXPathNewBoolean(0));
5661 else
5662 valuePush(ctxt, xmlXPathNewBoolean(1));
5663 xmlXPathFreeObject(hay);
5664 xmlXPathFreeObject(needle);
5665}
5666
5667/**
5668 * xmlXPathSubstringFunction:
5669 * @ctxt: the XPath Parser context
5670 * @nargs: the number of arguments
5671 *
5672 * Implement the substring() XPath function
5673 * string substring(string, number, number?)
5674 * The substring function returns the substring of the first argument
5675 * starting at the position specified in the second argument with
5676 * length specified in the third argument. For example,
5677 * substring("12345",2,3) returns "234". If the third argument is not
5678 * specified, it returns the substring starting at the position specified
5679 * in the second argument and continuing to the end of the string. For
5680 * example, substring("12345",2) returns "2345". More precisely, each
5681 * character in the string (see [3.6 Strings]) is considered to have a
5682 * numeric position: the position of the first character is 1, the position
5683 * of the second character is 2 and so on. The returned substring contains
5684 * those characters for which the position of the character is greater than
5685 * or equal to the second argument and, if the third argument is specified,
5686 * less than the sum of the second and third arguments; the comparisons
5687 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5688 * - substring("12345", 1.5, 2.6) returns "234"
5689 * - substring("12345", 0, 3) returns "12"
5690 * - substring("12345", 0 div 0, 3) returns ""
5691 * - substring("12345", 1, 0 div 0) returns ""
5692 * - substring("12345", -42, 1 div 0) returns "12345"
5693 * - substring("12345", -1 div 0, 1 div 0) returns ""
5694 */
5695void
5696xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5697 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005698 double le=0, in;
5699 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005700 xmlChar *ret;
5701
Owen Taylor3473f882001-02-23 17:55:21 +00005702 if (nargs < 2) {
5703 CHECK_ARITY(2);
5704 }
5705 if (nargs > 3) {
5706 CHECK_ARITY(3);
5707 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005708 /*
5709 * take care of possible last (position) argument
5710 */
Owen Taylor3473f882001-02-23 17:55:21 +00005711 if (nargs == 3) {
5712 CAST_TO_NUMBER;
5713 CHECK_TYPE(XPATH_NUMBER);
5714 len = valuePop(ctxt);
5715 le = len->floatval;
5716 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005717 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005718
Owen Taylor3473f882001-02-23 17:55:21 +00005719 CAST_TO_NUMBER;
5720 CHECK_TYPE(XPATH_NUMBER);
5721 start = valuePop(ctxt);
5722 in = start->floatval;
5723 xmlXPathFreeObject(start);
5724 CAST_TO_STRING;
5725 CHECK_TYPE(XPATH_STRING);
5726 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005727 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005728
Daniel Veillard97ac1312001-05-30 19:14:17 +00005729 /*
5730 * If last pos not present, calculate last position
5731 */
5732 if (nargs != 3)
5733 le = m;
5734
5735 /*
5736 * To meet our requirements, initial index calculations
5737 * must be done before we convert to integer format
5738 *
5739 * First we normalize indices
5740 */
5741 in -= 1.0;
5742 le += in;
5743 if (in < 0.0)
5744 in = 0.0;
5745 if (le > (double)m)
5746 le = (double)m;
5747
5748 /*
5749 * Now we go to integer form, rounding up
5750 */
Owen Taylor3473f882001-02-23 17:55:21 +00005751 i = (int) in;
5752 if (((double)i) != in) i++;
5753
Owen Taylor3473f882001-02-23 17:55:21 +00005754 l = (int) le;
5755 if (((double)l) != le) l++;
5756
Daniel Veillard97ac1312001-05-30 19:14:17 +00005757 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005758
5759 /* number of chars to copy */
5760 l -= i;
5761
Daniel Veillard97ac1312001-05-30 19:14:17 +00005762 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005763 if (ret == NULL)
5764 valuePush(ctxt, xmlXPathNewCString(""));
5765 else {
5766 valuePush(ctxt, xmlXPathNewString(ret));
5767 xmlFree(ret);
5768 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005769
Owen Taylor3473f882001-02-23 17:55:21 +00005770 xmlXPathFreeObject(str);
5771}
5772
5773/**
5774 * xmlXPathSubstringBeforeFunction:
5775 * @ctxt: the XPath Parser context
5776 * @nargs: the number of arguments
5777 *
5778 * Implement the substring-before() XPath function
5779 * string substring-before(string, string)
5780 * The substring-before function returns the substring of the first
5781 * argument string that precedes the first occurrence of the second
5782 * argument string in the first argument string, or the empty string
5783 * if the first argument string does not contain the second argument
5784 * string. For example, substring-before("1999/04/01","/") returns 1999.
5785 */
5786void
5787xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5788 xmlXPathObjectPtr str;
5789 xmlXPathObjectPtr find;
5790 xmlBufferPtr target;
5791 const xmlChar *point;
5792 int offset;
5793
5794 CHECK_ARITY(2);
5795 CAST_TO_STRING;
5796 find = valuePop(ctxt);
5797 CAST_TO_STRING;
5798 str = valuePop(ctxt);
5799
5800 target = xmlBufferCreate();
5801 if (target) {
5802 point = xmlStrstr(str->stringval, find->stringval);
5803 if (point) {
5804 offset = (int)(point - str->stringval);
5805 xmlBufferAdd(target, str->stringval, offset);
5806 }
5807 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5808 xmlBufferFree(target);
5809 }
5810
5811 xmlXPathFreeObject(str);
5812 xmlXPathFreeObject(find);
5813}
5814
5815/**
5816 * xmlXPathSubstringAfterFunction:
5817 * @ctxt: the XPath Parser context
5818 * @nargs: the number of arguments
5819 *
5820 * Implement the substring-after() XPath function
5821 * string substring-after(string, string)
5822 * The substring-after function returns the substring of the first
5823 * argument string that follows the first occurrence of the second
5824 * argument string in the first argument string, or the empty stringi
5825 * if the first argument string does not contain the second argument
5826 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5827 * and substring-after("1999/04/01","19") returns 99/04/01.
5828 */
5829void
5830xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5831 xmlXPathObjectPtr str;
5832 xmlXPathObjectPtr find;
5833 xmlBufferPtr target;
5834 const xmlChar *point;
5835 int offset;
5836
5837 CHECK_ARITY(2);
5838 CAST_TO_STRING;
5839 find = valuePop(ctxt);
5840 CAST_TO_STRING;
5841 str = valuePop(ctxt);
5842
5843 target = xmlBufferCreate();
5844 if (target) {
5845 point = xmlStrstr(str->stringval, find->stringval);
5846 if (point) {
5847 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5848 xmlBufferAdd(target, &str->stringval[offset],
5849 xmlStrlen(str->stringval) - offset);
5850 }
5851 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5852 xmlBufferFree(target);
5853 }
5854
5855 xmlXPathFreeObject(str);
5856 xmlXPathFreeObject(find);
5857}
5858
5859/**
5860 * xmlXPathNormalizeFunction:
5861 * @ctxt: the XPath Parser context
5862 * @nargs: the number of arguments
5863 *
5864 * Implement the normalize-space() XPath function
5865 * string normalize-space(string?)
5866 * The normalize-space function returns the argument string with white
5867 * space normalized by stripping leading and trailing whitespace
5868 * and replacing sequences of whitespace characters by a single
5869 * space. Whitespace characters are the same allowed by the S production
5870 * in XML. If the argument is omitted, it defaults to the context
5871 * node converted to a string, in other words the value of the context node.
5872 */
5873void
5874xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5875 xmlXPathObjectPtr obj = NULL;
5876 xmlChar *source = NULL;
5877 xmlBufferPtr target;
5878 xmlChar blank;
5879
5880 if (nargs == 0) {
5881 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005882 valuePush(ctxt,
5883 xmlXPathWrapString(
5884 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005885 nargs = 1;
5886 }
5887
5888 CHECK_ARITY(1);
5889 CAST_TO_STRING;
5890 CHECK_TYPE(XPATH_STRING);
5891 obj = valuePop(ctxt);
5892 source = obj->stringval;
5893
5894 target = xmlBufferCreate();
5895 if (target && source) {
5896
5897 /* Skip leading whitespaces */
5898 while (IS_BLANK(*source))
5899 source++;
5900
5901 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5902 blank = 0;
5903 while (*source) {
5904 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005905 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005906 } else {
5907 if (blank) {
5908 xmlBufferAdd(target, &blank, 1);
5909 blank = 0;
5910 }
5911 xmlBufferAdd(target, source, 1);
5912 }
5913 source++;
5914 }
5915
5916 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5917 xmlBufferFree(target);
5918 }
5919 xmlXPathFreeObject(obj);
5920}
5921
5922/**
5923 * xmlXPathTranslateFunction:
5924 * @ctxt: the XPath Parser context
5925 * @nargs: the number of arguments
5926 *
5927 * Implement the translate() XPath function
5928 * string translate(string, string, string)
5929 * The translate function returns the first argument string with
5930 * occurrences of characters in the second argument string replaced
5931 * by the character at the corresponding position in the third argument
5932 * string. For example, translate("bar","abc","ABC") returns the string
5933 * BAr. If there is a character in the second argument string with no
5934 * character at a corresponding position in the third argument string
5935 * (because the second argument string is longer than the third argument
5936 * string), then occurrences of that character in the first argument
5937 * string are removed. For example, translate("--aaa--","abc-","ABC")
5938 * returns "AAA". If a character occurs more than once in second
5939 * argument string, then the first occurrence determines the replacement
5940 * character. If the third argument string is longer than the second
5941 * argument string, then excess characters are ignored.
5942 */
5943void
5944xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005945 xmlXPathObjectPtr str;
5946 xmlXPathObjectPtr from;
5947 xmlXPathObjectPtr to;
5948 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005949 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005950 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005951 xmlChar *point;
5952 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005953
Daniel Veillarde043ee12001-04-16 14:08:07 +00005954 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005955
Daniel Veillarde043ee12001-04-16 14:08:07 +00005956 CAST_TO_STRING;
5957 to = valuePop(ctxt);
5958 CAST_TO_STRING;
5959 from = valuePop(ctxt);
5960 CAST_TO_STRING;
5961 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005962
Daniel Veillarde043ee12001-04-16 14:08:07 +00005963 target = xmlBufferCreate();
5964 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005965 max = xmlUTF8Strlen(to->stringval);
5966 for (cptr = str->stringval; (ch=*cptr); ) {
5967 offset = xmlUTF8Strloc(from->stringval, cptr);
5968 if (offset >= 0) {
5969 if (offset < max) {
5970 point = xmlUTF8Strpos(to->stringval, offset);
5971 if (point)
5972 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5973 }
5974 } else
5975 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5976
5977 /* Step to next character in input */
5978 cptr++;
5979 if ( ch & 0x80 ) {
5980 /* if not simple ascii, verify proper format */
5981 if ( (ch & 0xc0) != 0xc0 ) {
5982 xmlGenericError(xmlGenericErrorContext,
5983 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5984 break;
5985 }
5986 /* then skip over remaining bytes for this char */
5987 while ( (ch <<= 1) & 0x80 )
5988 if ( (*cptr++ & 0xc0) != 0x80 ) {
5989 xmlGenericError(xmlGenericErrorContext,
5990 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5991 break;
5992 }
5993 if (ch & 0x80) /* must have had error encountered */
5994 break;
5995 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005996 }
Owen Taylor3473f882001-02-23 17:55:21 +00005997 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005998 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5999 xmlBufferFree(target);
6000 xmlXPathFreeObject(str);
6001 xmlXPathFreeObject(from);
6002 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006003}
6004
6005/**
6006 * xmlXPathBooleanFunction:
6007 * @ctxt: the XPath Parser context
6008 * @nargs: the number of arguments
6009 *
6010 * Implement the boolean() XPath function
6011 * boolean boolean(object)
6012 * he boolean function converts its argument to a boolean as follows:
6013 * - a number is true if and only if it is neither positive or
6014 * negative zero nor NaN
6015 * - a node-set is true if and only if it is non-empty
6016 * - a string is true if and only if its length is non-zero
6017 */
6018void
6019xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6020 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006021
6022 CHECK_ARITY(1);
6023 cur = valuePop(ctxt);
6024 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006025 cur = xmlXPathConvertBoolean(cur);
6026 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006027}
6028
6029/**
6030 * xmlXPathNotFunction:
6031 * @ctxt: the XPath Parser context
6032 * @nargs: the number of arguments
6033 *
6034 * Implement the not() XPath function
6035 * boolean not(boolean)
6036 * The not function returns true if its argument is false,
6037 * and false otherwise.
6038 */
6039void
6040xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6041 CHECK_ARITY(1);
6042 CAST_TO_BOOLEAN;
6043 CHECK_TYPE(XPATH_BOOLEAN);
6044 ctxt->value->boolval = ! ctxt->value->boolval;
6045}
6046
6047/**
6048 * xmlXPathTrueFunction:
6049 * @ctxt: the XPath Parser context
6050 * @nargs: the number of arguments
6051 *
6052 * Implement the true() XPath function
6053 * boolean true()
6054 */
6055void
6056xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6057 CHECK_ARITY(0);
6058 valuePush(ctxt, xmlXPathNewBoolean(1));
6059}
6060
6061/**
6062 * xmlXPathFalseFunction:
6063 * @ctxt: the XPath Parser context
6064 * @nargs: the number of arguments
6065 *
6066 * Implement the false() XPath function
6067 * boolean false()
6068 */
6069void
6070xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6071 CHECK_ARITY(0);
6072 valuePush(ctxt, xmlXPathNewBoolean(0));
6073}
6074
6075/**
6076 * xmlXPathLangFunction:
6077 * @ctxt: the XPath Parser context
6078 * @nargs: the number of arguments
6079 *
6080 * Implement the lang() XPath function
6081 * boolean lang(string)
6082 * The lang function returns true or false depending on whether the
6083 * language of the context node as specified by xml:lang attributes
6084 * is the same as or is a sublanguage of the language specified by
6085 * the argument string. The language of the context node is determined
6086 * by the value of the xml:lang attribute on the context node, or, if
6087 * the context node has no xml:lang attribute, by the value of the
6088 * xml:lang attribute on the nearest ancestor of the context node that
6089 * has an xml:lang attribute. If there is no such attribute, then lang
6090 * returns false. If there is such an attribute, then lang returns
6091 * true if the attribute value is equal to the argument ignoring case,
6092 * or if there is some suffix starting with - such that the attribute
6093 * value is equal to the argument ignoring that suffix of the attribute
6094 * value and ignoring case.
6095 */
6096void
6097xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6098 xmlXPathObjectPtr val;
6099 const xmlChar *theLang;
6100 const xmlChar *lang;
6101 int ret = 0;
6102 int i;
6103
6104 CHECK_ARITY(1);
6105 CAST_TO_STRING;
6106 CHECK_TYPE(XPATH_STRING);
6107 val = valuePop(ctxt);
6108 lang = val->stringval;
6109 theLang = xmlNodeGetLang(ctxt->context->node);
6110 if ((theLang != NULL) && (lang != NULL)) {
6111 for (i = 0;lang[i] != 0;i++)
6112 if (toupper(lang[i]) != toupper(theLang[i]))
6113 goto not_equal;
6114 ret = 1;
6115 }
6116not_equal:
6117 xmlXPathFreeObject(val);
6118 valuePush(ctxt, xmlXPathNewBoolean(ret));
6119}
6120
6121/**
6122 * xmlXPathNumberFunction:
6123 * @ctxt: the XPath Parser context
6124 * @nargs: the number of arguments
6125 *
6126 * Implement the number() XPath function
6127 * number number(object?)
6128 */
6129void
6130xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6131 xmlXPathObjectPtr cur;
6132 double res;
6133
6134 if (nargs == 0) {
6135 if (ctxt->context->node == NULL) {
6136 valuePush(ctxt, xmlXPathNewFloat(0.0));
6137 } else {
6138 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6139
6140 res = xmlXPathStringEvalNumber(content);
6141 valuePush(ctxt, xmlXPathNewFloat(res));
6142 xmlFree(content);
6143 }
6144 return;
6145 }
6146
6147 CHECK_ARITY(1);
6148 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006149 cur = xmlXPathConvertNumber(cur);
6150 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006151}
6152
6153/**
6154 * xmlXPathSumFunction:
6155 * @ctxt: the XPath Parser context
6156 * @nargs: the number of arguments
6157 *
6158 * Implement the sum() XPath function
6159 * number sum(node-set)
6160 * The sum function returns the sum of the values of the nodes in
6161 * the argument node-set.
6162 */
6163void
6164xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6165 xmlXPathObjectPtr cur;
6166 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006167 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006168
6169 CHECK_ARITY(1);
6170 if ((ctxt->value == NULL) ||
6171 ((ctxt->value->type != XPATH_NODESET) &&
6172 (ctxt->value->type != XPATH_XSLT_TREE)))
6173 XP_ERROR(XPATH_INVALID_TYPE);
6174 cur = valuePop(ctxt);
6175
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006176 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006177 valuePush(ctxt, xmlXPathNewFloat(0.0));
6178 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006179 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6180 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006181 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006182 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006183 }
6184 xmlXPathFreeObject(cur);
6185}
6186
6187/**
6188 * xmlXPathFloorFunction:
6189 * @ctxt: the XPath Parser context
6190 * @nargs: the number of arguments
6191 *
6192 * Implement the floor() XPath function
6193 * number floor(number)
6194 * The floor function returns the largest (closest to positive infinity)
6195 * number that is not greater than the argument and that is an integer.
6196 */
6197void
6198xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6199 CHECK_ARITY(1);
6200 CAST_TO_NUMBER;
6201 CHECK_TYPE(XPATH_NUMBER);
6202#if 0
6203 ctxt->value->floatval = floor(ctxt->value->floatval);
6204#else
6205 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6206 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6207#endif
6208}
6209
6210/**
6211 * xmlXPathCeilingFunction:
6212 * @ctxt: the XPath Parser context
6213 * @nargs: the number of arguments
6214 *
6215 * Implement the ceiling() XPath function
6216 * number ceiling(number)
6217 * The ceiling function returns the smallest (closest to negative infinity)
6218 * number that is not less than the argument and that is an integer.
6219 */
6220void
6221xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6222 double f;
6223
6224 CHECK_ARITY(1);
6225 CAST_TO_NUMBER;
6226 CHECK_TYPE(XPATH_NUMBER);
6227
6228#if 0
6229 ctxt->value->floatval = ceil(ctxt->value->floatval);
6230#else
6231 f = (double)((int) ctxt->value->floatval);
6232 if (f != ctxt->value->floatval)
6233 ctxt->value->floatval = f + 1;
6234#endif
6235}
6236
6237/**
6238 * xmlXPathRoundFunction:
6239 * @ctxt: the XPath Parser context
6240 * @nargs: the number of arguments
6241 *
6242 * Implement the round() XPath function
6243 * number round(number)
6244 * The round function returns the number that is closest to the
6245 * argument and that is an integer. If there are two such numbers,
6246 * then the one that is even is returned.
6247 */
6248void
6249xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6250 double f;
6251
6252 CHECK_ARITY(1);
6253 CAST_TO_NUMBER;
6254 CHECK_TYPE(XPATH_NUMBER);
6255
Daniel Veillardcda96922001-08-21 10:56:31 +00006256 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6257 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6258 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006259 (ctxt->value->floatval == 0.0))
6260 return;
6261
6262#if 0
6263 f = floor(ctxt->value->floatval);
6264#else
6265 f = (double)((int) ctxt->value->floatval);
6266#endif
6267 if (ctxt->value->floatval < f + 0.5)
6268 ctxt->value->floatval = f;
6269 else
6270 ctxt->value->floatval = f + 1;
6271}
6272
6273/************************************************************************
6274 * *
6275 * The Parser *
6276 * *
6277 ************************************************************************/
6278
6279/*
6280 * a couple of forward declarations since we use a recursive call based
6281 * implementation.
6282 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006283static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006284static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006285static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006286#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006287static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6288#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006289#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006290static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006291#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006292static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6293 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006294
6295/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006296 * xmlXPathCurrentChar:
6297 * @ctxt: the XPath parser context
6298 * @cur: pointer to the beginning of the char
6299 * @len: pointer to the length of the char read
6300 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006301 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006302 * bytes in the input buffer.
6303 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006304 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006305 */
6306
6307static int
6308xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6309 unsigned char c;
6310 unsigned int val;
6311 const xmlChar *cur;
6312
6313 if (ctxt == NULL)
6314 return(0);
6315 cur = ctxt->cur;
6316
6317 /*
6318 * We are supposed to handle UTF8, check it's valid
6319 * From rfc2044: encoding of the Unicode values on UTF-8:
6320 *
6321 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6322 * 0000 0000-0000 007F 0xxxxxxx
6323 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6324 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6325 *
6326 * Check for the 0x110000 limit too
6327 */
6328 c = *cur;
6329 if (c & 0x80) {
6330 if ((cur[1] & 0xc0) != 0x80)
6331 goto encoding_error;
6332 if ((c & 0xe0) == 0xe0) {
6333
6334 if ((cur[2] & 0xc0) != 0x80)
6335 goto encoding_error;
6336 if ((c & 0xf0) == 0xf0) {
6337 if (((c & 0xf8) != 0xf0) ||
6338 ((cur[3] & 0xc0) != 0x80))
6339 goto encoding_error;
6340 /* 4-byte code */
6341 *len = 4;
6342 val = (cur[0] & 0x7) << 18;
6343 val |= (cur[1] & 0x3f) << 12;
6344 val |= (cur[2] & 0x3f) << 6;
6345 val |= cur[3] & 0x3f;
6346 } else {
6347 /* 3-byte code */
6348 *len = 3;
6349 val = (cur[0] & 0xf) << 12;
6350 val |= (cur[1] & 0x3f) << 6;
6351 val |= cur[2] & 0x3f;
6352 }
6353 } else {
6354 /* 2-byte code */
6355 *len = 2;
6356 val = (cur[0] & 0x1f) << 6;
6357 val |= cur[1] & 0x3f;
6358 }
6359 if (!IS_CHAR(val)) {
6360 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6361 }
6362 return(val);
6363 } else {
6364 /* 1-byte code */
6365 *len = 1;
6366 return((int) *cur);
6367 }
6368encoding_error:
6369 /*
6370 * If we detect an UTF8 error that probably mean that the
6371 * input encoding didn't get properly advertized in the
6372 * declaration header. Report the error and switch the encoding
6373 * to ISO-Latin-1 (if you don't like this policy, just declare the
6374 * encoding !)
6375 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006376 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006377 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006378}
6379
6380/**
Owen Taylor3473f882001-02-23 17:55:21 +00006381 * xmlXPathParseNCName:
6382 * @ctxt: the XPath Parser context
6383 *
6384 * parse an XML namespace non qualified name.
6385 *
6386 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6387 *
6388 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6389 * CombiningChar | Extender
6390 *
6391 * Returns the namespace name or NULL
6392 */
6393
6394xmlChar *
6395xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006396 const xmlChar *in;
6397 xmlChar *ret;
6398 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006399
Daniel Veillard2156a562001-04-28 12:24:34 +00006400 /*
6401 * Accelerator for simple ASCII names
6402 */
6403 in = ctxt->cur;
6404 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6405 ((*in >= 0x41) && (*in <= 0x5A)) ||
6406 (*in == '_')) {
6407 in++;
6408 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6409 ((*in >= 0x41) && (*in <= 0x5A)) ||
6410 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006411 (*in == '_') || (*in == '.') ||
6412 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006413 in++;
6414 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6415 (*in == '[') || (*in == ']') || (*in == ':') ||
6416 (*in == '@') || (*in == '*')) {
6417 count = in - ctxt->cur;
6418 if (count == 0)
6419 return(NULL);
6420 ret = xmlStrndup(ctxt->cur, count);
6421 ctxt->cur = in;
6422 return(ret);
6423 }
6424 }
6425 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006426}
6427
Daniel Veillard2156a562001-04-28 12:24:34 +00006428
Owen Taylor3473f882001-02-23 17:55:21 +00006429/**
6430 * xmlXPathParseQName:
6431 * @ctxt: the XPath Parser context
6432 * @prefix: a xmlChar **
6433 *
6434 * parse an XML qualified name
6435 *
6436 * [NS 5] QName ::= (Prefix ':')? LocalPart
6437 *
6438 * [NS 6] Prefix ::= NCName
6439 *
6440 * [NS 7] LocalPart ::= NCName
6441 *
6442 * Returns the function returns the local part, and prefix is updated
6443 * to get the Prefix if any.
6444 */
6445
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006446static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006447xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6448 xmlChar *ret = NULL;
6449
6450 *prefix = NULL;
6451 ret = xmlXPathParseNCName(ctxt);
6452 if (CUR == ':') {
6453 *prefix = ret;
6454 NEXT;
6455 ret = xmlXPathParseNCName(ctxt);
6456 }
6457 return(ret);
6458}
6459
6460/**
6461 * xmlXPathParseName:
6462 * @ctxt: the XPath Parser context
6463 *
6464 * parse an XML name
6465 *
6466 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6467 * CombiningChar | Extender
6468 *
6469 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6470 *
6471 * Returns the namespace name or NULL
6472 */
6473
6474xmlChar *
6475xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006476 const xmlChar *in;
6477 xmlChar *ret;
6478 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006479
Daniel Veillard61d80a22001-04-27 17:13:01 +00006480 /*
6481 * Accelerator for simple ASCII names
6482 */
6483 in = ctxt->cur;
6484 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6485 ((*in >= 0x41) && (*in <= 0x5A)) ||
6486 (*in == '_') || (*in == ':')) {
6487 in++;
6488 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6489 ((*in >= 0x41) && (*in <= 0x5A)) ||
6490 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006491 (*in == '_') || (*in == '-') ||
6492 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006493 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006494 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006495 count = in - ctxt->cur;
6496 ret = xmlStrndup(ctxt->cur, count);
6497 ctxt->cur = in;
6498 return(ret);
6499 }
6500 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006501 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006502}
6503
Daniel Veillard61d80a22001-04-27 17:13:01 +00006504static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006505xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006506 xmlChar buf[XML_MAX_NAMELEN + 5];
6507 int len = 0, l;
6508 int c;
6509
6510 /*
6511 * Handler for more complex cases
6512 */
6513 c = CUR_CHAR(l);
6514 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006515 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6516 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006517 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006518 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006519 return(NULL);
6520 }
6521
6522 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6523 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6524 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006525 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006526 (IS_COMBINING(c)) ||
6527 (IS_EXTENDER(c)))) {
6528 COPY_BUF(l,buf,len,c);
6529 NEXTL(l);
6530 c = CUR_CHAR(l);
6531 if (len >= XML_MAX_NAMELEN) {
6532 /*
6533 * Okay someone managed to make a huge name, so he's ready to pay
6534 * for the processing speed.
6535 */
6536 xmlChar *buffer;
6537 int max = len * 2;
6538
6539 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6540 if (buffer == NULL) {
6541 XP_ERROR0(XPATH_MEMORY_ERROR);
6542 }
6543 memcpy(buffer, buf, len);
6544 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6545 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006546 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006547 (IS_COMBINING(c)) ||
6548 (IS_EXTENDER(c))) {
6549 if (len + 10 > max) {
6550 max *= 2;
6551 buffer = (xmlChar *) xmlRealloc(buffer,
6552 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006553 if (buffer == NULL) {
6554 XP_ERROR0(XPATH_MEMORY_ERROR);
6555 }
6556 }
6557 COPY_BUF(l,buffer,len,c);
6558 NEXTL(l);
6559 c = CUR_CHAR(l);
6560 }
6561 buffer[len] = 0;
6562 return(buffer);
6563 }
6564 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006565 if (len == 0)
6566 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006567 return(xmlStrndup(buf, len));
6568}
Owen Taylor3473f882001-02-23 17:55:21 +00006569/**
6570 * xmlXPathStringEvalNumber:
6571 * @str: A string to scan
6572 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006573 * [30a] Float ::= Number ('e' Digits?)?
6574 *
Owen Taylor3473f882001-02-23 17:55:21 +00006575 * [30] Number ::= Digits ('.' Digits?)?
6576 * | '.' Digits
6577 * [31] Digits ::= [0-9]+
6578 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006579 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006580 * In complement of the Number expression, this function also handles
6581 * negative values : '-' Number.
6582 *
6583 * Returns the double value.
6584 */
6585double
6586xmlXPathStringEvalNumber(const xmlChar *str) {
6587 const xmlChar *cur = str;
6588 double ret = 0.0;
6589 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006590 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006591 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006592 int exponent = 0;
6593 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006594#ifdef __GNUC__
6595 unsigned long tmp = 0;
6596#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006597
Owen Taylor3473f882001-02-23 17:55:21 +00006598 while (IS_BLANK(*cur)) cur++;
6599 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6600 return(xmlXPathNAN);
6601 }
6602 if (*cur == '-') {
6603 isneg = 1;
6604 cur++;
6605 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006606
6607#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006608 /*
Daniel Veillardb06c6142001-08-27 14:26:30 +00006609 * tmp is a workaround against a gcc compiler bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006610 */
Owen Taylor3473f882001-02-23 17:55:21 +00006611 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006612 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006613 ok = 1;
6614 cur++;
6615 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006616 ret = (double) tmp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006617#else
6618 while ((*cur >= '0') && (*cur <= '9')) {
6619 ret = ret * 10 + (*cur - '0');
6620 ok = 1;
6621 cur++;
6622 }
6623#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006624
Owen Taylor3473f882001-02-23 17:55:21 +00006625 if (*cur == '.') {
6626 cur++;
6627 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6628 return(xmlXPathNAN);
6629 }
6630 while ((*cur >= '0') && (*cur <= '9')) {
6631 mult /= 10;
6632 ret = ret + (*cur - '0') * mult;
6633 cur++;
6634 }
6635 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006636 if ((*cur == 'e') || (*cur == 'E')) {
6637 cur++;
6638 if (*cur == '-') {
6639 is_exponent_negative = 1;
6640 cur++;
6641 }
6642 while ((*cur >= '0') && (*cur <= '9')) {
6643 exponent = exponent * 10 + (*cur - '0');
6644 cur++;
6645 }
6646 }
Owen Taylor3473f882001-02-23 17:55:21 +00006647 while (IS_BLANK(*cur)) cur++;
6648 if (*cur != 0) return(xmlXPathNAN);
6649 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006650 if (is_exponent_negative) exponent = -exponent;
6651 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006652 return(ret);
6653}
6654
6655/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006656 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006657 * @ctxt: the XPath Parser context
6658 *
6659 * [30] Number ::= Digits ('.' Digits?)?
6660 * | '.' Digits
6661 * [31] Digits ::= [0-9]+
6662 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006663 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006664 *
6665 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006666static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006667xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6668{
Owen Taylor3473f882001-02-23 17:55:21 +00006669 double ret = 0.0;
6670 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006671 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006672 int exponent = 0;
6673 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006674
6675 CHECK_ERROR;
6676 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6677 XP_ERROR(XPATH_NUMBER_ERROR);
6678 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006679 /*
6680 * Try to work around a gcc optimizer bug
6681 */
Owen Taylor3473f882001-02-23 17:55:21 +00006682 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006683 tmp = tmp * 10 + (CUR - '0');
6684 ok = 1;
6685 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006686 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006687 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006688 if (CUR == '.') {
6689 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006690 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6691 XP_ERROR(XPATH_NUMBER_ERROR);
6692 }
6693 while ((CUR >= '0') && (CUR <= '9')) {
6694 mult /= 10;
6695 ret = ret + (CUR - '0') * mult;
6696 NEXT;
6697 }
Owen Taylor3473f882001-02-23 17:55:21 +00006698 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006699 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006700 NEXT;
6701 if (CUR == '-') {
6702 is_exponent_negative = 1;
6703 NEXT;
6704 }
6705 while ((CUR >= '0') && (CUR <= '9')) {
6706 exponent = exponent * 10 + (CUR - '0');
6707 NEXT;
6708 }
6709 if (is_exponent_negative)
6710 exponent = -exponent;
6711 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006712 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006713 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006714 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006715}
6716
6717/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006718 * xmlXPathParseLiteral:
6719 * @ctxt: the XPath Parser context
6720 *
6721 * Parse a Literal
6722 *
6723 * [29] Literal ::= '"' [^"]* '"'
6724 * | "'" [^']* "'"
6725 *
6726 * Returns the value found or NULL in case of error
6727 */
6728static xmlChar *
6729xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6730 const xmlChar *q;
6731 xmlChar *ret = NULL;
6732
6733 if (CUR == '"') {
6734 NEXT;
6735 q = CUR_PTR;
6736 while ((IS_CHAR(CUR)) && (CUR != '"'))
6737 NEXT;
6738 if (!IS_CHAR(CUR)) {
6739 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6740 } else {
6741 ret = xmlStrndup(q, CUR_PTR - q);
6742 NEXT;
6743 }
6744 } else if (CUR == '\'') {
6745 NEXT;
6746 q = CUR_PTR;
6747 while ((IS_CHAR(CUR)) && (CUR != '\''))
6748 NEXT;
6749 if (!IS_CHAR(CUR)) {
6750 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6751 } else {
6752 ret = xmlStrndup(q, CUR_PTR - q);
6753 NEXT;
6754 }
6755 } else {
6756 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6757 }
6758 return(ret);
6759}
6760
6761/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006762 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006763 * @ctxt: the XPath Parser context
6764 *
6765 * Parse a Literal and push it on the stack.
6766 *
6767 * [29] Literal ::= '"' [^"]* '"'
6768 * | "'" [^']* "'"
6769 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006770 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006771 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006772static void
6773xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006774 const xmlChar *q;
6775 xmlChar *ret = NULL;
6776
6777 if (CUR == '"') {
6778 NEXT;
6779 q = CUR_PTR;
6780 while ((IS_CHAR(CUR)) && (CUR != '"'))
6781 NEXT;
6782 if (!IS_CHAR(CUR)) {
6783 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6784 } else {
6785 ret = xmlStrndup(q, CUR_PTR - q);
6786 NEXT;
6787 }
6788 } else if (CUR == '\'') {
6789 NEXT;
6790 q = CUR_PTR;
6791 while ((IS_CHAR(CUR)) && (CUR != '\''))
6792 NEXT;
6793 if (!IS_CHAR(CUR)) {
6794 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6795 } else {
6796 ret = xmlStrndup(q, CUR_PTR - q);
6797 NEXT;
6798 }
6799 } else {
6800 XP_ERROR(XPATH_START_LITERAL_ERROR);
6801 }
6802 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006803 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6804 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006805 xmlFree(ret);
6806}
6807
6808/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006809 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006810 * @ctxt: the XPath Parser context
6811 *
6812 * Parse a VariableReference, evaluate it and push it on the stack.
6813 *
6814 * The variable bindings consist of a mapping from variable names
6815 * to variable values. The value of a variable is an object, which
6816 * of any of the types that are possible for the value of an expression,
6817 * and may also be of additional types not specified here.
6818 *
6819 * Early evaluation is possible since:
6820 * The variable bindings [...] used to evaluate a subexpression are
6821 * always the same as those used to evaluate the containing expression.
6822 *
6823 * [36] VariableReference ::= '$' QName
6824 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006825static void
6826xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006827 xmlChar *name;
6828 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006829
6830 SKIP_BLANKS;
6831 if (CUR != '$') {
6832 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6833 }
6834 NEXT;
6835 name = xmlXPathParseQName(ctxt, &prefix);
6836 if (name == NULL) {
6837 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6838 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006839 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006840 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6841 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006842 SKIP_BLANKS;
6843}
6844
6845/**
6846 * xmlXPathIsNodeType:
6847 * @ctxt: the XPath Parser context
6848 * @name: a name string
6849 *
6850 * Is the name given a NodeType one.
6851 *
6852 * [38] NodeType ::= 'comment'
6853 * | 'text'
6854 * | 'processing-instruction'
6855 * | 'node'
6856 *
6857 * Returns 1 if true 0 otherwise
6858 */
6859int
6860xmlXPathIsNodeType(const xmlChar *name) {
6861 if (name == NULL)
6862 return(0);
6863
Daniel Veillard1971ee22002-01-31 20:29:19 +00006864 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00006865 return(1);
6866 if (xmlStrEqual(name, BAD_CAST "text"))
6867 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00006868 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00006869 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00006870 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00006871 return(1);
6872 return(0);
6873}
6874
6875/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006876 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006877 * @ctxt: the XPath Parser context
6878 *
6879 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6880 * [17] Argument ::= Expr
6881 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006882 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006883 * pushed on the stack
6884 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006885static void
6886xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006887 xmlChar *name;
6888 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006889 int nbargs = 0;
6890
6891 name = xmlXPathParseQName(ctxt, &prefix);
6892 if (name == NULL) {
6893 XP_ERROR(XPATH_EXPR_ERROR);
6894 }
6895 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006896#ifdef DEBUG_EXPR
6897 if (prefix == NULL)
6898 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6899 name);
6900 else
6901 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6902 prefix, name);
6903#endif
6904
Owen Taylor3473f882001-02-23 17:55:21 +00006905 if (CUR != '(') {
6906 XP_ERROR(XPATH_EXPR_ERROR);
6907 }
6908 NEXT;
6909 SKIP_BLANKS;
6910
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006911 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006912 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006913 int op1 = ctxt->comp->last;
6914 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006915 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006916 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006917 nbargs++;
6918 if (CUR == ')') break;
6919 if (CUR != ',') {
6920 XP_ERROR(XPATH_EXPR_ERROR);
6921 }
6922 NEXT;
6923 SKIP_BLANKS;
6924 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006925 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6926 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006927 NEXT;
6928 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006929}
6930
6931/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006932 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006933 * @ctxt: the XPath Parser context
6934 *
6935 * [15] PrimaryExpr ::= VariableReference
6936 * | '(' Expr ')'
6937 * | Literal
6938 * | Number
6939 * | FunctionCall
6940 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006941 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006942 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006943static void
6944xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006945 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006946 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006947 else if (CUR == '(') {
6948 NEXT;
6949 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006950 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006951 if (CUR != ')') {
6952 XP_ERROR(XPATH_EXPR_ERROR);
6953 }
6954 NEXT;
6955 SKIP_BLANKS;
6956 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006957 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006958 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006959 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006960 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006961 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006962 }
6963 SKIP_BLANKS;
6964}
6965
6966/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006967 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006968 * @ctxt: the XPath Parser context
6969 *
6970 * [20] FilterExpr ::= PrimaryExpr
6971 * | FilterExpr Predicate
6972 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006973 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006974 * Square brackets are used to filter expressions in the same way that
6975 * they are used in location paths. It is an error if the expression to
6976 * be filtered does not evaluate to a node-set. The context node list
6977 * used for evaluating the expression in square brackets is the node-set
6978 * to be filtered listed in document order.
6979 */
6980
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006981static void
6982xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6983 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006984 CHECK_ERROR;
6985 SKIP_BLANKS;
6986
6987 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006988 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006989 SKIP_BLANKS;
6990 }
6991
6992
6993}
6994
6995/**
6996 * xmlXPathScanName:
6997 * @ctxt: the XPath Parser context
6998 *
6999 * Trickery: parse an XML name but without consuming the input flow
7000 * Needed to avoid insanity in the parser state.
7001 *
7002 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7003 * CombiningChar | Extender
7004 *
7005 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7006 *
7007 * [6] Names ::= Name (S Name)*
7008 *
7009 * Returns the Name parsed or NULL
7010 */
7011
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007012static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007013xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7014 xmlChar buf[XML_MAX_NAMELEN];
7015 int len = 0;
7016
7017 SKIP_BLANKS;
7018 if (!IS_LETTER(CUR) && (CUR != '_') &&
7019 (CUR != ':')) {
7020 return(NULL);
7021 }
7022
7023 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7024 (NXT(len) == '.') || (NXT(len) == '-') ||
7025 (NXT(len) == '_') || (NXT(len) == ':') ||
7026 (IS_COMBINING(NXT(len))) ||
7027 (IS_EXTENDER(NXT(len)))) {
7028 buf[len] = NXT(len);
7029 len++;
7030 if (len >= XML_MAX_NAMELEN) {
7031 xmlGenericError(xmlGenericErrorContext,
7032 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7033 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7034 (NXT(len) == '.') || (NXT(len) == '-') ||
7035 (NXT(len) == '_') || (NXT(len) == ':') ||
7036 (IS_COMBINING(NXT(len))) ||
7037 (IS_EXTENDER(NXT(len))))
7038 len++;
7039 break;
7040 }
7041 }
7042 return(xmlStrndup(buf, len));
7043}
7044
7045/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007046 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007047 * @ctxt: the XPath Parser context
7048 *
7049 * [19] PathExpr ::= LocationPath
7050 * | FilterExpr
7051 * | FilterExpr '/' RelativeLocationPath
7052 * | FilterExpr '//' RelativeLocationPath
7053 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007054 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007055 * The / operator and // operators combine an arbitrary expression
7056 * and a relative location path. It is an error if the expression
7057 * does not evaluate to a node-set.
7058 * The / operator does composition in the same way as when / is
7059 * used in a location path. As in location paths, // is short for
7060 * /descendant-or-self::node()/.
7061 */
7062
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007063static void
7064xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007065 int lc = 1; /* Should we branch to LocationPath ? */
7066 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7067
7068 SKIP_BLANKS;
7069 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7070 (CUR == '\'') || (CUR == '"')) {
7071 lc = 0;
7072 } else if (CUR == '*') {
7073 /* relative or absolute location path */
7074 lc = 1;
7075 } else if (CUR == '/') {
7076 /* relative or absolute location path */
7077 lc = 1;
7078 } else if (CUR == '@') {
7079 /* relative abbreviated attribute location path */
7080 lc = 1;
7081 } else if (CUR == '.') {
7082 /* relative abbreviated attribute location path */
7083 lc = 1;
7084 } else {
7085 /*
7086 * Problem is finding if we have a name here whether it's:
7087 * - a nodetype
7088 * - a function call in which case it's followed by '('
7089 * - an axis in which case it's followed by ':'
7090 * - a element name
7091 * We do an a priori analysis here rather than having to
7092 * maintain parsed token content through the recursive function
7093 * calls. This looks uglier but makes the code quite easier to
7094 * read/write/debug.
7095 */
7096 SKIP_BLANKS;
7097 name = xmlXPathScanName(ctxt);
7098 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7099#ifdef DEBUG_STEP
7100 xmlGenericError(xmlGenericErrorContext,
7101 "PathExpr: Axis\n");
7102#endif
7103 lc = 1;
7104 xmlFree(name);
7105 } else if (name != NULL) {
7106 int len =xmlStrlen(name);
7107 int blank = 0;
7108
7109
7110 while (NXT(len) != 0) {
7111 if (NXT(len) == '/') {
7112 /* element name */
7113#ifdef DEBUG_STEP
7114 xmlGenericError(xmlGenericErrorContext,
7115 "PathExpr: AbbrRelLocation\n");
7116#endif
7117 lc = 1;
7118 break;
7119 } else if (IS_BLANK(NXT(len))) {
7120 /* skip to next */
7121 blank = 1;
7122 } else if (NXT(len) == ':') {
7123#ifdef DEBUG_STEP
7124 xmlGenericError(xmlGenericErrorContext,
7125 "PathExpr: AbbrRelLocation\n");
7126#endif
7127 lc = 1;
7128 break;
7129 } else if ((NXT(len) == '(')) {
7130 /* Note Type or Function */
7131 if (xmlXPathIsNodeType(name)) {
7132#ifdef DEBUG_STEP
7133 xmlGenericError(xmlGenericErrorContext,
7134 "PathExpr: Type search\n");
7135#endif
7136 lc = 1;
7137 } else {
7138#ifdef DEBUG_STEP
7139 xmlGenericError(xmlGenericErrorContext,
7140 "PathExpr: function call\n");
7141#endif
7142 lc = 0;
7143 }
7144 break;
7145 } else if ((NXT(len) == '[')) {
7146 /* element name */
7147#ifdef DEBUG_STEP
7148 xmlGenericError(xmlGenericErrorContext,
7149 "PathExpr: AbbrRelLocation\n");
7150#endif
7151 lc = 1;
7152 break;
7153 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7154 (NXT(len) == '=')) {
7155 lc = 1;
7156 break;
7157 } else {
7158 lc = 1;
7159 break;
7160 }
7161 len++;
7162 }
7163 if (NXT(len) == 0) {
7164#ifdef DEBUG_STEP
7165 xmlGenericError(xmlGenericErrorContext,
7166 "PathExpr: AbbrRelLocation\n");
7167#endif
7168 /* element name */
7169 lc = 1;
7170 }
7171 xmlFree(name);
7172 } else {
7173 /* make sure all cases are covered explicitely */
7174 XP_ERROR(XPATH_EXPR_ERROR);
7175 }
7176 }
7177
7178 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007179 if (CUR == '/') {
7180 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7181 } else {
7182 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007183 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007184 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007185 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007186 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007187 CHECK_ERROR;
7188 if ((CUR == '/') && (NXT(1) == '/')) {
7189 SKIP(2);
7190 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007191
7192 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7193 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7194 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7195
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007196 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007197 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007198 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007199 }
7200 }
7201 SKIP_BLANKS;
7202}
7203
7204/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007205 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007206 * @ctxt: the XPath Parser context
7207 *
7208 * [18] UnionExpr ::= PathExpr
7209 * | UnionExpr '|' PathExpr
7210 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007211 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007212 */
7213
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007214static void
7215xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7216 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007217 CHECK_ERROR;
7218 SKIP_BLANKS;
7219 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007220 int op1 = ctxt->comp->last;
7221 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007222
7223 NEXT;
7224 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007225 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007226
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007227 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7228
Owen Taylor3473f882001-02-23 17:55:21 +00007229 SKIP_BLANKS;
7230 }
Owen Taylor3473f882001-02-23 17:55:21 +00007231}
7232
7233/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007234 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007235 * @ctxt: the XPath Parser context
7236 *
7237 * [27] UnaryExpr ::= UnionExpr
7238 * | '-' UnaryExpr
7239 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007240 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007241 */
7242
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007243static void
7244xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007245 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007246 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007247
7248 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007249 while (CUR == '-') {
7250 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007251 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007252 NEXT;
7253 SKIP_BLANKS;
7254 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007255
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007256 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007257 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007258 if (found) {
7259 if (minus)
7260 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7261 else
7262 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007263 }
7264}
7265
7266/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007267 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007268 * @ctxt: the XPath Parser context
7269 *
7270 * [26] MultiplicativeExpr ::= UnaryExpr
7271 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7272 * | MultiplicativeExpr 'div' UnaryExpr
7273 * | MultiplicativeExpr 'mod' UnaryExpr
7274 * [34] MultiplyOperator ::= '*'
7275 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007276 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007277 */
7278
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007279static void
7280xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7281 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007282 CHECK_ERROR;
7283 SKIP_BLANKS;
7284 while ((CUR == '*') ||
7285 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7286 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7287 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007288 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007289
7290 if (CUR == '*') {
7291 op = 0;
7292 NEXT;
7293 } else if (CUR == 'd') {
7294 op = 1;
7295 SKIP(3);
7296 } else if (CUR == 'm') {
7297 op = 2;
7298 SKIP(3);
7299 }
7300 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007301 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007302 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007303 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007304 SKIP_BLANKS;
7305 }
7306}
7307
7308/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007309 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007310 * @ctxt: the XPath Parser context
7311 *
7312 * [25] AdditiveExpr ::= MultiplicativeExpr
7313 * | AdditiveExpr '+' MultiplicativeExpr
7314 * | AdditiveExpr '-' MultiplicativeExpr
7315 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007316 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007317 */
7318
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007319static void
7320xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007321
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007322 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007323 CHECK_ERROR;
7324 SKIP_BLANKS;
7325 while ((CUR == '+') || (CUR == '-')) {
7326 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007327 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007328
7329 if (CUR == '+') plus = 1;
7330 else plus = 0;
7331 NEXT;
7332 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007333 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007334 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007335 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007336 SKIP_BLANKS;
7337 }
7338}
7339
7340/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007341 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007342 * @ctxt: the XPath Parser context
7343 *
7344 * [24] RelationalExpr ::= AdditiveExpr
7345 * | RelationalExpr '<' AdditiveExpr
7346 * | RelationalExpr '>' AdditiveExpr
7347 * | RelationalExpr '<=' AdditiveExpr
7348 * | RelationalExpr '>=' AdditiveExpr
7349 *
7350 * A <= B > C is allowed ? Answer from James, yes with
7351 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7352 * which is basically what got implemented.
7353 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007354 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007355 * on the stack
7356 */
7357
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007358static void
7359xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7360 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007361 CHECK_ERROR;
7362 SKIP_BLANKS;
7363 while ((CUR == '<') ||
7364 (CUR == '>') ||
7365 ((CUR == '<') && (NXT(1) == '=')) ||
7366 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007367 int inf, strict;
7368 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007369
7370 if (CUR == '<') inf = 1;
7371 else inf = 0;
7372 if (NXT(1) == '=') strict = 0;
7373 else strict = 1;
7374 NEXT;
7375 if (!strict) NEXT;
7376 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007377 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007378 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007379 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007380 SKIP_BLANKS;
7381 }
7382}
7383
7384/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007385 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007386 * @ctxt: the XPath Parser context
7387 *
7388 * [23] EqualityExpr ::= RelationalExpr
7389 * | EqualityExpr '=' RelationalExpr
7390 * | EqualityExpr '!=' RelationalExpr
7391 *
7392 * A != B != C is allowed ? Answer from James, yes with
7393 * (RelationalExpr = RelationalExpr) = RelationalExpr
7394 * (RelationalExpr != RelationalExpr) != RelationalExpr
7395 * which is basically what got implemented.
7396 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007397 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007398 *
7399 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007400static void
7401xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7402 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007403 CHECK_ERROR;
7404 SKIP_BLANKS;
7405 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007406 int eq;
7407 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007408
7409 if (CUR == '=') eq = 1;
7410 else eq = 0;
7411 NEXT;
7412 if (!eq) NEXT;
7413 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007414 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007415 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007416 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007417 SKIP_BLANKS;
7418 }
7419}
7420
7421/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007422 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007423 * @ctxt: the XPath Parser context
7424 *
7425 * [22] AndExpr ::= EqualityExpr
7426 * | AndExpr 'and' EqualityExpr
7427 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007428 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007429 *
7430 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007431static void
7432xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7433 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007434 CHECK_ERROR;
7435 SKIP_BLANKS;
7436 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007437 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007438 SKIP(3);
7439 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007440 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007441 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007442 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007443 SKIP_BLANKS;
7444 }
7445}
7446
7447/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007448 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007449 * @ctxt: the XPath Parser context
7450 *
7451 * [14] Expr ::= OrExpr
7452 * [21] OrExpr ::= AndExpr
7453 * | OrExpr 'or' AndExpr
7454 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007455 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007456 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007457static void
7458xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7459 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007460 CHECK_ERROR;
7461 SKIP_BLANKS;
7462 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007463 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007464 SKIP(2);
7465 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007466 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007467 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007468 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7469 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007470 SKIP_BLANKS;
7471 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007472 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7473 /* more ops could be optimized too */
7474 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7475 }
Owen Taylor3473f882001-02-23 17:55:21 +00007476}
7477
7478/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007479 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007480 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007481 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007482 *
7483 * [8] Predicate ::= '[' PredicateExpr ']'
7484 * [9] PredicateExpr ::= Expr
7485 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007486 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007487 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007488static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007489xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007490 int op1 = ctxt->comp->last;
7491
7492 SKIP_BLANKS;
7493 if (CUR != '[') {
7494 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7495 }
7496 NEXT;
7497 SKIP_BLANKS;
7498
7499 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007500 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007501 CHECK_ERROR;
7502
7503 if (CUR != ']') {
7504 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7505 }
7506
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007507 if (filter)
7508 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7509 else
7510 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007511
7512 NEXT;
7513 SKIP_BLANKS;
7514}
7515
7516/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007517 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007518 * @ctxt: the XPath Parser context
7519 * @test: pointer to a xmlXPathTestVal
7520 * @type: pointer to a xmlXPathTypeVal
7521 * @prefix: placeholder for a possible name prefix
7522 *
7523 * [7] NodeTest ::= NameTest
7524 * | NodeType '(' ')'
7525 * | 'processing-instruction' '(' Literal ')'
7526 *
7527 * [37] NameTest ::= '*'
7528 * | NCName ':' '*'
7529 * | QName
7530 * [38] NodeType ::= 'comment'
7531 * | 'text'
7532 * | 'processing-instruction'
7533 * | 'node'
7534 *
7535 * Returns the name found and update @test, @type and @prefix appropriately
7536 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007537static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007538xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7539 xmlXPathTypeVal *type, const xmlChar **prefix,
7540 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007541 int blanks;
7542
7543 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7544 STRANGE;
7545 return(NULL);
7546 }
7547 *type = 0;
7548 *test = 0;
7549 *prefix = NULL;
7550 SKIP_BLANKS;
7551
7552 if ((name == NULL) && (CUR == '*')) {
7553 /*
7554 * All elements
7555 */
7556 NEXT;
7557 *test = NODE_TEST_ALL;
7558 return(NULL);
7559 }
7560
7561 if (name == NULL)
7562 name = xmlXPathParseNCName(ctxt);
7563 if (name == NULL) {
7564 XP_ERROR0(XPATH_EXPR_ERROR);
7565 }
7566
7567 blanks = IS_BLANK(CUR);
7568 SKIP_BLANKS;
7569 if (CUR == '(') {
7570 NEXT;
7571 /*
7572 * NodeType or PI search
7573 */
7574 if (xmlStrEqual(name, BAD_CAST "comment"))
7575 *type = NODE_TYPE_COMMENT;
7576 else if (xmlStrEqual(name, BAD_CAST "node"))
7577 *type = NODE_TYPE_NODE;
7578 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7579 *type = NODE_TYPE_PI;
7580 else if (xmlStrEqual(name, BAD_CAST "text"))
7581 *type = NODE_TYPE_TEXT;
7582 else {
7583 if (name != NULL)
7584 xmlFree(name);
7585 XP_ERROR0(XPATH_EXPR_ERROR);
7586 }
7587
7588 *test = NODE_TEST_TYPE;
7589
7590 SKIP_BLANKS;
7591 if (*type == NODE_TYPE_PI) {
7592 /*
7593 * Specific case: search a PI by name.
7594 */
Owen Taylor3473f882001-02-23 17:55:21 +00007595 if (name != NULL)
7596 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007597 name = NULL;
7598 if (CUR != ')') {
7599 name = xmlXPathParseLiteral(ctxt);
7600 CHECK_ERROR 0;
7601 SKIP_BLANKS;
7602 }
Owen Taylor3473f882001-02-23 17:55:21 +00007603 }
7604 if (CUR != ')') {
7605 if (name != NULL)
7606 xmlFree(name);
7607 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7608 }
7609 NEXT;
7610 return(name);
7611 }
7612 *test = NODE_TEST_NAME;
7613 if ((!blanks) && (CUR == ':')) {
7614 NEXT;
7615
7616 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007617 * Since currently the parser context don't have a
7618 * namespace list associated:
7619 * The namespace name for this prefix can be computed
7620 * only at evaluation time. The compilation is done
7621 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007622 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007623#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007624 *prefix = xmlXPathNsLookup(ctxt->context, name);
7625 if (name != NULL)
7626 xmlFree(name);
7627 if (*prefix == NULL) {
7628 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7629 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007630#else
7631 *prefix = name;
7632#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007633
7634 if (CUR == '*') {
7635 /*
7636 * All elements
7637 */
7638 NEXT;
7639 *test = NODE_TEST_ALL;
7640 return(NULL);
7641 }
7642
7643 name = xmlXPathParseNCName(ctxt);
7644 if (name == NULL) {
7645 XP_ERROR0(XPATH_EXPR_ERROR);
7646 }
7647 }
7648 return(name);
7649}
7650
7651/**
7652 * xmlXPathIsAxisName:
7653 * @name: a preparsed name token
7654 *
7655 * [6] AxisName ::= 'ancestor'
7656 * | 'ancestor-or-self'
7657 * | 'attribute'
7658 * | 'child'
7659 * | 'descendant'
7660 * | 'descendant-or-self'
7661 * | 'following'
7662 * | 'following-sibling'
7663 * | 'namespace'
7664 * | 'parent'
7665 * | 'preceding'
7666 * | 'preceding-sibling'
7667 * | 'self'
7668 *
7669 * Returns the axis or 0
7670 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007671static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007672xmlXPathIsAxisName(const xmlChar *name) {
7673 xmlXPathAxisVal ret = 0;
7674 switch (name[0]) {
7675 case 'a':
7676 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7677 ret = AXIS_ANCESTOR;
7678 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7679 ret = AXIS_ANCESTOR_OR_SELF;
7680 if (xmlStrEqual(name, BAD_CAST "attribute"))
7681 ret = AXIS_ATTRIBUTE;
7682 break;
7683 case 'c':
7684 if (xmlStrEqual(name, BAD_CAST "child"))
7685 ret = AXIS_CHILD;
7686 break;
7687 case 'd':
7688 if (xmlStrEqual(name, BAD_CAST "descendant"))
7689 ret = AXIS_DESCENDANT;
7690 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7691 ret = AXIS_DESCENDANT_OR_SELF;
7692 break;
7693 case 'f':
7694 if (xmlStrEqual(name, BAD_CAST "following"))
7695 ret = AXIS_FOLLOWING;
7696 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7697 ret = AXIS_FOLLOWING_SIBLING;
7698 break;
7699 case 'n':
7700 if (xmlStrEqual(name, BAD_CAST "namespace"))
7701 ret = AXIS_NAMESPACE;
7702 break;
7703 case 'p':
7704 if (xmlStrEqual(name, BAD_CAST "parent"))
7705 ret = AXIS_PARENT;
7706 if (xmlStrEqual(name, BAD_CAST "preceding"))
7707 ret = AXIS_PRECEDING;
7708 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7709 ret = AXIS_PRECEDING_SIBLING;
7710 break;
7711 case 's':
7712 if (xmlStrEqual(name, BAD_CAST "self"))
7713 ret = AXIS_SELF;
7714 break;
7715 }
7716 return(ret);
7717}
7718
7719/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007720 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007721 * @ctxt: the XPath Parser context
7722 *
7723 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7724 * | AbbreviatedStep
7725 *
7726 * [12] AbbreviatedStep ::= '.' | '..'
7727 *
7728 * [5] AxisSpecifier ::= AxisName '::'
7729 * | AbbreviatedAxisSpecifier
7730 *
7731 * [13] AbbreviatedAxisSpecifier ::= '@'?
7732 *
7733 * Modified for XPtr range support as:
7734 *
7735 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7736 * | AbbreviatedStep
7737 * | 'range-to' '(' Expr ')' Predicate*
7738 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007739 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007740 * A location step of . is short for self::node(). This is
7741 * particularly useful in conjunction with //. For example, the
7742 * location path .//para is short for
7743 * self::node()/descendant-or-self::node()/child::para
7744 * and so will select all para descendant elements of the context
7745 * node.
7746 * Similarly, a location step of .. is short for parent::node().
7747 * For example, ../title is short for parent::node()/child::title
7748 * and so will select the title children of the parent of the context
7749 * node.
7750 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007751static void
7752xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007753#ifdef LIBXML_XPTR_ENABLED
7754 int rangeto = 0;
7755 int op2 = -1;
7756#endif
7757
Owen Taylor3473f882001-02-23 17:55:21 +00007758 SKIP_BLANKS;
7759 if ((CUR == '.') && (NXT(1) == '.')) {
7760 SKIP(2);
7761 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007762 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7763 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007764 } else if (CUR == '.') {
7765 NEXT;
7766 SKIP_BLANKS;
7767 } else {
7768 xmlChar *name = NULL;
7769 const xmlChar *prefix = NULL;
7770 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007771 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007772 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007773 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007774
7775 /*
7776 * The modification needed for XPointer change to the production
7777 */
7778#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007779 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007780 name = xmlXPathParseNCName(ctxt);
7781 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007782 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007783 xmlFree(name);
7784 SKIP_BLANKS;
7785 if (CUR != '(') {
7786 XP_ERROR(XPATH_EXPR_ERROR);
7787 }
7788 NEXT;
7789 SKIP_BLANKS;
7790
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007791 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007792 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007793 CHECK_ERROR;
7794
7795 SKIP_BLANKS;
7796 if (CUR != ')') {
7797 XP_ERROR(XPATH_EXPR_ERROR);
7798 }
7799 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007800 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007801 goto eval_predicates;
7802 }
7803 }
7804#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007805 if (CUR == '*') {
7806 axis = AXIS_CHILD;
7807 } else {
7808 if (name == NULL)
7809 name = xmlXPathParseNCName(ctxt);
7810 if (name != NULL) {
7811 axis = xmlXPathIsAxisName(name);
7812 if (axis != 0) {
7813 SKIP_BLANKS;
7814 if ((CUR == ':') && (NXT(1) == ':')) {
7815 SKIP(2);
7816 xmlFree(name);
7817 name = NULL;
7818 } else {
7819 /* an element name can conflict with an axis one :-\ */
7820 axis = AXIS_CHILD;
7821 }
Owen Taylor3473f882001-02-23 17:55:21 +00007822 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007823 axis = AXIS_CHILD;
7824 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007825 } else if (CUR == '@') {
7826 NEXT;
7827 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007828 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007829 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007830 }
Owen Taylor3473f882001-02-23 17:55:21 +00007831 }
7832
7833 CHECK_ERROR;
7834
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007835 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007836 if (test == 0)
7837 return;
7838
7839#ifdef DEBUG_STEP
7840 xmlGenericError(xmlGenericErrorContext,
7841 "Basis : computing new set\n");
7842#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007843
Owen Taylor3473f882001-02-23 17:55:21 +00007844#ifdef DEBUG_STEP
7845 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007846 if (ctxt->value == NULL)
7847 xmlGenericError(xmlGenericErrorContext, "no value\n");
7848 else if (ctxt->value->nodesetval == NULL)
7849 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7850 else
7851 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007852#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007853
7854eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007855 op1 = ctxt->comp->last;
7856 ctxt->comp->last = -1;
7857
Owen Taylor3473f882001-02-23 17:55:21 +00007858 SKIP_BLANKS;
7859 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007860 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007861 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007862
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007863#ifdef LIBXML_XPTR_ENABLED
7864 if (rangeto) {
7865 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7866 } else
7867#endif
7868 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7869 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007870
Owen Taylor3473f882001-02-23 17:55:21 +00007871 }
7872#ifdef DEBUG_STEP
7873 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007874 if (ctxt->value == NULL)
7875 xmlGenericError(xmlGenericErrorContext, "no value\n");
7876 else if (ctxt->value->nodesetval == NULL)
7877 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7878 else
7879 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7880 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007881#endif
7882}
7883
7884/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007885 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007886 * @ctxt: the XPath Parser context
7887 *
7888 * [3] RelativeLocationPath ::= Step
7889 * | RelativeLocationPath '/' Step
7890 * | AbbreviatedRelativeLocationPath
7891 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7892 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007893 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007894 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007895static void
Owen Taylor3473f882001-02-23 17:55:21 +00007896#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007897xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007898#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007899xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007900#endif
7901(xmlXPathParserContextPtr ctxt) {
7902 SKIP_BLANKS;
7903 if ((CUR == '/') && (NXT(1) == '/')) {
7904 SKIP(2);
7905 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007906 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7907 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007908 } else if (CUR == '/') {
7909 NEXT;
7910 SKIP_BLANKS;
7911 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007912 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007913 SKIP_BLANKS;
7914 while (CUR == '/') {
7915 if ((CUR == '/') && (NXT(1) == '/')) {
7916 SKIP(2);
7917 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007918 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007919 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007920 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007921 } else if (CUR == '/') {
7922 NEXT;
7923 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007924 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007925 }
7926 SKIP_BLANKS;
7927 }
7928}
7929
7930/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007931 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007932 * @ctxt: the XPath Parser context
7933 *
7934 * [1] LocationPath ::= RelativeLocationPath
7935 * | AbsoluteLocationPath
7936 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7937 * | AbbreviatedAbsoluteLocationPath
7938 * [10] AbbreviatedAbsoluteLocationPath ::=
7939 * '//' RelativeLocationPath
7940 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007941 * Compile a location path
7942 *
Owen Taylor3473f882001-02-23 17:55:21 +00007943 * // is short for /descendant-or-self::node()/. For example,
7944 * //para is short for /descendant-or-self::node()/child::para and
7945 * so will select any para element in the document (even a para element
7946 * that is a document element will be selected by //para since the
7947 * document element node is a child of the root node); div//para is
7948 * short for div/descendant-or-self::node()/child::para and so will
7949 * select all para descendants of div children.
7950 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007951static void
7952xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007953 SKIP_BLANKS;
7954 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007955 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007956 } else {
7957 while (CUR == '/') {
7958 if ((CUR == '/') && (NXT(1) == '/')) {
7959 SKIP(2);
7960 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007961 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7962 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007963 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007964 } else if (CUR == '/') {
7965 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007966 SKIP_BLANKS;
7967 if ((CUR != 0 ) &&
7968 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7969 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007970 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007971 }
7972 }
7973 }
7974}
7975
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007976/************************************************************************
7977 * *
7978 * XPath precompiled expression evaluation *
7979 * *
7980 ************************************************************************/
7981
Daniel Veillardf06307e2001-07-03 10:35:50 +00007982static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007983xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7984
7985/**
7986 * xmlXPathNodeCollectAndTest:
7987 * @ctxt: the XPath Parser context
7988 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007989 * @first: pointer to the first element in document order
7990 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007991 *
7992 * This is the function implementing a step: based on the current list
7993 * of nodes, it builds up a new list, looking at all nodes under that
7994 * axis and selecting them it also do the predicate filtering
7995 *
7996 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007997 *
7998 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007999 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008000static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008001xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008002 xmlXPathStepOpPtr op,
8003 xmlNodePtr * first, xmlNodePtr * last)
8004{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008005 xmlXPathAxisVal axis = op->value;
8006 xmlXPathTestVal test = op->value2;
8007 xmlXPathTypeVal type = op->value3;
8008 const xmlChar *prefix = op->value4;
8009 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008010 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008011
8012#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008013 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008014#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008015 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008016 xmlNodeSetPtr ret, list;
8017 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008018 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008019 xmlNodePtr cur = NULL;
8020 xmlXPathObjectPtr obj;
8021 xmlNodeSetPtr nodelist;
8022 xmlNodePtr tmp;
8023
Daniel Veillardf06307e2001-07-03 10:35:50 +00008024 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008025 obj = valuePop(ctxt);
8026 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008027 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008028 URI = xmlXPathNsLookup(ctxt->context, prefix);
8029 if (URI == NULL)
8030 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008031 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008032#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008033 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008034#endif
8035 switch (axis) {
8036 case AXIS_ANCESTOR:
8037#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008038 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008039#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008040 first = NULL;
8041 next = xmlXPathNextAncestor;
8042 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008043 case AXIS_ANCESTOR_OR_SELF:
8044#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008045 xmlGenericError(xmlGenericErrorContext,
8046 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008047#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008048 first = NULL;
8049 next = xmlXPathNextAncestorOrSelf;
8050 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008051 case AXIS_ATTRIBUTE:
8052#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008053 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008054#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008055 first = NULL;
8056 last = NULL;
8057 next = xmlXPathNextAttribute;
8058 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008059 case AXIS_CHILD:
8060#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008061 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008062#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008063 last = NULL;
8064 next = xmlXPathNextChild;
8065 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008066 case AXIS_DESCENDANT:
8067#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008068 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008069#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008070 last = NULL;
8071 next = xmlXPathNextDescendant;
8072 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008073 case AXIS_DESCENDANT_OR_SELF:
8074#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008075 xmlGenericError(xmlGenericErrorContext,
8076 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008077#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008078 last = NULL;
8079 next = xmlXPathNextDescendantOrSelf;
8080 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008081 case AXIS_FOLLOWING:
8082#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008083 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008084#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008085 last = NULL;
8086 next = xmlXPathNextFollowing;
8087 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008088 case AXIS_FOLLOWING_SIBLING:
8089#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008090 xmlGenericError(xmlGenericErrorContext,
8091 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008092#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008093 last = NULL;
8094 next = xmlXPathNextFollowingSibling;
8095 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008096 case AXIS_NAMESPACE:
8097#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008098 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008099#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008100 first = NULL;
8101 last = NULL;
8102 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8103 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008104 case AXIS_PARENT:
8105#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008106 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008107#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008108 first = NULL;
8109 next = xmlXPathNextParent;
8110 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008111 case AXIS_PRECEDING:
8112#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008113 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008114#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008115 first = NULL;
8116 next = xmlXPathNextPrecedingInternal;
8117 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008118 case AXIS_PRECEDING_SIBLING:
8119#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008120 xmlGenericError(xmlGenericErrorContext,
8121 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008122#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008123 first = NULL;
8124 next = xmlXPathNextPrecedingSibling;
8125 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008126 case AXIS_SELF:
8127#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008128 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008129#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008130 first = NULL;
8131 last = NULL;
8132 next = xmlXPathNextSelf;
8133 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008134 }
8135 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008136 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008137
8138 nodelist = obj->nodesetval;
8139 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008140 xmlXPathFreeObject(obj);
8141 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8142 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008143 }
8144 addNode = xmlXPathNodeSetAddUnique;
8145 ret = NULL;
8146#ifdef DEBUG_STEP
8147 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008148 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008149 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008150 case NODE_TEST_NONE:
8151 xmlGenericError(xmlGenericErrorContext,
8152 " searching for none !!!\n");
8153 break;
8154 case NODE_TEST_TYPE:
8155 xmlGenericError(xmlGenericErrorContext,
8156 " searching for type %d\n", type);
8157 break;
8158 case NODE_TEST_PI:
8159 xmlGenericError(xmlGenericErrorContext,
8160 " searching for PI !!!\n");
8161 break;
8162 case NODE_TEST_ALL:
8163 xmlGenericError(xmlGenericErrorContext,
8164 " searching for *\n");
8165 break;
8166 case NODE_TEST_NS:
8167 xmlGenericError(xmlGenericErrorContext,
8168 " searching for namespace %s\n",
8169 prefix);
8170 break;
8171 case NODE_TEST_NAME:
8172 xmlGenericError(xmlGenericErrorContext,
8173 " searching for name %s\n", name);
8174 if (prefix != NULL)
8175 xmlGenericError(xmlGenericErrorContext,
8176 " with namespace %s\n", prefix);
8177 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008178 }
8179 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8180#endif
8181 /*
8182 * 2.3 Node Tests
8183 * - For the attribute axis, the principal node type is attribute.
8184 * - For the namespace axis, the principal node type is namespace.
8185 * - For other axes, the principal node type is element.
8186 *
8187 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008188 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008189 * select all element children of the context node
8190 */
8191 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008192 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008193 ctxt->context->node = nodelist->nodeTab[i];
8194
Daniel Veillardf06307e2001-07-03 10:35:50 +00008195 cur = NULL;
8196 list = xmlXPathNodeSetCreate(NULL);
8197 do {
8198 cur = next(ctxt, cur);
8199 if (cur == NULL)
8200 break;
8201 if ((first != NULL) && (*first == cur))
8202 break;
8203 if (((t % 256) == 0) &&
8204 (first != NULL) && (*first != NULL) &&
8205 (xmlXPathCmpNodes(*first, cur) >= 0))
8206 break;
8207 if ((last != NULL) && (*last == cur))
8208 break;
8209 if (((t % 256) == 0) &&
8210 (last != NULL) && (*last != NULL) &&
8211 (xmlXPathCmpNodes(cur, *last) >= 0))
8212 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008213 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008214#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008215 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8216#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008217 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008218 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008219 ctxt->context->node = tmp;
8220 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008221 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008222 if ((cur->type == type) ||
8223 ((type == NODE_TYPE_NODE) &&
8224 ((cur->type == XML_DOCUMENT_NODE) ||
8225 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8226 (cur->type == XML_ELEMENT_NODE) ||
8227 (cur->type == XML_PI_NODE) ||
8228 (cur->type == XML_COMMENT_NODE) ||
8229 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008230 (cur->type == XML_TEXT_NODE))) ||
8231 ((type == NODE_TYPE_TEXT) &&
8232 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008233#ifdef DEBUG_STEP
8234 n++;
8235#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008236 addNode(list, cur);
8237 }
8238 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008239 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008240 if (cur->type == XML_PI_NODE) {
8241 if ((name != NULL) &&
8242 (!xmlStrEqual(name, cur->name)))
8243 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008244#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008245 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008246#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008247 addNode(list, cur);
8248 }
8249 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008250 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008251 if (axis == AXIS_ATTRIBUTE) {
8252 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008253#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008254 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008255#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008256 addNode(list, cur);
8257 }
8258 } else if (axis == AXIS_NAMESPACE) {
8259 if (cur->type == XML_NAMESPACE_DECL) {
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 }
8265 } else {
8266 if (cur->type == XML_ELEMENT_NODE) {
8267 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008268#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008269 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008270#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008271 addNode(list, cur);
8272 } else if ((cur->ns != NULL) &&
8273 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008274#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008275 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008276#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008277 addNode(list, cur);
8278 }
8279 }
8280 }
8281 break;
8282 case NODE_TEST_NS:{
8283 TODO;
8284 break;
8285 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008286 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008287 switch (cur->type) {
8288 case XML_ELEMENT_NODE:
8289 if (xmlStrEqual(name, cur->name)) {
8290 if (prefix == NULL) {
8291 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008292#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008293 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008294#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008295 addNode(list, cur);
8296 }
8297 } else {
8298 if ((cur->ns != NULL) &&
8299 (xmlStrEqual(URI,
8300 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008301#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008302 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008303#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008304 addNode(list, cur);
8305 }
8306 }
8307 }
8308 break;
8309 case XML_ATTRIBUTE_NODE:{
8310 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008311
Daniel Veillardf06307e2001-07-03 10:35:50 +00008312 if (xmlStrEqual(name, attr->name)) {
8313 if (prefix == NULL) {
8314 if ((attr->ns == NULL) ||
8315 (attr->ns->prefix == NULL)) {
8316#ifdef DEBUG_STEP
8317 n++;
8318#endif
8319 addNode(list,
8320 (xmlNodePtr) attr);
8321 }
8322 } else {
8323 if ((attr->ns != NULL) &&
8324 (xmlStrEqual(URI,
8325 attr->ns->
8326 href))) {
8327#ifdef DEBUG_STEP
8328 n++;
8329#endif
8330 addNode(list,
8331 (xmlNodePtr) attr);
8332 }
8333 }
8334 }
8335 break;
8336 }
8337 case XML_NAMESPACE_DECL:
8338 if (cur->type == XML_NAMESPACE_DECL) {
8339 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008340
Daniel Veillardf06307e2001-07-03 10:35:50 +00008341 if ((ns->prefix != NULL) && (name != NULL)
8342 && (xmlStrEqual(ns->prefix, name))) {
8343#ifdef DEBUG_STEP
8344 n++;
8345#endif
8346 addNode(list, cur);
8347 }
8348 }
8349 break;
8350 default:
8351 break;
8352 }
8353 break;
8354 break;
8355 }
8356 } while (cur != NULL);
8357
8358 /*
8359 * If there is some predicate filtering do it now
8360 */
8361 if (op->ch2 != -1) {
8362 xmlXPathObjectPtr obj2;
8363
8364 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8365 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8366 CHECK_TYPE0(XPATH_NODESET);
8367 obj2 = valuePop(ctxt);
8368 list = obj2->nodesetval;
8369 obj2->nodesetval = NULL;
8370 xmlXPathFreeObject(obj2);
8371 }
8372 if (ret == NULL) {
8373 ret = list;
8374 } else {
8375 ret = xmlXPathNodeSetMerge(ret, list);
8376 xmlXPathFreeNodeSet(list);
8377 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008378 }
8379 ctxt->context->node = tmp;
8380#ifdef DEBUG_STEP
8381 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008382 "\nExamined %d nodes, found %d nodes at that step\n",
8383 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008384#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008385 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008386 if ((obj->boolval) && (obj->user != NULL)) {
8387 ctxt->value->boolval = 1;
8388 ctxt->value->user = obj->user;
8389 obj->user = NULL;
8390 obj->boolval = 0;
8391 }
8392 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008393 return(t);
8394}
8395
8396/**
8397 * xmlXPathNodeCollectAndTestNth:
8398 * @ctxt: the XPath Parser context
8399 * @op: the XPath precompiled step operation
8400 * @indx: the index to collect
8401 * @first: pointer to the first element in document order
8402 * @last: pointer to the last element in document order
8403 *
8404 * This is the function implementing a step: based on the current list
8405 * of nodes, it builds up a new list, looking at all nodes under that
8406 * axis and selecting them it also do the predicate filtering
8407 *
8408 * Pushes the new NodeSet resulting from the search.
8409 * Returns the number of node traversed
8410 */
8411static int
8412xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8413 xmlXPathStepOpPtr op, int indx,
8414 xmlNodePtr * first, xmlNodePtr * last)
8415{
8416 xmlXPathAxisVal axis = op->value;
8417 xmlXPathTestVal test = op->value2;
8418 xmlXPathTypeVal type = op->value3;
8419 const xmlChar *prefix = op->value4;
8420 const xmlChar *name = op->value5;
8421 const xmlChar *URI = NULL;
8422 int n = 0, t = 0;
8423
8424 int i;
8425 xmlNodeSetPtr list;
8426 xmlXPathTraversalFunction next = NULL;
8427 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8428 xmlNodePtr cur = NULL;
8429 xmlXPathObjectPtr obj;
8430 xmlNodeSetPtr nodelist;
8431 xmlNodePtr tmp;
8432
8433 CHECK_TYPE0(XPATH_NODESET);
8434 obj = valuePop(ctxt);
8435 addNode = xmlXPathNodeSetAdd;
8436 if (prefix != NULL) {
8437 URI = xmlXPathNsLookup(ctxt->context, prefix);
8438 if (URI == NULL)
8439 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8440 }
8441#ifdef DEBUG_STEP_NTH
8442 xmlGenericError(xmlGenericErrorContext, "new step : ");
8443 if (first != NULL) {
8444 if (*first != NULL)
8445 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8446 (*first)->name);
8447 else
8448 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8449 }
8450 if (last != NULL) {
8451 if (*last != NULL)
8452 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8453 (*last)->name);
8454 else
8455 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8456 }
8457#endif
8458 switch (axis) {
8459 case AXIS_ANCESTOR:
8460#ifdef DEBUG_STEP_NTH
8461 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8462#endif
8463 first = NULL;
8464 next = xmlXPathNextAncestor;
8465 break;
8466 case AXIS_ANCESTOR_OR_SELF:
8467#ifdef DEBUG_STEP_NTH
8468 xmlGenericError(xmlGenericErrorContext,
8469 "axis 'ancestors-or-self' ");
8470#endif
8471 first = NULL;
8472 next = xmlXPathNextAncestorOrSelf;
8473 break;
8474 case AXIS_ATTRIBUTE:
8475#ifdef DEBUG_STEP_NTH
8476 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8477#endif
8478 first = NULL;
8479 last = NULL;
8480 next = xmlXPathNextAttribute;
8481 break;
8482 case AXIS_CHILD:
8483#ifdef DEBUG_STEP_NTH
8484 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8485#endif
8486 last = NULL;
8487 next = xmlXPathNextChild;
8488 break;
8489 case AXIS_DESCENDANT:
8490#ifdef DEBUG_STEP_NTH
8491 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8492#endif
8493 last = NULL;
8494 next = xmlXPathNextDescendant;
8495 break;
8496 case AXIS_DESCENDANT_OR_SELF:
8497#ifdef DEBUG_STEP_NTH
8498 xmlGenericError(xmlGenericErrorContext,
8499 "axis 'descendant-or-self' ");
8500#endif
8501 last = NULL;
8502 next = xmlXPathNextDescendantOrSelf;
8503 break;
8504 case AXIS_FOLLOWING:
8505#ifdef DEBUG_STEP_NTH
8506 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8507#endif
8508 last = NULL;
8509 next = xmlXPathNextFollowing;
8510 break;
8511 case AXIS_FOLLOWING_SIBLING:
8512#ifdef DEBUG_STEP_NTH
8513 xmlGenericError(xmlGenericErrorContext,
8514 "axis 'following-siblings' ");
8515#endif
8516 last = NULL;
8517 next = xmlXPathNextFollowingSibling;
8518 break;
8519 case AXIS_NAMESPACE:
8520#ifdef DEBUG_STEP_NTH
8521 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8522#endif
8523 last = NULL;
8524 first = NULL;
8525 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8526 break;
8527 case AXIS_PARENT:
8528#ifdef DEBUG_STEP_NTH
8529 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8530#endif
8531 first = NULL;
8532 next = xmlXPathNextParent;
8533 break;
8534 case AXIS_PRECEDING:
8535#ifdef DEBUG_STEP_NTH
8536 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8537#endif
8538 first = NULL;
8539 next = xmlXPathNextPrecedingInternal;
8540 break;
8541 case AXIS_PRECEDING_SIBLING:
8542#ifdef DEBUG_STEP_NTH
8543 xmlGenericError(xmlGenericErrorContext,
8544 "axis 'preceding-sibling' ");
8545#endif
8546 first = NULL;
8547 next = xmlXPathNextPrecedingSibling;
8548 break;
8549 case AXIS_SELF:
8550#ifdef DEBUG_STEP_NTH
8551 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8552#endif
8553 first = NULL;
8554 last = NULL;
8555 next = xmlXPathNextSelf;
8556 break;
8557 }
8558 if (next == NULL)
8559 return(0);
8560
8561 nodelist = obj->nodesetval;
8562 if (nodelist == NULL) {
8563 xmlXPathFreeObject(obj);
8564 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8565 return(0);
8566 }
8567 addNode = xmlXPathNodeSetAddUnique;
8568#ifdef DEBUG_STEP_NTH
8569 xmlGenericError(xmlGenericErrorContext,
8570 " context contains %d nodes\n", nodelist->nodeNr);
8571 switch (test) {
8572 case NODE_TEST_NONE:
8573 xmlGenericError(xmlGenericErrorContext,
8574 " searching for none !!!\n");
8575 break;
8576 case NODE_TEST_TYPE:
8577 xmlGenericError(xmlGenericErrorContext,
8578 " searching for type %d\n", type);
8579 break;
8580 case NODE_TEST_PI:
8581 xmlGenericError(xmlGenericErrorContext,
8582 " searching for PI !!!\n");
8583 break;
8584 case NODE_TEST_ALL:
8585 xmlGenericError(xmlGenericErrorContext,
8586 " searching for *\n");
8587 break;
8588 case NODE_TEST_NS:
8589 xmlGenericError(xmlGenericErrorContext,
8590 " searching for namespace %s\n",
8591 prefix);
8592 break;
8593 case NODE_TEST_NAME:
8594 xmlGenericError(xmlGenericErrorContext,
8595 " searching for name %s\n", name);
8596 if (prefix != NULL)
8597 xmlGenericError(xmlGenericErrorContext,
8598 " with namespace %s\n", prefix);
8599 break;
8600 }
8601 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8602#endif
8603 /*
8604 * 2.3 Node Tests
8605 * - For the attribute axis, the principal node type is attribute.
8606 * - For the namespace axis, the principal node type is namespace.
8607 * - For other axes, the principal node type is element.
8608 *
8609 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008610 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008611 * select all element children of the context node
8612 */
8613 tmp = ctxt->context->node;
8614 list = xmlXPathNodeSetCreate(NULL);
8615 for (i = 0; i < nodelist->nodeNr; i++) {
8616 ctxt->context->node = nodelist->nodeTab[i];
8617
8618 cur = NULL;
8619 n = 0;
8620 do {
8621 cur = next(ctxt, cur);
8622 if (cur == NULL)
8623 break;
8624 if ((first != NULL) && (*first == cur))
8625 break;
8626 if (((t % 256) == 0) &&
8627 (first != NULL) && (*first != NULL) &&
8628 (xmlXPathCmpNodes(*first, cur) >= 0))
8629 break;
8630 if ((last != NULL) && (*last == cur))
8631 break;
8632 if (((t % 256) == 0) &&
8633 (last != NULL) && (*last != NULL) &&
8634 (xmlXPathCmpNodes(cur, *last) >= 0))
8635 break;
8636 t++;
8637 switch (test) {
8638 case NODE_TEST_NONE:
8639 ctxt->context->node = tmp;
8640 STRANGE return(0);
8641 case NODE_TEST_TYPE:
8642 if ((cur->type == type) ||
8643 ((type == NODE_TYPE_NODE) &&
8644 ((cur->type == XML_DOCUMENT_NODE) ||
8645 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8646 (cur->type == XML_ELEMENT_NODE) ||
8647 (cur->type == XML_PI_NODE) ||
8648 (cur->type == XML_COMMENT_NODE) ||
8649 (cur->type == XML_CDATA_SECTION_NODE) ||
8650 (cur->type == XML_TEXT_NODE)))) {
8651 n++;
8652 if (n == indx)
8653 addNode(list, cur);
8654 }
8655 break;
8656 case NODE_TEST_PI:
8657 if (cur->type == XML_PI_NODE) {
8658 if ((name != NULL) &&
8659 (!xmlStrEqual(name, cur->name)))
8660 break;
8661 n++;
8662 if (n == indx)
8663 addNode(list, cur);
8664 }
8665 break;
8666 case NODE_TEST_ALL:
8667 if (axis == AXIS_ATTRIBUTE) {
8668 if (cur->type == XML_ATTRIBUTE_NODE) {
8669 n++;
8670 if (n == indx)
8671 addNode(list, cur);
8672 }
8673 } else if (axis == AXIS_NAMESPACE) {
8674 if (cur->type == XML_NAMESPACE_DECL) {
8675 n++;
8676 if (n == indx)
8677 addNode(list, cur);
8678 }
8679 } else {
8680 if (cur->type == XML_ELEMENT_NODE) {
8681 if (prefix == NULL) {
8682 n++;
8683 if (n == indx)
8684 addNode(list, cur);
8685 } else if ((cur->ns != NULL) &&
8686 (xmlStrEqual(URI, cur->ns->href))) {
8687 n++;
8688 if (n == indx)
8689 addNode(list, cur);
8690 }
8691 }
8692 }
8693 break;
8694 case NODE_TEST_NS:{
8695 TODO;
8696 break;
8697 }
8698 case NODE_TEST_NAME:
8699 switch (cur->type) {
8700 case XML_ELEMENT_NODE:
8701 if (xmlStrEqual(name, cur->name)) {
8702 if (prefix == NULL) {
8703 if (cur->ns == NULL) {
8704 n++;
8705 if (n == indx)
8706 addNode(list, cur);
8707 }
8708 } else {
8709 if ((cur->ns != NULL) &&
8710 (xmlStrEqual(URI,
8711 cur->ns->href))) {
8712 n++;
8713 if (n == indx)
8714 addNode(list, cur);
8715 }
8716 }
8717 }
8718 break;
8719 case XML_ATTRIBUTE_NODE:{
8720 xmlAttrPtr attr = (xmlAttrPtr) cur;
8721
8722 if (xmlStrEqual(name, attr->name)) {
8723 if (prefix == NULL) {
8724 if ((attr->ns == NULL) ||
8725 (attr->ns->prefix == NULL)) {
8726 n++;
8727 if (n == indx)
8728 addNode(list, cur);
8729 }
8730 } else {
8731 if ((attr->ns != NULL) &&
8732 (xmlStrEqual(URI,
8733 attr->ns->
8734 href))) {
8735 n++;
8736 if (n == indx)
8737 addNode(list, cur);
8738 }
8739 }
8740 }
8741 break;
8742 }
8743 case XML_NAMESPACE_DECL:
8744 if (cur->type == XML_NAMESPACE_DECL) {
8745 xmlNsPtr ns = (xmlNsPtr) cur;
8746
8747 if ((ns->prefix != NULL) && (name != NULL)
8748 && (xmlStrEqual(ns->prefix, name))) {
8749 n++;
8750 if (n == indx)
8751 addNode(list, cur);
8752 }
8753 }
8754 break;
8755 default:
8756 break;
8757 }
8758 break;
8759 break;
8760 }
8761 } while (n < indx);
8762 }
8763 ctxt->context->node = tmp;
8764#ifdef DEBUG_STEP_NTH
8765 xmlGenericError(xmlGenericErrorContext,
8766 "\nExamined %d nodes, found %d nodes at that step\n",
8767 t, list->nodeNr);
8768#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008769 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008770 if ((obj->boolval) && (obj->user != NULL)) {
8771 ctxt->value->boolval = 1;
8772 ctxt->value->user = obj->user;
8773 obj->user = NULL;
8774 obj->boolval = 0;
8775 }
8776 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008777 return(t);
8778}
8779
8780/**
8781 * xmlXPathCompOpEvalFirst:
8782 * @ctxt: the XPath parser context with the compiled expression
8783 * @op: an XPath compiled operation
8784 * @first: the first elem found so far
8785 *
8786 * Evaluate the Precompiled XPath operation searching only the first
8787 * element in document order
8788 *
8789 * Returns the number of examined objects.
8790 */
8791static int
8792xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8793 xmlXPathStepOpPtr op, xmlNodePtr * first)
8794{
8795 int total = 0, cur;
8796 xmlXPathCompExprPtr comp;
8797 xmlXPathObjectPtr arg1, arg2;
8798
Daniel Veillard556c6682001-10-06 09:59:51 +00008799 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008800 comp = ctxt->comp;
8801 switch (op->op) {
8802 case XPATH_OP_END:
8803 return (0);
8804 case XPATH_OP_UNION:
8805 total =
8806 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8807 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008808 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008809 if ((ctxt->value != NULL)
8810 && (ctxt->value->type == XPATH_NODESET)
8811 && (ctxt->value->nodesetval != NULL)
8812 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8813 /*
8814 * limit tree traversing to first node in the result
8815 */
8816 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8817 *first = ctxt->value->nodesetval->nodeTab[0];
8818 }
8819 cur =
8820 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8821 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008822 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008823 CHECK_TYPE0(XPATH_NODESET);
8824 arg2 = valuePop(ctxt);
8825
8826 CHECK_TYPE0(XPATH_NODESET);
8827 arg1 = valuePop(ctxt);
8828
8829 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8830 arg2->nodesetval);
8831 valuePush(ctxt, arg1);
8832 xmlXPathFreeObject(arg2);
8833 /* optimizer */
8834 if (total > cur)
8835 xmlXPathCompSwap(op);
8836 return (total + cur);
8837 case XPATH_OP_ROOT:
8838 xmlXPathRoot(ctxt);
8839 return (0);
8840 case XPATH_OP_NODE:
8841 if (op->ch1 != -1)
8842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008844 if (op->ch2 != -1)
8845 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008846 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008847 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8848 return (total);
8849 case XPATH_OP_RESET:
8850 if (op->ch1 != -1)
8851 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008852 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008853 if (op->ch2 != -1)
8854 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008855 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008856 ctxt->context->node = NULL;
8857 return (total);
8858 case XPATH_OP_COLLECT:{
8859 if (op->ch1 == -1)
8860 return (total);
8861
8862 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008863 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008864
8865 /*
8866 * Optimization for [n] selection where n is a number
8867 */
8868 if ((op->ch2 != -1) &&
8869 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8870 (comp->steps[op->ch2].ch1 == -1) &&
8871 (comp->steps[op->ch2].ch2 != -1) &&
8872 (comp->steps[comp->steps[op->ch2].ch2].op ==
8873 XPATH_OP_VALUE)) {
8874 xmlXPathObjectPtr val;
8875
8876 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8877 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8878 int indx = (int) val->floatval;
8879
8880 if (val->floatval == (float) indx) {
8881 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8882 first, NULL);
8883 return (total);
8884 }
8885 }
8886 }
8887 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8888 return (total);
8889 }
8890 case XPATH_OP_VALUE:
8891 valuePush(ctxt,
8892 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8893 return (0);
8894 case XPATH_OP_SORT:
8895 if (op->ch1 != -1)
8896 total +=
8897 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8898 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008899 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008900 if ((ctxt->value != NULL)
8901 && (ctxt->value->type == XPATH_NODESET)
8902 && (ctxt->value->nodesetval != NULL))
8903 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8904 return (total);
8905 default:
8906 return (xmlXPathCompOpEval(ctxt, op));
8907 }
8908}
8909
8910/**
8911 * xmlXPathCompOpEvalLast:
8912 * @ctxt: the XPath parser context with the compiled expression
8913 * @op: an XPath compiled operation
8914 * @last: the last elem found so far
8915 *
8916 * Evaluate the Precompiled XPath operation searching only the last
8917 * element in document order
8918 *
8919 * Returns the number of node traversed
8920 */
8921static int
8922xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8923 xmlNodePtr * last)
8924{
8925 int total = 0, cur;
8926 xmlXPathCompExprPtr comp;
8927 xmlXPathObjectPtr arg1, arg2;
8928
Daniel Veillard556c6682001-10-06 09:59:51 +00008929 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008930 comp = ctxt->comp;
8931 switch (op->op) {
8932 case XPATH_OP_END:
8933 return (0);
8934 case XPATH_OP_UNION:
8935 total =
8936 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008937 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 if ((ctxt->value != NULL)
8939 && (ctxt->value->type == XPATH_NODESET)
8940 && (ctxt->value->nodesetval != NULL)
8941 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8942 /*
8943 * limit tree traversing to first node in the result
8944 */
8945 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8946 *last =
8947 ctxt->value->nodesetval->nodeTab[ctxt->value->
8948 nodesetval->nodeNr -
8949 1];
8950 }
8951 cur =
8952 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008953 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008954 if ((ctxt->value != NULL)
8955 && (ctxt->value->type == XPATH_NODESET)
8956 && (ctxt->value->nodesetval != NULL)
8957 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8958 }
8959 CHECK_TYPE0(XPATH_NODESET);
8960 arg2 = valuePop(ctxt);
8961
8962 CHECK_TYPE0(XPATH_NODESET);
8963 arg1 = valuePop(ctxt);
8964
8965 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8966 arg2->nodesetval);
8967 valuePush(ctxt, arg1);
8968 xmlXPathFreeObject(arg2);
8969 /* optimizer */
8970 if (total > cur)
8971 xmlXPathCompSwap(op);
8972 return (total + cur);
8973 case XPATH_OP_ROOT:
8974 xmlXPathRoot(ctxt);
8975 return (0);
8976 case XPATH_OP_NODE:
8977 if (op->ch1 != -1)
8978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008979 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 if (op->ch2 != -1)
8981 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008982 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008983 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8984 return (total);
8985 case XPATH_OP_RESET:
8986 if (op->ch1 != -1)
8987 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008988 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008989 if (op->ch2 != -1)
8990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008991 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 ctxt->context->node = NULL;
8993 return (total);
8994 case XPATH_OP_COLLECT:{
8995 if (op->ch1 == -1)
8996 return (0);
8997
8998 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008999 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009000
9001 /*
9002 * Optimization for [n] selection where n is a number
9003 */
9004 if ((op->ch2 != -1) &&
9005 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9006 (comp->steps[op->ch2].ch1 == -1) &&
9007 (comp->steps[op->ch2].ch2 != -1) &&
9008 (comp->steps[comp->steps[op->ch2].ch2].op ==
9009 XPATH_OP_VALUE)) {
9010 xmlXPathObjectPtr val;
9011
9012 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9013 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9014 int indx = (int) val->floatval;
9015
9016 if (val->floatval == (float) indx) {
9017 total +=
9018 xmlXPathNodeCollectAndTestNth(ctxt, op,
9019 indx, NULL,
9020 last);
9021 return (total);
9022 }
9023 }
9024 }
9025 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9026 return (total);
9027 }
9028 case XPATH_OP_VALUE:
9029 valuePush(ctxt,
9030 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9031 return (0);
9032 case XPATH_OP_SORT:
9033 if (op->ch1 != -1)
9034 total +=
9035 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9036 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009037 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009038 if ((ctxt->value != NULL)
9039 && (ctxt->value->type == XPATH_NODESET)
9040 && (ctxt->value->nodesetval != NULL))
9041 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9042 return (total);
9043 default:
9044 return (xmlXPathCompOpEval(ctxt, op));
9045 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009046}
9047
Owen Taylor3473f882001-02-23 17:55:21 +00009048/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009049 * xmlXPathCompOpEval:
9050 * @ctxt: the XPath parser context with the compiled expression
9051 * @op: an XPath compiled operation
9052 *
9053 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009054 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009055 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056static int
9057xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9058{
9059 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009060 int equal, ret;
9061 xmlXPathCompExprPtr comp;
9062 xmlXPathObjectPtr arg1, arg2;
9063
Daniel Veillard556c6682001-10-06 09:59:51 +00009064 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009065 comp = ctxt->comp;
9066 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067 case XPATH_OP_END:
9068 return (0);
9069 case XPATH_OP_AND:
9070 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009071 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009072 xmlXPathBooleanFunction(ctxt, 1);
9073 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9074 return (total);
9075 arg2 = valuePop(ctxt);
9076 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009077 if (ctxt->error) {
9078 xmlXPathFreeObject(arg2);
9079 return(0);
9080 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081 xmlXPathBooleanFunction(ctxt, 1);
9082 arg1 = valuePop(ctxt);
9083 arg1->boolval &= arg2->boolval;
9084 valuePush(ctxt, arg1);
9085 xmlXPathFreeObject(arg2);
9086 return (total);
9087 case XPATH_OP_OR:
9088 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009089 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009090 xmlXPathBooleanFunction(ctxt, 1);
9091 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9092 return (total);
9093 arg2 = valuePop(ctxt);
9094 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009095 if (ctxt->error) {
9096 xmlXPathFreeObject(arg2);
9097 return(0);
9098 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 xmlXPathBooleanFunction(ctxt, 1);
9100 arg1 = valuePop(ctxt);
9101 arg1->boolval |= arg2->boolval;
9102 valuePush(ctxt, arg1);
9103 xmlXPathFreeObject(arg2);
9104 return (total);
9105 case XPATH_OP_EQUAL:
9106 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009107 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009109 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 equal = xmlXPathEqualValues(ctxt);
9111 if (op->value)
9112 valuePush(ctxt, xmlXPathNewBoolean(equal));
9113 else
9114 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9115 return (total);
9116 case XPATH_OP_CMP:
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 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009120 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9122 valuePush(ctxt, xmlXPathNewBoolean(ret));
9123 return (total);
9124 case XPATH_OP_PLUS:
9125 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009126 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127 if (op->ch2 != -1)
9128 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009129 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130 if (op->value == 0)
9131 xmlXPathSubValues(ctxt);
9132 else if (op->value == 1)
9133 xmlXPathAddValues(ctxt);
9134 else if (op->value == 2)
9135 xmlXPathValueFlipSign(ctxt);
9136 else if (op->value == 3) {
9137 CAST_TO_NUMBER;
9138 CHECK_TYPE0(XPATH_NUMBER);
9139 }
9140 return (total);
9141 case XPATH_OP_MULT:
9142 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009143 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009144 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009145 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 if (op->value == 0)
9147 xmlXPathMultValues(ctxt);
9148 else if (op->value == 1)
9149 xmlXPathDivValues(ctxt);
9150 else if (op->value == 2)
9151 xmlXPathModValues(ctxt);
9152 return (total);
9153 case XPATH_OP_UNION:
9154 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009155 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009157 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009158 CHECK_TYPE0(XPATH_NODESET);
9159 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009160
Daniel Veillardf06307e2001-07-03 10:35:50 +00009161 CHECK_TYPE0(XPATH_NODESET);
9162 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009163
Daniel Veillardf06307e2001-07-03 10:35:50 +00009164 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9165 arg2->nodesetval);
9166 valuePush(ctxt, arg1);
9167 xmlXPathFreeObject(arg2);
9168 return (total);
9169 case XPATH_OP_ROOT:
9170 xmlXPathRoot(ctxt);
9171 return (total);
9172 case XPATH_OP_NODE:
9173 if (op->ch1 != -1)
9174 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009175 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 if (op->ch2 != -1)
9177 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009178 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009179 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9180 return (total);
9181 case XPATH_OP_RESET:
9182 if (op->ch1 != -1)
9183 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009184 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 if (op->ch2 != -1)
9186 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009187 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009188 ctxt->context->node = NULL;
9189 return (total);
9190 case XPATH_OP_COLLECT:{
9191 if (op->ch1 == -1)
9192 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009193
Daniel Veillardf06307e2001-07-03 10:35:50 +00009194 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009195 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009196
Daniel Veillardf06307e2001-07-03 10:35:50 +00009197 /*
9198 * Optimization for [n] selection where n is a number
9199 */
9200 if ((op->ch2 != -1) &&
9201 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9202 (comp->steps[op->ch2].ch1 == -1) &&
9203 (comp->steps[op->ch2].ch2 != -1) &&
9204 (comp->steps[comp->steps[op->ch2].ch2].op ==
9205 XPATH_OP_VALUE)) {
9206 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009207
Daniel Veillardf06307e2001-07-03 10:35:50 +00009208 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9209 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9210 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009211
Daniel Veillardf06307e2001-07-03 10:35:50 +00009212 if (val->floatval == (float) indx) {
9213 total +=
9214 xmlXPathNodeCollectAndTestNth(ctxt, op,
9215 indx, NULL,
9216 NULL);
9217 return (total);
9218 }
9219 }
9220 }
9221 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9222 return (total);
9223 }
9224 case XPATH_OP_VALUE:
9225 valuePush(ctxt,
9226 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9227 return (total);
9228 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009229 xmlXPathObjectPtr val;
9230
Daniel Veillardf06307e2001-07-03 10:35:50 +00009231 if (op->ch1 != -1)
9232 total +=
9233 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009234 if (op->value5 == NULL) {
9235 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9236 if (val == NULL) {
9237 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9238 return(0);
9239 }
9240 valuePush(ctxt, val);
9241 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009242 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009243
Daniel Veillardf06307e2001-07-03 10:35:50 +00009244 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9245 if (URI == NULL) {
9246 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009247 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009248 op->value4, op->value5);
9249 return (total);
9250 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009251 val = xmlXPathVariableLookupNS(ctxt->context,
9252 op->value4, URI);
9253 if (val == NULL) {
9254 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9255 return(0);
9256 }
9257 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009258 }
9259 return (total);
9260 }
9261 case XPATH_OP_FUNCTION:{
9262 xmlXPathFunction func;
9263 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009264 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009265
9266 if (op->ch1 != -1)
9267 total +=
9268 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009269 if (ctxt->valueNr < op->value) {
9270 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009271 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009272 ctxt->error = XPATH_INVALID_OPERAND;
9273 return (total);
9274 }
9275 for (i = 0; i < op->value; i++)
9276 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9277 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009278 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009279 ctxt->error = XPATH_INVALID_OPERAND;
9280 return (total);
9281 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009282 if (op->cache != NULL)
9283 func = (xmlXPathFunction) op->cache;
9284 else {
9285 const xmlChar *URI = NULL;
9286
9287 if (op->value5 == NULL)
9288 func =
9289 xmlXPathFunctionLookup(ctxt->context,
9290 op->value4);
9291 else {
9292 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9293 if (URI == NULL) {
9294 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009295 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009296 op->value4, op->value5);
9297 return (total);
9298 }
9299 func = xmlXPathFunctionLookupNS(ctxt->context,
9300 op->value4, URI);
9301 }
9302 if (func == NULL) {
9303 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009304 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009305 op->value4);
9306 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009307 }
9308 op->cache = (void *) func;
9309 op->cacheURI = (void *) URI;
9310 }
9311 oldFunc = ctxt->context->function;
9312 oldFuncURI = ctxt->context->functionURI;
9313 ctxt->context->function = op->value4;
9314 ctxt->context->functionURI = op->cacheURI;
9315 func(ctxt, op->value);
9316 ctxt->context->function = oldFunc;
9317 ctxt->context->functionURI = oldFuncURI;
9318 return (total);
9319 }
9320 case XPATH_OP_ARG:
9321 if (op->ch1 != -1)
9322 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009323 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009324 if (op->ch2 != -1)
9325 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009326 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009327 return (total);
9328 case XPATH_OP_PREDICATE:
9329 case XPATH_OP_FILTER:{
9330 xmlXPathObjectPtr res;
9331 xmlXPathObjectPtr obj, tmp;
9332 xmlNodeSetPtr newset = NULL;
9333 xmlNodeSetPtr oldset;
9334 xmlNodePtr oldnode;
9335 int i;
9336
9337 /*
9338 * Optimization for ()[1] selection i.e. the first elem
9339 */
9340 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9341 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9342 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9343 xmlXPathObjectPtr val;
9344
9345 val = comp->steps[op->ch2].value4;
9346 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9347 (val->floatval == 1.0)) {
9348 xmlNodePtr first = NULL;
9349
9350 total +=
9351 xmlXPathCompOpEvalFirst(ctxt,
9352 &comp->steps[op->ch1],
9353 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009354 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009355 /*
9356 * The nodeset should be in document order,
9357 * Keep only the first value
9358 */
9359 if ((ctxt->value != NULL) &&
9360 (ctxt->value->type == XPATH_NODESET) &&
9361 (ctxt->value->nodesetval != NULL) &&
9362 (ctxt->value->nodesetval->nodeNr > 1))
9363 ctxt->value->nodesetval->nodeNr = 1;
9364 return (total);
9365 }
9366 }
9367 /*
9368 * Optimization for ()[last()] selection i.e. the last elem
9369 */
9370 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9371 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9372 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9373 int f = comp->steps[op->ch2].ch1;
9374
9375 if ((f != -1) &&
9376 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9377 (comp->steps[f].value5 == NULL) &&
9378 (comp->steps[f].value == 0) &&
9379 (comp->steps[f].value4 != NULL) &&
9380 (xmlStrEqual
9381 (comp->steps[f].value4, BAD_CAST "last"))) {
9382 xmlNodePtr last = NULL;
9383
9384 total +=
9385 xmlXPathCompOpEvalLast(ctxt,
9386 &comp->steps[op->ch1],
9387 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009388 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009389 /*
9390 * The nodeset should be in document order,
9391 * Keep only the last value
9392 */
9393 if ((ctxt->value != NULL) &&
9394 (ctxt->value->type == XPATH_NODESET) &&
9395 (ctxt->value->nodesetval != NULL) &&
9396 (ctxt->value->nodesetval->nodeTab != NULL) &&
9397 (ctxt->value->nodesetval->nodeNr > 1)) {
9398 ctxt->value->nodesetval->nodeTab[0] =
9399 ctxt->value->nodesetval->nodeTab[ctxt->
9400 value->
9401 nodesetval->
9402 nodeNr -
9403 1];
9404 ctxt->value->nodesetval->nodeNr = 1;
9405 }
9406 return (total);
9407 }
9408 }
9409
9410 if (op->ch1 != -1)
9411 total +=
9412 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009413 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009414 if (op->ch2 == -1)
9415 return (total);
9416 if (ctxt->value == NULL)
9417 return (total);
9418
9419 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009420
9421#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009422 /*
9423 * Hum are we filtering the result of an XPointer expression
9424 */
9425 if (ctxt->value->type == XPATH_LOCATIONSET) {
9426 xmlLocationSetPtr newlocset = NULL;
9427 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009428
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 /*
9430 * Extract the old locset, and then evaluate the result of the
9431 * expression for all the element in the locset. use it to grow
9432 * up a new locset.
9433 */
9434 CHECK_TYPE0(XPATH_LOCATIONSET);
9435 obj = valuePop(ctxt);
9436 oldlocset = obj->user;
9437 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009438
Daniel Veillardf06307e2001-07-03 10:35:50 +00009439 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9440 ctxt->context->contextSize = 0;
9441 ctxt->context->proximityPosition = 0;
9442 if (op->ch2 != -1)
9443 total +=
9444 xmlXPathCompOpEval(ctxt,
9445 &comp->steps[op->ch2]);
9446 res = valuePop(ctxt);
9447 if (res != NULL)
9448 xmlXPathFreeObject(res);
9449 valuePush(ctxt, obj);
9450 CHECK_ERROR0;
9451 return (total);
9452 }
9453 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009454
Daniel Veillardf06307e2001-07-03 10:35:50 +00009455 for (i = 0; i < oldlocset->locNr; i++) {
9456 /*
9457 * Run the evaluation with a node list made of a
9458 * single item in the nodelocset.
9459 */
9460 ctxt->context->node = oldlocset->locTab[i]->user;
9461 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9462 valuePush(ctxt, tmp);
9463 ctxt->context->contextSize = oldlocset->locNr;
9464 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009465
Daniel Veillardf06307e2001-07-03 10:35:50 +00009466 if (op->ch2 != -1)
9467 total +=
9468 xmlXPathCompOpEval(ctxt,
9469 &comp->steps[op->ch2]);
9470 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009471
Daniel Veillardf06307e2001-07-03 10:35:50 +00009472 /*
9473 * The result of the evaluation need to be tested to
9474 * decided whether the filter succeeded or not
9475 */
9476 res = valuePop(ctxt);
9477 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9478 xmlXPtrLocationSetAdd(newlocset,
9479 xmlXPathObjectCopy
9480 (oldlocset->locTab[i]));
9481 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009482
Daniel Veillardf06307e2001-07-03 10:35:50 +00009483 /*
9484 * Cleanup
9485 */
9486 if (res != NULL)
9487 xmlXPathFreeObject(res);
9488 if (ctxt->value == tmp) {
9489 res = valuePop(ctxt);
9490 xmlXPathFreeObject(res);
9491 }
9492
9493 ctxt->context->node = NULL;
9494 }
9495
9496 /*
9497 * The result is used as the new evaluation locset.
9498 */
9499 xmlXPathFreeObject(obj);
9500 ctxt->context->node = NULL;
9501 ctxt->context->contextSize = -1;
9502 ctxt->context->proximityPosition = -1;
9503 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9504 ctxt->context->node = oldnode;
9505 return (total);
9506 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009507#endif /* LIBXML_XPTR_ENABLED */
9508
Daniel Veillardf06307e2001-07-03 10:35:50 +00009509 /*
9510 * Extract the old set, and then evaluate the result of the
9511 * expression for all the element in the set. use it to grow
9512 * up a new set.
9513 */
9514 CHECK_TYPE0(XPATH_NODESET);
9515 obj = valuePop(ctxt);
9516 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009517
Daniel Veillardf06307e2001-07-03 10:35:50 +00009518 oldnode = ctxt->context->node;
9519 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009520
Daniel Veillardf06307e2001-07-03 10:35:50 +00009521 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9522 ctxt->context->contextSize = 0;
9523 ctxt->context->proximityPosition = 0;
9524 if (op->ch2 != -1)
9525 total +=
9526 xmlXPathCompOpEval(ctxt,
9527 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009528 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009529 res = valuePop(ctxt);
9530 if (res != NULL)
9531 xmlXPathFreeObject(res);
9532 valuePush(ctxt, obj);
9533 ctxt->context->node = oldnode;
9534 CHECK_ERROR0;
9535 } else {
9536 /*
9537 * Initialize the new set.
9538 */
9539 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009540
Daniel Veillardf06307e2001-07-03 10:35:50 +00009541 for (i = 0; i < oldset->nodeNr; i++) {
9542 /*
9543 * Run the evaluation with a node list made of
9544 * a single item in the nodeset.
9545 */
9546 ctxt->context->node = oldset->nodeTab[i];
9547 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9548 valuePush(ctxt, tmp);
9549 ctxt->context->contextSize = oldset->nodeNr;
9550 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009551
Daniel Veillardf06307e2001-07-03 10:35:50 +00009552 if (op->ch2 != -1)
9553 total +=
9554 xmlXPathCompOpEval(ctxt,
9555 &comp->steps[op->ch2]);
9556 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009557
Daniel Veillardf06307e2001-07-03 10:35:50 +00009558 /*
9559 * The result of the evaluation need to be tested to
9560 * decided whether the filter succeeded or not
9561 */
9562 res = valuePop(ctxt);
9563 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9564 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9565 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009566
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 /*
9568 * Cleanup
9569 */
9570 if (res != NULL)
9571 xmlXPathFreeObject(res);
9572 if (ctxt->value == tmp) {
9573 res = valuePop(ctxt);
9574 xmlXPathFreeObject(res);
9575 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009576
Daniel Veillardf06307e2001-07-03 10:35:50 +00009577 ctxt->context->node = NULL;
9578 }
9579
9580 /*
9581 * The result is used as the new evaluation set.
9582 */
9583 xmlXPathFreeObject(obj);
9584 ctxt->context->node = NULL;
9585 ctxt->context->contextSize = -1;
9586 ctxt->context->proximityPosition = -1;
9587 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9588 }
9589 ctxt->context->node = oldnode;
9590 return (total);
9591 }
9592 case XPATH_OP_SORT:
9593 if (op->ch1 != -1)
9594 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009595 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009596 if ((ctxt->value != NULL) &&
9597 (ctxt->value->type == XPATH_NODESET) &&
9598 (ctxt->value->nodesetval != NULL))
9599 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9600 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009601#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009602 case XPATH_OP_RANGETO:{
9603 xmlXPathObjectPtr range;
9604 xmlXPathObjectPtr res, obj;
9605 xmlXPathObjectPtr tmp;
9606 xmlLocationSetPtr newset = NULL;
9607 xmlNodeSetPtr oldset;
9608 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009609
Daniel Veillardf06307e2001-07-03 10:35:50 +00009610 if (op->ch1 != -1)
9611 total +=
9612 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9613 if (op->ch2 == -1)
9614 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009615
Daniel Veillardf06307e2001-07-03 10:35:50 +00009616 CHECK_TYPE0(XPATH_NODESET);
9617 obj = valuePop(ctxt);
9618 oldset = obj->nodesetval;
9619 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009620
Daniel Veillardf06307e2001-07-03 10:35:50 +00009621 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009622
Daniel Veillardf06307e2001-07-03 10:35:50 +00009623 if (oldset != NULL) {
9624 for (i = 0; i < oldset->nodeNr; i++) {
9625 /*
9626 * Run the evaluation with a node list made of a single item
9627 * in the nodeset.
9628 */
9629 ctxt->context->node = oldset->nodeTab[i];
9630 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9631 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009632
Daniel Veillardf06307e2001-07-03 10:35:50 +00009633 if (op->ch2 != -1)
9634 total +=
9635 xmlXPathCompOpEval(ctxt,
9636 &comp->steps[op->ch2]);
9637 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009638
Daniel Veillardf06307e2001-07-03 10:35:50 +00009639 /*
9640 * The result of the evaluation need to be tested to
9641 * decided whether the filter succeeded or not
9642 */
9643 res = valuePop(ctxt);
9644 range =
9645 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9646 res);
9647 if (range != NULL) {
9648 xmlXPtrLocationSetAdd(newset, range);
9649 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009650
Daniel Veillardf06307e2001-07-03 10:35:50 +00009651 /*
9652 * Cleanup
9653 */
9654 if (res != NULL)
9655 xmlXPathFreeObject(res);
9656 if (ctxt->value == tmp) {
9657 res = valuePop(ctxt);
9658 xmlXPathFreeObject(res);
9659 }
9660
9661 ctxt->context->node = NULL;
9662 }
9663 }
9664
9665 /*
9666 * The result is used as the new evaluation set.
9667 */
9668 xmlXPathFreeObject(obj);
9669 ctxt->context->node = NULL;
9670 ctxt->context->contextSize = -1;
9671 ctxt->context->proximityPosition = -1;
9672 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9673 return (total);
9674 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009675#endif /* LIBXML_XPTR_ENABLED */
9676 }
9677 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009678 "XPath: unknown precompiled operation %d\n", op->op);
9679 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009680}
9681
9682/**
9683 * xmlXPathRunEval:
9684 * @ctxt: the XPath parser context with the compiled expression
9685 *
9686 * Evaluate the Precompiled XPath expression in the given context.
9687 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009688static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009689xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9690 xmlXPathCompExprPtr comp;
9691
9692 if ((ctxt == NULL) || (ctxt->comp == NULL))
9693 return;
9694
9695 if (ctxt->valueTab == NULL) {
9696 /* Allocate the value stack */
9697 ctxt->valueTab = (xmlXPathObjectPtr *)
9698 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9699 if (ctxt->valueTab == NULL) {
9700 xmlFree(ctxt);
9701 xmlGenericError(xmlGenericErrorContext,
9702 "xmlXPathRunEval: out of memory\n");
9703 return;
9704 }
9705 ctxt->valueNr = 0;
9706 ctxt->valueMax = 10;
9707 ctxt->value = NULL;
9708 }
9709 comp = ctxt->comp;
9710 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9711}
9712
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009713/************************************************************************
9714 * *
9715 * Public interfaces *
9716 * *
9717 ************************************************************************/
9718
9719/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009720 * xmlXPathEvalPredicate:
9721 * @ctxt: the XPath context
9722 * @res: the Predicate Expression evaluation result
9723 *
9724 * Evaluate a predicate result for the current node.
9725 * A PredicateExpr is evaluated by evaluating the Expr and converting
9726 * the result to a boolean. If the result is a number, the result will
9727 * be converted to true if the number is equal to the position of the
9728 * context node in the context node list (as returned by the position
9729 * function) and will be converted to false otherwise; if the result
9730 * is not a number, then the result will be converted as if by a call
9731 * to the boolean function.
9732 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009733 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009734 */
9735int
9736xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9737 if (res == NULL) return(0);
9738 switch (res->type) {
9739 case XPATH_BOOLEAN:
9740 return(res->boolval);
9741 case XPATH_NUMBER:
9742 return(res->floatval == ctxt->proximityPosition);
9743 case XPATH_NODESET:
9744 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009745 if (res->nodesetval == NULL)
9746 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009747 return(res->nodesetval->nodeNr != 0);
9748 case XPATH_STRING:
9749 return((res->stringval != NULL) &&
9750 (xmlStrlen(res->stringval) != 0));
9751 default:
9752 STRANGE
9753 }
9754 return(0);
9755}
9756
9757/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009758 * xmlXPathEvaluatePredicateResult:
9759 * @ctxt: the XPath Parser context
9760 * @res: the Predicate Expression evaluation result
9761 *
9762 * Evaluate a predicate result for the current node.
9763 * A PredicateExpr is evaluated by evaluating the Expr and converting
9764 * the result to a boolean. If the result is a number, the result will
9765 * be converted to true if the number is equal to the position of the
9766 * context node in the context node list (as returned by the position
9767 * function) and will be converted to false otherwise; if the result
9768 * is not a number, then the result will be converted as if by a call
9769 * to the boolean function.
9770 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009771 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009772 */
9773int
9774xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9775 xmlXPathObjectPtr res) {
9776 if (res == NULL) return(0);
9777 switch (res->type) {
9778 case XPATH_BOOLEAN:
9779 return(res->boolval);
9780 case XPATH_NUMBER:
9781 return(res->floatval == ctxt->context->proximityPosition);
9782 case XPATH_NODESET:
9783 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009784 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009785 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009786 return(res->nodesetval->nodeNr != 0);
9787 case XPATH_STRING:
9788 return((res->stringval != NULL) &&
9789 (xmlStrlen(res->stringval) != 0));
9790 default:
9791 STRANGE
9792 }
9793 return(0);
9794}
9795
9796/**
9797 * xmlXPathCompile:
9798 * @str: the XPath expression
9799 *
9800 * Compile an XPath expression
9801 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009802 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009803 * the caller has to free the object.
9804 */
9805xmlXPathCompExprPtr
9806xmlXPathCompile(const xmlChar *str) {
9807 xmlXPathParserContextPtr ctxt;
9808 xmlXPathCompExprPtr comp;
9809
9810 xmlXPathInit();
9811
9812 ctxt = xmlXPathNewParserContext(str, NULL);
9813 xmlXPathCompileExpr(ctxt);
9814
Daniel Veillard40af6492001-04-22 08:50:55 +00009815 if (*ctxt->cur != 0) {
9816 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9817 comp = NULL;
9818 } else {
9819 comp = ctxt->comp;
9820 ctxt->comp = NULL;
9821 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009822 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009823#ifdef DEBUG_EVAL_COUNTS
9824 if (comp != NULL) {
9825 comp->string = xmlStrdup(str);
9826 comp->nb = 0;
9827 }
9828#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009829 return(comp);
9830}
9831
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009832/**
9833 * xmlXPathCompiledEval:
9834 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009835 * @ctx: the XPath context
9836 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009837 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009838 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009839 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +00009840 * the caller has to free the object.
9841 */
9842xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009843xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009844 xmlXPathParserContextPtr ctxt;
9845 xmlXPathObjectPtr res, tmp, init = NULL;
9846 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00009847#ifndef LIBXML_THREAD_ENABLED
9848 static int reentance = 0;
9849#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009850
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009851 if ((comp == NULL) || (ctx == NULL))
9852 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009853 xmlXPathInit();
9854
9855 CHECK_CONTEXT(ctx)
9856
Daniel Veillard81463942001-10-16 12:34:39 +00009857#ifndef LIBXML_THREAD_ENABLED
9858 reentance++;
9859 if (reentance > 1)
9860 xmlXPathDisableOptimizer = 1;
9861#endif
9862
Daniel Veillardf06307e2001-07-03 10:35:50 +00009863#ifdef DEBUG_EVAL_COUNTS
9864 comp->nb++;
9865 if ((comp->string != NULL) && (comp->nb > 100)) {
9866 fprintf(stderr, "100 x %s\n", comp->string);
9867 comp->nb = 0;
9868 }
9869#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009870 ctxt = xmlXPathCompParserContext(comp, ctx);
9871 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009872
9873 if (ctxt->value == NULL) {
9874 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009875 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00009876 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009877 } else {
9878 res = valuePop(ctxt);
9879 }
9880
Daniel Veillardf06307e2001-07-03 10:35:50 +00009881
Owen Taylor3473f882001-02-23 17:55:21 +00009882 do {
9883 tmp = valuePop(ctxt);
9884 if (tmp != NULL) {
9885 if (tmp != init)
9886 stack++;
9887 xmlXPathFreeObject(tmp);
9888 }
9889 } while (tmp != NULL);
9890 if ((stack != 0) && (res != NULL)) {
9891 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009892 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +00009893 stack);
9894 }
9895 if (ctxt->error != XPATH_EXPRESSION_OK) {
9896 xmlXPathFreeObject(res);
9897 res = NULL;
9898 }
9899
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009900
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009901 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009902 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +00009903#ifndef LIBXML_THREAD_ENABLED
9904 reentance--;
9905#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009906 return(res);
9907}
9908
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009909/**
9910 * xmlXPathEvalExpr:
9911 * @ctxt: the XPath Parser context
9912 *
9913 * Parse and evaluate an XPath expression in the given context,
9914 * then push the result on the context stack
9915 */
9916void
9917xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9918 xmlXPathCompileExpr(ctxt);
9919 xmlXPathRunEval(ctxt);
9920}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009921
9922/**
9923 * xmlXPathEval:
9924 * @str: the XPath expression
9925 * @ctx: the XPath context
9926 *
9927 * Evaluate the XPath Location Path in the given context.
9928 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009929 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009930 * the caller has to free the object.
9931 */
9932xmlXPathObjectPtr
9933xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9934 xmlXPathParserContextPtr ctxt;
9935 xmlXPathObjectPtr res, tmp, init = NULL;
9936 int stack = 0;
9937
9938 xmlXPathInit();
9939
9940 CHECK_CONTEXT(ctx)
9941
9942 ctxt = xmlXPathNewParserContext(str, ctx);
9943 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009944
9945 if (ctxt->value == NULL) {
9946 xmlGenericError(xmlGenericErrorContext,
9947 "xmlXPathEval: evaluation failed\n");
9948 res = NULL;
9949 } else if (*ctxt->cur != 0) {
9950 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9951 res = NULL;
9952 } else {
9953 res = valuePop(ctxt);
9954 }
9955
9956 do {
9957 tmp = valuePop(ctxt);
9958 if (tmp != NULL) {
9959 if (tmp != init)
9960 stack++;
9961 xmlXPathFreeObject(tmp);
9962 }
9963 } while (tmp != NULL);
9964 if ((stack != 0) && (res != NULL)) {
9965 xmlGenericError(xmlGenericErrorContext,
9966 "xmlXPathEval: %d object left on the stack\n",
9967 stack);
9968 }
9969 if (ctxt->error != XPATH_EXPRESSION_OK) {
9970 xmlXPathFreeObject(res);
9971 res = NULL;
9972 }
9973
Owen Taylor3473f882001-02-23 17:55:21 +00009974 xmlXPathFreeParserContext(ctxt);
9975 return(res);
9976}
9977
9978/**
9979 * xmlXPathEvalExpression:
9980 * @str: the XPath expression
9981 * @ctxt: the XPath context
9982 *
9983 * Evaluate the XPath expression in the given context.
9984 *
9985 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9986 * the caller has to free the object.
9987 */
9988xmlXPathObjectPtr
9989xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9990 xmlXPathParserContextPtr pctxt;
9991 xmlXPathObjectPtr res, tmp;
9992 int stack = 0;
9993
9994 xmlXPathInit();
9995
9996 CHECK_CONTEXT(ctxt)
9997
9998 pctxt = xmlXPathNewParserContext(str, ctxt);
9999 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010000
10001 if (*pctxt->cur != 0) {
10002 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10003 res = NULL;
10004 } else {
10005 res = valuePop(pctxt);
10006 }
10007 do {
10008 tmp = valuePop(pctxt);
10009 if (tmp != NULL) {
10010 xmlXPathFreeObject(tmp);
10011 stack++;
10012 }
10013 } while (tmp != NULL);
10014 if ((stack != 0) && (res != NULL)) {
10015 xmlGenericError(xmlGenericErrorContext,
10016 "xmlXPathEvalExpression: %d object left on the stack\n",
10017 stack);
10018 }
10019 xmlXPathFreeParserContext(pctxt);
10020 return(res);
10021}
10022
10023/**
10024 * xmlXPathRegisterAllFunctions:
10025 * @ctxt: the XPath context
10026 *
10027 * Registers all default XPath functions in this context
10028 */
10029void
10030xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10031{
10032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10033 xmlXPathBooleanFunction);
10034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10035 xmlXPathCeilingFunction);
10036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10037 xmlXPathCountFunction);
10038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10039 xmlXPathConcatFunction);
10040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10041 xmlXPathContainsFunction);
10042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10043 xmlXPathIdFunction);
10044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10045 xmlXPathFalseFunction);
10046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10047 xmlXPathFloorFunction);
10048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10049 xmlXPathLastFunction);
10050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10051 xmlXPathLangFunction);
10052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10053 xmlXPathLocalNameFunction);
10054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10055 xmlXPathNotFunction);
10056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10057 xmlXPathNameFunction);
10058 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10059 xmlXPathNamespaceURIFunction);
10060 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10061 xmlXPathNormalizeFunction);
10062 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10063 xmlXPathNumberFunction);
10064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10065 xmlXPathPositionFunction);
10066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10067 xmlXPathRoundFunction);
10068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10069 xmlXPathStringFunction);
10070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10071 xmlXPathStringLengthFunction);
10072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10073 xmlXPathStartsWithFunction);
10074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10075 xmlXPathSubstringFunction);
10076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10077 xmlXPathSubstringBeforeFunction);
10078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10079 xmlXPathSubstringAfterFunction);
10080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10081 xmlXPathSumFunction);
10082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10083 xmlXPathTrueFunction);
10084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10085 xmlXPathTranslateFunction);
10086}
10087
10088#endif /* LIBXML_XPATH_ENABLED */