blob: 548d20e33c622b9fb2a1ebd2e8d2ccf2ed2d7bef [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 *
11 * See COPYRIGHT for the status of this software
12 *
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
33#ifdef HAVE_IEEEFP_H
34#include <ieeefp.h>
35#endif
36#ifdef HAVE_NAN_H
37#include <nan.h>
38#endif
39#ifdef HAVE_CTYPE_H
40#include <ctype.h>
41#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000042#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000043#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000044#endif
Owen Taylor3473f882001-02-23 17:55:21 +000045
46#include <libxml/xmlmemory.h>
47#include <libxml/tree.h>
48#include <libxml/valid.h>
49#include <libxml/xpath.h>
50#include <libxml/xpathInternals.h>
51#include <libxml/parserInternals.h>
52#include <libxml/hash.h>
53#ifdef LIBXML_XPTR_ENABLED
54#include <libxml/xpointer.h>
55#endif
56#ifdef LIBXML_DEBUG_ENABLED
57#include <libxml/debugXML.h>
58#endif
59#include <libxml/xmlerror.h>
60
61/* #define DEBUG */
62/* #define DEBUG_STEP */
63/* #define DEBUG_EXPR */
64
65void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
66double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000067double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000068
Daniel Veillard9e7160d2001-03-18 23:17:47 +000069/************************************************************************
70 * *
71 * Floating point stuff *
72 * *
73 ************************************************************************/
74
Owen Taylor3473f882001-02-23 17:55:21 +000075/*
Owen Taylor3473f882001-02-23 17:55:21 +000076 * The lack of portability of this section of the libc is annoying !
77 */
78double xmlXPathNAN = 0;
79double xmlXPathPINF = 1;
80double xmlXPathNINF = -1;
81
82#ifndef isinf
83#ifndef HAVE_ISINF
84
85#if HAVE_FPCLASS
86
87int isinf(double d) {
88 fpclass_t type = fpclass(d);
89 switch (type) {
90 case FP_NINF:
91 return(-1);
92 case FP_PINF:
93 return(1);
94 }
95 return(0);
96}
97
98#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
99
100#if HAVE_FP_CLASS_H
101#include <fp_class.h>
102#endif
103
104int isinf(double d) {
105#if HAVE_FP_CLASS
106 int fpclass = fp_class(d);
107#else
108 int fpclass = fp_class_d(d);
109#endif
110 if (fpclass == FP_POS_INF)
111 return(1);
112 if (fpclass == FP_NEG_INF)
113 return(-1);
114 return(0);
115}
116
117#elif defined(HAVE_CLASS)
118
119int isinf(double d) {
120 int fpclass = class(d);
121 if (fpclass == FP_PLUS_INF)
122 return(1);
123 if (fpclass == FP_MINUS_INF)
124 return(-1);
125 return(0);
126}
127#elif defined(finite) || defined(HAVE_FINITE)
128int isinf(double x) { return !finite(x) && x==x; }
129#elif defined(HUGE_VAL)
130int isinf(double x)
131{
132 if (x == HUGE_VAL)
133 return(1);
134 if (x == -HUGE_VAL)
135 return(-1);
136 return(0);
137}
138#endif
139
140#endif /* ! HAVE_ISINF */
141#endif /* ! defined(isinf) */
142
143#ifndef isnan
144#ifndef HAVE_ISNAN
145
146#ifdef HAVE_ISNAND
147#define isnan(f) isnand(f)
148#endif /* HAVE_iSNAND */
149
150#endif /* ! HAVE_iSNAN */
151#endif /* ! defined(isnan) */
152
Daniel Veillard5792e162001-04-30 17:44:45 +0000153
154/**
155 * xmlXPathDivideBy:
156 *
157 * The best way found so far to generate the NAN, +-INF
158 * without hitting a compiler bug or optimization :-\
159 *
160 * Returns the double resulting from the division
161 */
162double
163xmlXPathDivideBy(double f, double fzero) {
Daniel Veillard81418e32001-05-22 15:08:55 +0000164 double ret;
Daniel Veillard5792e162001-04-30 17:44:45 +0000165#ifdef HAVE_SIGNAL
166#ifdef SIGFPE
167#ifdef SIG_IGN
168 void (*sighandler)(int);
169 sighandler = signal(SIGFPE, SIG_IGN);
170#endif
171#endif
172#endif
173 ret = f / fzero;
174#ifdef HAVE_SIGNAL
175#ifdef SIGFPE
176#ifdef SIG_IGN
177 signal(SIGFPE, sighandler);
178#endif
179#endif
180#endif
181 return(ret);
182}
183
Owen Taylor3473f882001-02-23 17:55:21 +0000184/**
185 * xmlXPathInit:
186 *
187 * Initialize the XPath environment
188 */
189void
190xmlXPathInit(void) {
191 static int initialized = 0;
192
193 if (initialized) return;
194
Daniel Veillard5792e162001-04-30 17:44:45 +0000195 xmlXPathNAN = xmlXPathDivideBy(0.0, 0.0);
196 xmlXPathPINF = xmlXPathDivideBy(1.0, 0.0);
Daniel Veillard541d6552001-06-07 14:20:01 +0000197 xmlXPathNINF = xmlXPathDivideBy(-1.0, 0.0);
Owen Taylor3473f882001-02-23 17:55:21 +0000198
199 initialized = 1;
200}
201
202/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000203 * *
204 * Parser Types *
205 * *
206 ************************************************************************/
207
208/*
209 * Types are private:
210 */
211
212typedef enum {
213 XPATH_OP_END=0,
214 XPATH_OP_AND,
215 XPATH_OP_OR,
216 XPATH_OP_EQUAL,
217 XPATH_OP_CMP,
218 XPATH_OP_PLUS,
219 XPATH_OP_MULT,
220 XPATH_OP_UNION,
221 XPATH_OP_ROOT,
222 XPATH_OP_NODE,
223 XPATH_OP_RESET,
224 XPATH_OP_COLLECT,
225 XPATH_OP_VALUE,
226 XPATH_OP_VARIABLE,
227 XPATH_OP_FUNCTION,
228 XPATH_OP_ARG,
229 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000230 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000231 XPATH_OP_SORT
232#ifdef LIBXML_XPTR_ENABLED
233 ,XPATH_OP_RANGETO
234#endif
235} xmlXPathOp;
236
237typedef enum {
238 AXIS_ANCESTOR = 1,
239 AXIS_ANCESTOR_OR_SELF,
240 AXIS_ATTRIBUTE,
241 AXIS_CHILD,
242 AXIS_DESCENDANT,
243 AXIS_DESCENDANT_OR_SELF,
244 AXIS_FOLLOWING,
245 AXIS_FOLLOWING_SIBLING,
246 AXIS_NAMESPACE,
247 AXIS_PARENT,
248 AXIS_PRECEDING,
249 AXIS_PRECEDING_SIBLING,
250 AXIS_SELF
251} xmlXPathAxisVal;
252
253typedef enum {
254 NODE_TEST_NONE = 0,
255 NODE_TEST_TYPE = 1,
256 NODE_TEST_PI = 2,
257 NODE_TEST_ALL = 3,
258 NODE_TEST_NS = 4,
259 NODE_TEST_NAME = 5
260} xmlXPathTestVal;
261
262typedef enum {
263 NODE_TYPE_NODE = 0,
264 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
265 NODE_TYPE_TEXT = XML_TEXT_NODE,
266 NODE_TYPE_PI = XML_PI_NODE
267} xmlXPathTypeVal;
268
269
270typedef struct _xmlXPathStepOp xmlXPathStepOp;
271typedef xmlXPathStepOp *xmlXPathStepOpPtr;
272struct _xmlXPathStepOp {
273 xmlXPathOp op;
274 int ch1;
275 int ch2;
276 int value;
277 int value2;
278 int value3;
279 void *value4;
280 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000281 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000282 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000283};
284
285struct _xmlXPathCompExpr {
286 int nbStep;
287 int maxStep;
288 xmlXPathStepOp *steps; /* ops for computation */
289 int last;
290};
291
292/************************************************************************
293 * *
294 * Parser Type functions *
295 * *
296 ************************************************************************/
297
298/**
299 * xmlXPathNewCompExpr:
300 *
301 * Create a new Xpath component
302 *
303 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
304 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000305static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000306xmlXPathNewCompExpr(void) {
307 xmlXPathCompExprPtr cur;
308
309 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
310 if (cur == NULL) {
311 xmlGenericError(xmlGenericErrorContext,
312 "xmlXPathNewCompExpr : malloc failed\n");
313 return(NULL);
314 }
315 memset(cur, 0, sizeof(xmlXPathCompExpr));
316 cur->maxStep = 10;
317 cur->nbStep = 0;
318 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
319 sizeof(xmlXPathStepOp));
320 if (cur->steps == NULL) {
321 xmlGenericError(xmlGenericErrorContext,
322 "xmlXPathNewCompExpr : malloc failed\n");
323 xmlFree(cur);
324 return(NULL);
325 }
326 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
327 cur->last = -1;
328 return(cur);
329}
330
331/**
332 * xmlXPathFreeCompExpr:
333 * @comp: an XPATH comp
334 *
335 * Free up the memory allocated by @comp
336 */
337void
338xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) {
339 xmlXPathStepOpPtr op;
340 int i;
341
342 if (comp == NULL)
343 return;
344 for (i = 0;i < comp->nbStep;i++) {
345 op = &comp->steps[i];
346 if (op->value4 != NULL) {
347 if (op->op == XPATH_OP_VALUE)
348 xmlXPathFreeObject(op->value4);
349 else
350 xmlFree(op->value4);
351 }
352 if (op->value5 != NULL)
353 xmlFree(op->value5);
354 }
355 if (comp->steps != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000356 xmlFree(comp->steps);
357 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000358 xmlFree(comp);
359}
360
361/**
362 * xmlXPathCompExprAdd:
363 * @comp: the compiled expression
364 * @ch1: first child index
365 * @ch2: second child index
366 * @op: an op
367 * @value: the first int value
368 * @value2: the second int value
369 * @value3: the third int value
370 * @value4: the first string value
371 * @value5: the second string value
372 *
373 * Add an step to an XPath Compiled Expression
374 *
375 * Returns -1 in case of failure, the index otherwise
376 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000377static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000378xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
379 xmlXPathOp op, int value,
380 int value2, int value3, void *value4, void *value5) {
381 if (comp->nbStep >= comp->maxStep) {
382 xmlXPathStepOp *real;
383
384 comp->maxStep *= 2;
385 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
386 comp->maxStep * sizeof(xmlXPathStepOp));
387 if (real == NULL) {
388 comp->maxStep /= 2;
389 xmlGenericError(xmlGenericErrorContext,
390 "xmlXPathCompExprAdd : realloc failed\n");
391 return(-1);
392 }
393 comp->steps = real;
394 }
395 comp->last = comp->nbStep;
396 comp->steps[comp->nbStep].ch1 = ch1;
397 comp->steps[comp->nbStep].ch2 = ch2;
398 comp->steps[comp->nbStep].op = op;
399 comp->steps[comp->nbStep].value = value;
400 comp->steps[comp->nbStep].value2 = value2;
401 comp->steps[comp->nbStep].value3 = value3;
402 comp->steps[comp->nbStep].value4 = value4;
403 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000404 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000405 return(comp->nbStep++);
406}
407
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000408#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
409 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
410 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000411#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
412 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
413 (op), (val), (val2), (val3), (val4), (val5))
414
415#define PUSH_LEAVE_EXPR(op, val, val2) \
416xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
417
418#define PUSH_UNARY_EXPR(op, ch, val, val2) \
419xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
420
421#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
422xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
423
424/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000425 * *
426 * Debugging related functions *
427 * *
428 ************************************************************************/
429
430#define TODO \
431 xmlGenericError(xmlGenericErrorContext, \
432 "Unimplemented block at %s:%d\n", \
433 __FILE__, __LINE__);
434
435#define STRANGE \
436 xmlGenericError(xmlGenericErrorContext, \
437 "Internal error at %s:%d\n", \
438 __FILE__, __LINE__);
439
440#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000441static void
442xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000443 int i;
444 char shift[100];
445
446 for (i = 0;((i < depth) && (i < 25));i++)
447 shift[2 * i] = shift[2 * i + 1] = ' ';
448 shift[2 * i] = shift[2 * i + 1] = 0;
449 if (cur == NULL) {
450 fprintf(output, shift);
451 fprintf(output, "Node is NULL !\n");
452 return;
453
454 }
455
456 if ((cur->type == XML_DOCUMENT_NODE) ||
457 (cur->type == XML_HTML_DOCUMENT_NODE)) {
458 fprintf(output, shift);
459 fprintf(output, " /\n");
460 } else if (cur->type == XML_ATTRIBUTE_NODE)
461 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
462 else
463 xmlDebugDumpOneNode(output, cur, depth);
464}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000465static void
466xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000467 xmlNodePtr tmp;
468 int i;
469 char shift[100];
470
471 for (i = 0;((i < depth) && (i < 25));i++)
472 shift[2 * i] = shift[2 * i + 1] = ' ';
473 shift[2 * i] = shift[2 * i + 1] = 0;
474 if (cur == NULL) {
475 fprintf(output, shift);
476 fprintf(output, "Node is NULL !\n");
477 return;
478
479 }
480
481 while (cur != NULL) {
482 tmp = cur;
483 cur = cur->next;
484 xmlDebugDumpOneNode(output, tmp, depth);
485 }
486}
Owen Taylor3473f882001-02-23 17:55:21 +0000487
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000488static void
489xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000490 int i;
491 char shift[100];
492
493 for (i = 0;((i < depth) && (i < 25));i++)
494 shift[2 * i] = shift[2 * i + 1] = ' ';
495 shift[2 * i] = shift[2 * i + 1] = 0;
496
497 if (cur == NULL) {
498 fprintf(output, shift);
499 fprintf(output, "NodeSet is NULL !\n");
500 return;
501
502 }
503
Daniel Veillard911f49a2001-04-07 15:39:35 +0000504 if (cur != NULL) {
505 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
506 for (i = 0;i < cur->nodeNr;i++) {
507 fprintf(output, shift);
508 fprintf(output, "%d", i + 1);
509 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
510 }
Owen Taylor3473f882001-02-23 17:55:21 +0000511 }
512}
513
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000514static void
515xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000516 int i;
517 char shift[100];
518
519 for (i = 0;((i < depth) && (i < 25));i++)
520 shift[2 * i] = shift[2 * i + 1] = ' ';
521 shift[2 * i] = shift[2 * i + 1] = 0;
522
523 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
524 fprintf(output, shift);
525 fprintf(output, "Value Tree is NULL !\n");
526 return;
527
528 }
529
530 fprintf(output, shift);
531 fprintf(output, "%d", i + 1);
532 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
533}
Owen Taylor3473f882001-02-23 17:55:21 +0000534#if defined(LIBXML_XPTR_ENABLED)
535void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000536static void
537xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000538 int i;
539 char shift[100];
540
541 for (i = 0;((i < depth) && (i < 25));i++)
542 shift[2 * i] = shift[2 * i + 1] = ' ';
543 shift[2 * i] = shift[2 * i + 1] = 0;
544
545 if (cur == NULL) {
546 fprintf(output, shift);
547 fprintf(output, "LocationSet is NULL !\n");
548 return;
549
550 }
551
552 for (i = 0;i < cur->locNr;i++) {
553 fprintf(output, shift);
554 fprintf(output, "%d : ", i + 1);
555 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
556 }
557}
Daniel Veillard017b1082001-06-21 11:20:21 +0000558#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000559
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000560/**
561 * xmlXPathDebugDumpObject:
562 * @output: the FILE * to dump the output
563 * @cur: the object to inspect
564 * @depth: indentation level
565 *
566 * Dump the content of the object for debugging purposes
567 */
568void
569xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000570 int i;
571 char shift[100];
572
573 for (i = 0;((i < depth) && (i < 25));i++)
574 shift[2 * i] = shift[2 * i + 1] = ' ';
575 shift[2 * i] = shift[2 * i + 1] = 0;
576
577 fprintf(output, shift);
578
579 if (cur == NULL) {
580 fprintf(output, "Object is empty (NULL)\n");
581 return;
582 }
583 switch(cur->type) {
584 case XPATH_UNDEFINED:
585 fprintf(output, "Object is uninitialized\n");
586 break;
587 case XPATH_NODESET:
588 fprintf(output, "Object is a Node Set :\n");
589 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
590 break;
591 case XPATH_XSLT_TREE:
592 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000593 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000594 break;
595 case XPATH_BOOLEAN:
596 fprintf(output, "Object is a Boolean : ");
597 if (cur->boolval) fprintf(output, "true\n");
598 else fprintf(output, "false\n");
599 break;
600 case XPATH_NUMBER:
Daniel Veillard357c9602001-05-03 10:49:20 +0000601 switch (isinf(cur->floatval)) {
602 case 1:
603 fprintf(output, "Object is a number : +Infinity\n");
604 break;
605 case -1:
606 fprintf(output, "Object is a number : -Infinity\n");
607 break;
608 default:
609 if (isnan(cur->floatval)) {
610 fprintf(output, "Object is a number : NaN\n");
611 } else {
612 fprintf(output, "Object is a number : %0g\n", cur->floatval);
613 }
614 }
Owen Taylor3473f882001-02-23 17:55:21 +0000615 break;
616 case XPATH_STRING:
617 fprintf(output, "Object is a string : ");
618 xmlDebugDumpString(output, cur->stringval);
619 fprintf(output, "\n");
620 break;
621 case XPATH_POINT:
622 fprintf(output, "Object is a point : index %d in node", cur->index);
623 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
624 fprintf(output, "\n");
625 break;
626 case XPATH_RANGE:
627 if ((cur->user2 == NULL) ||
628 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
629 fprintf(output, "Object is a collapsed range :\n");
630 fprintf(output, shift);
631 if (cur->index >= 0)
632 fprintf(output, "index %d in ", cur->index);
633 fprintf(output, "node\n");
634 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
635 depth + 1);
636 } else {
637 fprintf(output, "Object is a range :\n");
638 fprintf(output, shift);
639 fprintf(output, "From ");
640 if (cur->index >= 0)
641 fprintf(output, "index %d in ", cur->index);
642 fprintf(output, "node\n");
643 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
644 depth + 1);
645 fprintf(output, shift);
646 fprintf(output, "To ");
647 if (cur->index2 >= 0)
648 fprintf(output, "index %d in ", cur->index2);
649 fprintf(output, "node\n");
650 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
651 depth + 1);
652 fprintf(output, "\n");
653 }
654 break;
655 case XPATH_LOCATIONSET:
656#if defined(LIBXML_XPTR_ENABLED)
657 fprintf(output, "Object is a Location Set:\n");
658 xmlXPathDebugDumpLocationSet(output,
659 (xmlLocationSetPtr) cur->user, depth);
660#endif
661 break;
662 case XPATH_USERS:
663 fprintf(output, "Object is user defined\n");
664 break;
665 }
666}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000667
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000668static void
669xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000670 xmlXPathStepOpPtr op, int depth) {
671 int i;
672 char shift[100];
673
674 for (i = 0;((i < depth) && (i < 25));i++)
675 shift[2 * i] = shift[2 * i + 1] = ' ';
676 shift[2 * i] = shift[2 * i + 1] = 0;
677
678 fprintf(output, shift);
679 if (op == NULL) {
680 fprintf(output, "Step is NULL\n");
681 return;
682 }
683 switch (op->op) {
684 case XPATH_OP_END:
685 fprintf(output, "END"); break;
686 case XPATH_OP_AND:
687 fprintf(output, "AND"); break;
688 case XPATH_OP_OR:
689 fprintf(output, "OR"); break;
690 case XPATH_OP_EQUAL:
691 if (op->value)
692 fprintf(output, "EQUAL =");
693 else
694 fprintf(output, "EQUAL !=");
695 break;
696 case XPATH_OP_CMP:
697 if (op->value)
698 fprintf(output, "CMP <");
699 else
700 fprintf(output, "CMP >");
701 if (!op->value2)
702 fprintf(output, "=");
703 break;
704 case XPATH_OP_PLUS:
705 if (op->value == 0)
706 fprintf(output, "PLUS -");
707 else if (op->value == 1)
708 fprintf(output, "PLUS +");
709 else if (op->value == 2)
710 fprintf(output, "PLUS unary -");
711 else if (op->value == 3)
712 fprintf(output, "PLUS unary - -");
713 break;
714 case XPATH_OP_MULT:
715 if (op->value == 0)
716 fprintf(output, "MULT *");
717 else if (op->value == 1)
718 fprintf(output, "MULT div");
719 else
720 fprintf(output, "MULT mod");
721 break;
722 case XPATH_OP_UNION:
723 fprintf(output, "UNION"); break;
724 case XPATH_OP_ROOT:
725 fprintf(output, "ROOT"); break;
726 case XPATH_OP_NODE:
727 fprintf(output, "NODE"); break;
728 case XPATH_OP_RESET:
729 fprintf(output, "RESET"); break;
730 case XPATH_OP_SORT:
731 fprintf(output, "SORT"); break;
732 case XPATH_OP_COLLECT: {
733 xmlXPathAxisVal axis = op->value;
734 xmlXPathTestVal test = op->value2;
735 xmlXPathTypeVal type = op->value3;
736 const xmlChar *prefix = op->value4;
737 const xmlChar *name = op->value5;
738
739 fprintf(output, "COLLECT ");
740 switch (axis) {
741 case AXIS_ANCESTOR:
742 fprintf(output, " 'ancestors' "); break;
743 case AXIS_ANCESTOR_OR_SELF:
744 fprintf(output, " 'ancestors-or-self' "); break;
745 case AXIS_ATTRIBUTE:
746 fprintf(output, " 'attributes' "); break;
747 case AXIS_CHILD:
748 fprintf(output, " 'child' "); break;
749 case AXIS_DESCENDANT:
750 fprintf(output, " 'descendant' "); break;
751 case AXIS_DESCENDANT_OR_SELF:
752 fprintf(output, " 'descendant-or-self' "); break;
753 case AXIS_FOLLOWING:
754 fprintf(output, " 'following' "); break;
755 case AXIS_FOLLOWING_SIBLING:
756 fprintf(output, " 'following-siblings' "); break;
757 case AXIS_NAMESPACE:
758 fprintf(output, " 'namespace' "); break;
759 case AXIS_PARENT:
760 fprintf(output, " 'parent' "); break;
761 case AXIS_PRECEDING:
762 fprintf(output, " 'preceding' "); break;
763 case AXIS_PRECEDING_SIBLING:
764 fprintf(output, " 'preceding-sibling' "); break;
765 case AXIS_SELF:
766 fprintf(output, " 'self' "); break;
767 }
768 switch (test) {
769 case NODE_TEST_NONE:
770 fprintf(output, "'none' "); break;
771 case NODE_TEST_TYPE:
772 fprintf(output, "'type' "); break;
773 case NODE_TEST_PI:
774 fprintf(output, "'PI' "); break;
775 case NODE_TEST_ALL:
776 fprintf(output, "'all' "); break;
777 case NODE_TEST_NS:
778 fprintf(output, "'namespace' "); break;
779 case NODE_TEST_NAME:
780 fprintf(output, "'name' "); break;
781 }
782 switch (type) {
783 case NODE_TYPE_NODE:
784 fprintf(output, "'node' "); break;
785 case NODE_TYPE_COMMENT:
786 fprintf(output, "'comment' "); break;
787 case NODE_TYPE_TEXT:
788 fprintf(output, "'text' "); break;
789 case NODE_TYPE_PI:
790 fprintf(output, "'PI' "); break;
791 }
792 if (prefix != NULL)
793 fprintf(output, "%s:", prefix);
794 if (name != NULL)
795 fprintf(output, "%s", name);
796 break;
797
798 }
799 case XPATH_OP_VALUE: {
800 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
801
802 fprintf(output, "ELEM ");
803 xmlXPathDebugDumpObject(output, object, 0);
804 goto finish;
805 }
806 case XPATH_OP_VARIABLE: {
807 const xmlChar *prefix = op->value5;
808 const xmlChar *name = op->value4;
809
810 if (prefix != NULL)
811 fprintf(output, "VARIABLE %s:%s", prefix, name);
812 else
813 fprintf(output, "VARIABLE %s", name);
814 break;
815 }
816 case XPATH_OP_FUNCTION: {
817 int nbargs = op->value;
818 const xmlChar *prefix = op->value5;
819 const xmlChar *name = op->value4;
820
821 if (prefix != NULL)
822 fprintf(output, "FUNCTION %s:%s(%d args)",
823 prefix, name, nbargs);
824 else
825 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
826 break;
827 }
828 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
829 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000830 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000831#ifdef LIBXML_XPTR_ENABLED
832 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
833#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000834 default:
835 fprintf(output, "UNKNOWN %d\n", op->op); return;
836 }
837 fprintf(output, "\n");
838finish:
839 if (op->ch1 >= 0)
840 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
841 if (op->ch2 >= 0)
842 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
843}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000844
845void
846xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
847 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000848 int i;
849 char shift[100];
850
851 for (i = 0;((i < depth) && (i < 25));i++)
852 shift[2 * i] = shift[2 * i + 1] = ' ';
853 shift[2 * i] = shift[2 * i + 1] = 0;
854
855 fprintf(output, shift);
856
857 if (comp == NULL) {
858 fprintf(output, "Compiled Expression is NULL\n");
859 return;
860 }
861 fprintf(output, "Compiled Expression : %d elements\n",
862 comp->nbStep);
863 i = comp->last;
864 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
865}
Daniel Veillard017b1082001-06-21 11:20:21 +0000866#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000867
868/************************************************************************
869 * *
870 * Parser stacks related functions and macros *
871 * *
872 ************************************************************************/
873
874/*
875 * Generic function for accessing stacks in the Parser Context
876 */
877
878#define PUSH_AND_POP(type, name) \
879extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
880 if (ctxt->name##Nr >= ctxt->name##Max) { \
881 ctxt->name##Max *= 2; \
882 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
883 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
884 if (ctxt->name##Tab == NULL) { \
885 xmlGenericError(xmlGenericErrorContext, \
886 "realloc failed !\n"); \
887 return(0); \
888 } \
889 } \
890 ctxt->name##Tab[ctxt->name##Nr] = value; \
891 ctxt->name = value; \
892 return(ctxt->name##Nr++); \
893} \
894extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
895 type ret; \
896 if (ctxt->name##Nr <= 0) return(0); \
897 ctxt->name##Nr--; \
898 if (ctxt->name##Nr > 0) \
899 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
900 else \
901 ctxt->name = NULL; \
902 ret = ctxt->name##Tab[ctxt->name##Nr]; \
903 ctxt->name##Tab[ctxt->name##Nr] = 0; \
904 return(ret); \
905} \
906
907PUSH_AND_POP(xmlXPathObjectPtr, value)
908
909/*
910 * Macros for accessing the content. Those should be used only by the parser,
911 * and not exported.
912 *
913 * Dirty macros, i.e. one need to make assumption on the context to use them
914 *
915 * CUR_PTR return the current pointer to the xmlChar to be parsed.
916 * CUR returns the current xmlChar value, i.e. a 8 bit value
917 * in ISO-Latin or UTF-8.
918 * This should be used internally by the parser
919 * only to compare to ASCII values otherwise it would break when
920 * running with UTF-8 encoding.
921 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
922 * to compare on ASCII based substring.
923 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
924 * strings within the parser.
925 * CURRENT Returns the current char value, with the full decoding of
926 * UTF-8 if we are using this mode. It returns an int.
927 * NEXT Skip to the next character, this does the proper decoding
928 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
929 * It returns the pointer to the current xmlChar.
930 */
931
932#define CUR (*ctxt->cur)
933#define SKIP(val) ctxt->cur += (val)
934#define NXT(val) ctxt->cur[(val)]
935#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +0000936#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
937
938#define COPY_BUF(l,b,i,v) \
939 if (l == 1) b[i++] = (xmlChar) v; \
940 else i += xmlCopyChar(l,&b[i],v)
941
942#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +0000943
944#define SKIP_BLANKS \
945 while (IS_BLANK(*(ctxt->cur))) NEXT
946
947#define CURRENT (*ctxt->cur)
948#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
949
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000950
951#ifndef DBL_DIG
952#define DBL_DIG 16
953#endif
954#ifndef DBL_EPSILON
955#define DBL_EPSILON 1E-9
956#endif
957
958#define UPPER_DOUBLE 1E9
959#define LOWER_DOUBLE 1E-5
960
961#define INTEGER_DIGITS DBL_DIG
962#define FRACTION_DIGITS (DBL_DIG + 1)
963#define EXPONENT_DIGITS (3 + 2)
964
965/**
966 * xmlXPathFormatNumber:
967 * @number: number to format
968 * @buffer: output buffer
969 * @buffersize: size of output buffer
970 *
971 * Convert the number into a string representation.
972 */
973static void
974xmlXPathFormatNumber(double number, char buffer[], int buffersize)
975{
976 switch (isinf(number)) {
977 case 1:
978 if (buffersize > (int)sizeof("+Infinity"))
979 sprintf(buffer, "+Infinity");
980 break;
981 case -1:
982 if (buffersize > (int)sizeof("-Infinity"))
983 sprintf(buffer, "-Infinity");
984 break;
985 default:
986 if (isnan(number)) {
987 if (buffersize > (int)sizeof("NaN"))
988 sprintf(buffer, "NaN");
989 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000990 /* 3 is sign, decimal point, and terminating zero */
991 char work[DBL_DIG + EXPONENT_DIGITS + 3];
992 int integer_place, fraction_place;
993 char *ptr;
994 char *after_fraction;
995 double absolute_value;
996 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000997
Bjorn Reese70a9da52001-04-21 16:57:29 +0000998 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000999
Bjorn Reese70a9da52001-04-21 16:57:29 +00001000 /*
1001 * First choose format - scientific or regular floating point.
1002 * In either case, result is in work, and after_fraction points
1003 * just past the fractional part.
1004 */
1005 if ( ((absolute_value > UPPER_DOUBLE) ||
1006 (absolute_value < LOWER_DOUBLE)) &&
1007 (absolute_value != 0.0) ) {
1008 /* Use scientific notation */
1009 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1010 fraction_place = DBL_DIG - 1;
1011 snprintf(work, sizeof(work),"%*.*e",
1012 integer_place, fraction_place, number);
1013 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001014 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001015 else {
1016 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001017 if (absolute_value > 0.0)
1018 integer_place = 1 + (int)log10(absolute_value);
1019 else
1020 integer_place = 1 - HUGE_VAL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001021 fraction_place = (integer_place > 0)
1022 ? DBL_DIG - integer_place
1023 : DBL_DIG;
1024 size = snprintf(work, sizeof(work), "%0.*f",
1025 fraction_place, number);
1026 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001027 }
1028
Bjorn Reese70a9da52001-04-21 16:57:29 +00001029 /* Remove fractional trailing zeroes */
1030 ptr = after_fraction;
1031 while (*(--ptr) == '0')
1032 ;
1033 if (*ptr != '.')
1034 ptr++;
1035 strcpy(ptr, after_fraction);
1036
1037 /* Finally copy result back to caller */
1038 size = strlen(work) + 1;
1039 if (size > buffersize) {
1040 work[buffersize - 1] = 0;
1041 size = buffersize;
1042 }
1043 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001044 }
1045 break;
1046 }
1047}
1048
Owen Taylor3473f882001-02-23 17:55:21 +00001049/************************************************************************
1050 * *
1051 * Error handling routines *
1052 * *
1053 ************************************************************************/
1054
1055
1056const char *xmlXPathErrorMessages[] = {
1057 "Ok",
1058 "Number encoding",
1059 "Unfinished litteral",
1060 "Start of litteral",
1061 "Expected $ for variable reference",
1062 "Undefined variable",
1063 "Invalid predicate",
1064 "Invalid expression",
1065 "Missing closing curly brace",
1066 "Unregistered function",
1067 "Invalid operand",
1068 "Invalid type",
1069 "Invalid number of arguments",
1070 "Invalid context size",
1071 "Invalid context position",
1072 "Memory allocation error",
1073 "Syntax error",
1074 "Resource error",
1075 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001076 "Undefined namespace prefix",
1077 "Encoding error",
1078 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001079};
1080
1081/**
1082 * xmlXPathError:
1083 * @ctxt: the XPath Parser context
1084 * @file: the file name
1085 * @line: the line number
1086 * @no: the error number
1087 *
1088 * Create a new xmlNodeSetPtr of type double and of value @val
1089 *
1090 * Returns the newly created object.
1091 */
1092void
1093xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1094 int line, int no) {
1095 int n;
1096 const xmlChar *cur;
1097 const xmlChar *base;
1098
1099 xmlGenericError(xmlGenericErrorContext,
1100 "Error %s:%d: %s\n", file, line,
1101 xmlXPathErrorMessages[no]);
1102
1103 cur = ctxt->cur;
1104 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001105 if ((cur == NULL) || (base == NULL))
1106 return;
1107
Owen Taylor3473f882001-02-23 17:55:21 +00001108 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1109 cur--;
1110 }
1111 n = 0;
1112 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1113 cur--;
1114 if ((*cur == '\n') || (*cur == '\r')) cur++;
1115 base = cur;
1116 n = 0;
1117 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1118 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1119 n++;
1120 }
1121 xmlGenericError(xmlGenericErrorContext, "\n");
1122 cur = ctxt->cur;
1123 while ((*cur == '\n') || (*cur == '\r'))
1124 cur--;
1125 n = 0;
1126 while ((cur != base) && (n++ < 80)) {
1127 xmlGenericError(xmlGenericErrorContext, " ");
1128 base++;
1129 }
1130 xmlGenericError(xmlGenericErrorContext,"^\n");
1131}
1132
1133
1134/************************************************************************
1135 * *
1136 * Routines to handle NodeSets *
1137 * *
1138 ************************************************************************/
1139
1140/**
1141 * xmlXPathCmpNodes:
1142 * @node1: the first node
1143 * @node2: the second node
1144 *
1145 * Compare two nodes w.r.t document order
1146 *
1147 * Returns -2 in case of error 1 if first point < second point, 0 if
1148 * that's the same node, -1 otherwise
1149 */
1150int
1151xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1152 int depth1, depth2;
1153 xmlNodePtr cur, root;
1154
1155 if ((node1 == NULL) || (node2 == NULL))
1156 return(-2);
1157 /*
1158 * a couple of optimizations which will avoid computations in most cases
1159 */
1160 if (node1 == node2)
1161 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001162 if ((node1->type == XML_NAMESPACE_DECL) ||
1163 (node2->type == XML_NAMESPACE_DECL))
1164 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001165 if (node1 == node2->prev)
1166 return(1);
1167 if (node1 == node2->next)
1168 return(-1);
1169
1170 /*
1171 * compute depth to root
1172 */
1173 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1174 if (cur == node1)
1175 return(1);
1176 depth2++;
1177 }
1178 root = cur;
1179 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1180 if (cur == node2)
1181 return(-1);
1182 depth1++;
1183 }
1184 /*
1185 * Distinct document (or distinct entities :-( ) case.
1186 */
1187 if (root != cur) {
1188 return(-2);
1189 }
1190 /*
1191 * get the nearest common ancestor.
1192 */
1193 while (depth1 > depth2) {
1194 depth1--;
1195 node1 = node1->parent;
1196 }
1197 while (depth2 > depth1) {
1198 depth2--;
1199 node2 = node2->parent;
1200 }
1201 while (node1->parent != node2->parent) {
1202 node1 = node1->parent;
1203 node2 = node2->parent;
1204 /* should not happen but just in case ... */
1205 if ((node1 == NULL) || (node2 == NULL))
1206 return(-2);
1207 }
1208 /*
1209 * Find who's first.
1210 */
1211 if (node1 == node2->next)
1212 return(-1);
1213 for (cur = node1->next;cur != NULL;cur = cur->next)
1214 if (cur == node2)
1215 return(1);
1216 return(-1); /* assume there is no sibling list corruption */
1217}
1218
1219/**
1220 * xmlXPathNodeSetSort:
1221 * @set: the node set
1222 *
1223 * Sort the node set in document order
1224 */
1225void
1226xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001227 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001228 xmlNodePtr tmp;
1229
1230 if (set == NULL)
1231 return;
1232
1233 /* Use Shell's sort to sort the node-set */
1234 len = set->nodeNr;
1235 for (incr = len / 2; incr > 0; incr /= 2) {
1236 for (i = incr; i < len; i++) {
1237 j = i - incr;
1238 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001239 if (xmlXPathCmpNodes(set->nodeTab[j],
1240 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001241 tmp = set->nodeTab[j];
1242 set->nodeTab[j] = set->nodeTab[j + incr];
1243 set->nodeTab[j + incr] = tmp;
1244 j -= incr;
1245 } else
1246 break;
1247 }
1248 }
1249 }
1250}
1251
1252#define XML_NODESET_DEFAULT 10
1253/**
1254 * xmlXPathNodeSetCreate:
1255 * @val: an initial xmlNodePtr, or NULL
1256 *
1257 * Create a new xmlNodeSetPtr of type double and of value @val
1258 *
1259 * Returns the newly created object.
1260 */
1261xmlNodeSetPtr
1262xmlXPathNodeSetCreate(xmlNodePtr val) {
1263 xmlNodeSetPtr ret;
1264
1265 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1266 if (ret == NULL) {
1267 xmlGenericError(xmlGenericErrorContext,
1268 "xmlXPathNewNodeSet: out of memory\n");
1269 return(NULL);
1270 }
1271 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1272 if (val != NULL) {
1273 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1274 sizeof(xmlNodePtr));
1275 if (ret->nodeTab == NULL) {
1276 xmlGenericError(xmlGenericErrorContext,
1277 "xmlXPathNewNodeSet: out of memory\n");
1278 return(NULL);
1279 }
1280 memset(ret->nodeTab, 0 ,
1281 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1282 ret->nodeMax = XML_NODESET_DEFAULT;
1283 ret->nodeTab[ret->nodeNr++] = val;
1284 }
1285 return(ret);
1286}
1287
1288/**
1289 * xmlXPathNodeSetAdd:
1290 * @cur: the initial node set
1291 * @val: a new xmlNodePtr
1292 *
1293 * add a new xmlNodePtr ot an existing NodeSet
1294 */
1295void
1296xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1297 int i;
1298
1299 if (val == NULL) return;
1300
1301 /*
1302 * check against doublons
1303 */
1304 for (i = 0;i < cur->nodeNr;i++)
1305 if (cur->nodeTab[i] == val) return;
1306
1307 /*
1308 * grow the nodeTab if needed
1309 */
1310 if (cur->nodeMax == 0) {
1311 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1312 sizeof(xmlNodePtr));
1313 if (cur->nodeTab == NULL) {
1314 xmlGenericError(xmlGenericErrorContext,
1315 "xmlXPathNodeSetAdd: out of memory\n");
1316 return;
1317 }
1318 memset(cur->nodeTab, 0 ,
1319 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1320 cur->nodeMax = XML_NODESET_DEFAULT;
1321 } else if (cur->nodeNr == cur->nodeMax) {
1322 xmlNodePtr *temp;
1323
1324 cur->nodeMax *= 2;
1325 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1326 sizeof(xmlNodePtr));
1327 if (temp == NULL) {
1328 xmlGenericError(xmlGenericErrorContext,
1329 "xmlXPathNodeSetAdd: out of memory\n");
1330 return;
1331 }
1332 cur->nodeTab = temp;
1333 }
1334 cur->nodeTab[cur->nodeNr++] = val;
1335}
1336
1337/**
1338 * xmlXPathNodeSetAddUnique:
1339 * @cur: the initial node set
1340 * @val: a new xmlNodePtr
1341 *
1342 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1343 * when we are sure the node is not already in the set.
1344 */
1345void
1346xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1347 if (val == NULL) return;
1348
1349 /*
1350 * grow the nodeTab if needed
1351 */
1352 if (cur->nodeMax == 0) {
1353 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1354 sizeof(xmlNodePtr));
1355 if (cur->nodeTab == NULL) {
1356 xmlGenericError(xmlGenericErrorContext,
1357 "xmlXPathNodeSetAddUnique: out of memory\n");
1358 return;
1359 }
1360 memset(cur->nodeTab, 0 ,
1361 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1362 cur->nodeMax = XML_NODESET_DEFAULT;
1363 } else if (cur->nodeNr == cur->nodeMax) {
1364 xmlNodePtr *temp;
1365
1366 cur->nodeMax *= 2;
1367 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1368 sizeof(xmlNodePtr));
1369 if (temp == NULL) {
1370 xmlGenericError(xmlGenericErrorContext,
1371 "xmlXPathNodeSetAddUnique: out of memory\n");
1372 return;
1373 }
1374 cur->nodeTab = temp;
1375 }
1376 cur->nodeTab[cur->nodeNr++] = val;
1377}
1378
1379/**
1380 * xmlXPathNodeSetMerge:
1381 * @val1: the first NodeSet or NULL
1382 * @val2: the second NodeSet
1383 *
1384 * Merges two nodesets, all nodes from @val2 are added to @val1
1385 * if @val1 is NULL, a new set is created and copied from @val2
1386 *
1387 * Returns val1 once extended or NULL in case of error.
1388 */
1389xmlNodeSetPtr
1390xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001391 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001392
1393 if (val2 == NULL) return(val1);
1394 if (val1 == NULL) {
1395 val1 = xmlXPathNodeSetCreate(NULL);
1396 }
1397
1398 initNr = val1->nodeNr;
1399
1400 for (i = 0;i < val2->nodeNr;i++) {
1401 /*
1402 * check against doublons
1403 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001404 skip = 0;
1405 for (j = 0; j < initNr; j++) {
1406 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1407 skip = 1;
1408 break;
1409 }
1410 }
1411 if (skip)
1412 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001413
1414 /*
1415 * grow the nodeTab if needed
1416 */
1417 if (val1->nodeMax == 0) {
1418 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1419 sizeof(xmlNodePtr));
1420 if (val1->nodeTab == NULL) {
1421 xmlGenericError(xmlGenericErrorContext,
1422 "xmlXPathNodeSetMerge: out of memory\n");
1423 return(NULL);
1424 }
1425 memset(val1->nodeTab, 0 ,
1426 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1427 val1->nodeMax = XML_NODESET_DEFAULT;
1428 } else if (val1->nodeNr == val1->nodeMax) {
1429 xmlNodePtr *temp;
1430
1431 val1->nodeMax *= 2;
1432 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1433 sizeof(xmlNodePtr));
1434 if (temp == NULL) {
1435 xmlGenericError(xmlGenericErrorContext,
1436 "xmlXPathNodeSetMerge: out of memory\n");
1437 return(NULL);
1438 }
1439 val1->nodeTab = temp;
1440 }
1441 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1442 }
1443
1444 return(val1);
1445}
1446
1447/**
1448 * xmlXPathNodeSetDel:
1449 * @cur: the initial node set
1450 * @val: an xmlNodePtr
1451 *
1452 * Removes an xmlNodePtr from an existing NodeSet
1453 */
1454void
1455xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1456 int i;
1457
1458 if (cur == NULL) return;
1459 if (val == NULL) return;
1460
1461 /*
1462 * check against doublons
1463 */
1464 for (i = 0;i < cur->nodeNr;i++)
1465 if (cur->nodeTab[i] == val) break;
1466
1467 if (i >= cur->nodeNr) {
1468#ifdef DEBUG
1469 xmlGenericError(xmlGenericErrorContext,
1470 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1471 val->name);
1472#endif
1473 return;
1474 }
1475 cur->nodeNr--;
1476 for (;i < cur->nodeNr;i++)
1477 cur->nodeTab[i] = cur->nodeTab[i + 1];
1478 cur->nodeTab[cur->nodeNr] = NULL;
1479}
1480
1481/**
1482 * xmlXPathNodeSetRemove:
1483 * @cur: the initial node set
1484 * @val: the index to remove
1485 *
1486 * Removes an entry from an existing NodeSet list.
1487 */
1488void
1489xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1490 if (cur == NULL) return;
1491 if (val >= cur->nodeNr) return;
1492 cur->nodeNr--;
1493 for (;val < cur->nodeNr;val++)
1494 cur->nodeTab[val] = cur->nodeTab[val + 1];
1495 cur->nodeTab[cur->nodeNr] = NULL;
1496}
1497
1498/**
1499 * xmlXPathFreeNodeSet:
1500 * @obj: the xmlNodeSetPtr to free
1501 *
1502 * Free the NodeSet compound (not the actual nodes !).
1503 */
1504void
1505xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1506 if (obj == NULL) return;
1507 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001508 xmlFree(obj->nodeTab);
1509 }
Owen Taylor3473f882001-02-23 17:55:21 +00001510 xmlFree(obj);
1511}
1512
1513/**
1514 * xmlXPathFreeValueTree:
1515 * @obj: the xmlNodeSetPtr to free
1516 *
1517 * Free the NodeSet compound and the actual tree, this is different
1518 * from xmlXPathFreeNodeSet()
1519 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001520static void
Owen Taylor3473f882001-02-23 17:55:21 +00001521xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1522 int i;
1523
1524 if (obj == NULL) return;
1525 for (i = 0;i < obj->nodeNr;i++)
1526 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001527 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001528
1529 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001530 xmlFree(obj->nodeTab);
1531 }
Owen Taylor3473f882001-02-23 17:55:21 +00001532 xmlFree(obj);
1533}
1534
1535#if defined(DEBUG) || defined(DEBUG_STEP)
1536/**
1537 * xmlGenericErrorContextNodeSet:
1538 * @output: a FILE * for the output
1539 * @obj: the xmlNodeSetPtr to free
1540 *
1541 * Quick display of a NodeSet
1542 */
1543void
1544xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1545 int i;
1546
1547 if (output == NULL) output = xmlGenericErrorContext;
1548 if (obj == NULL) {
1549 fprintf(output, "NodeSet == NULL !\n");
1550 return;
1551 }
1552 if (obj->nodeNr == 0) {
1553 fprintf(output, "NodeSet is empty\n");
1554 return;
1555 }
1556 if (obj->nodeTab == NULL) {
1557 fprintf(output, " nodeTab == NULL !\n");
1558 return;
1559 }
1560 for (i = 0; i < obj->nodeNr; i++) {
1561 if (obj->nodeTab[i] == NULL) {
1562 fprintf(output, " NULL !\n");
1563 return;
1564 }
1565 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1566 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1567 fprintf(output, " /");
1568 else if (obj->nodeTab[i]->name == NULL)
1569 fprintf(output, " noname!");
1570 else fprintf(output, " %s", obj->nodeTab[i]->name);
1571 }
1572 fprintf(output, "\n");
1573}
1574#endif
1575
1576/**
1577 * xmlXPathNewNodeSet:
1578 * @val: the NodePtr value
1579 *
1580 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1581 * it with the single Node @val
1582 *
1583 * Returns the newly created object.
1584 */
1585xmlXPathObjectPtr
1586xmlXPathNewNodeSet(xmlNodePtr val) {
1587 xmlXPathObjectPtr ret;
1588
1589 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1590 if (ret == NULL) {
1591 xmlGenericError(xmlGenericErrorContext,
1592 "xmlXPathNewNodeSet: out of memory\n");
1593 return(NULL);
1594 }
1595 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1596 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001597 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001598 ret->nodesetval = xmlXPathNodeSetCreate(val);
1599 return(ret);
1600}
1601
1602/**
1603 * xmlXPathNewValueTree:
1604 * @val: the NodePtr value
1605 *
1606 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1607 * it with the tree root @val
1608 *
1609 * Returns the newly created object.
1610 */
1611xmlXPathObjectPtr
1612xmlXPathNewValueTree(xmlNodePtr val) {
1613 xmlXPathObjectPtr ret;
1614
1615 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1616 if (ret == NULL) {
1617 xmlGenericError(xmlGenericErrorContext,
1618 "xmlXPathNewNodeSet: out of memory\n");
1619 return(NULL);
1620 }
1621 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1622 ret->type = XPATH_XSLT_TREE;
1623 ret->nodesetval = xmlXPathNodeSetCreate(val);
1624 return(ret);
1625}
1626
1627/**
1628 * xmlXPathNewNodeSetList:
1629 * @val: an existing NodeSet
1630 *
1631 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1632 * it with the Nodeset @val
1633 *
1634 * Returns the newly created object.
1635 */
1636xmlXPathObjectPtr
1637xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1638 xmlXPathObjectPtr ret;
1639 int i;
1640
1641 if (val == NULL)
1642 ret = NULL;
1643 else if (val->nodeTab == NULL)
1644 ret = xmlXPathNewNodeSet(NULL);
1645 else
1646 {
1647 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1648 for (i = 1; i < val->nodeNr; ++i)
1649 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1650 }
1651
1652 return(ret);
1653}
1654
1655/**
1656 * xmlXPathWrapNodeSet:
1657 * @val: the NodePtr value
1658 *
1659 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1660 *
1661 * Returns the newly created object.
1662 */
1663xmlXPathObjectPtr
1664xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1665 xmlXPathObjectPtr ret;
1666
1667 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1668 if (ret == NULL) {
1669 xmlGenericError(xmlGenericErrorContext,
1670 "xmlXPathWrapNodeSet: out of memory\n");
1671 return(NULL);
1672 }
1673 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1674 ret->type = XPATH_NODESET;
1675 ret->nodesetval = val;
1676 return(ret);
1677}
1678
1679/**
1680 * xmlXPathFreeNodeSetList:
1681 * @obj: an existing NodeSetList object
1682 *
1683 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1684 * the list contrary to xmlXPathFreeObject().
1685 */
1686void
1687xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1688 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001689 xmlFree(obj);
1690}
1691
1692/************************************************************************
1693 * *
1694 * Routines to handle extra functions *
1695 * *
1696 ************************************************************************/
1697
1698/**
1699 * xmlXPathRegisterFunc:
1700 * @ctxt: the XPath context
1701 * @name: the function name
1702 * @f: the function implementation or NULL
1703 *
1704 * Register a new function. If @f is NULL it unregisters the function
1705 *
1706 * Returns 0 in case of success, -1 in case of error
1707 */
1708int
1709xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1710 xmlXPathFunction f) {
1711 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1712}
1713
1714/**
1715 * xmlXPathRegisterFuncNS:
1716 * @ctxt: the XPath context
1717 * @name: the function name
1718 * @ns_uri: the function namespace URI
1719 * @f: the function implementation or NULL
1720 *
1721 * Register a new function. If @f is NULL it unregisters the function
1722 *
1723 * Returns 0 in case of success, -1 in case of error
1724 */
1725int
1726xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1727 const xmlChar *ns_uri, xmlXPathFunction f) {
1728 if (ctxt == NULL)
1729 return(-1);
1730 if (name == NULL)
1731 return(-1);
1732
1733 if (ctxt->funcHash == NULL)
1734 ctxt->funcHash = xmlHashCreate(0);
1735 if (ctxt->funcHash == NULL)
1736 return(-1);
1737 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1738}
1739
1740/**
1741 * xmlXPathFunctionLookup:
1742 * @ctxt: the XPath context
1743 * @name: the function name
1744 *
1745 * Search in the Function array of the context for the given
1746 * function.
1747 *
1748 * Returns the xmlXPathFunction or NULL if not found
1749 */
1750xmlXPathFunction
1751xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1752 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1753}
1754
1755/**
1756 * xmlXPathFunctionLookupNS:
1757 * @ctxt: the XPath context
1758 * @name: the function name
1759 * @ns_uri: the function namespace URI
1760 *
1761 * Search in the Function array of the context for the given
1762 * function.
1763 *
1764 * Returns the xmlXPathFunction or NULL if not found
1765 */
1766xmlXPathFunction
1767xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1768 const xmlChar *ns_uri) {
1769 if (ctxt == NULL)
1770 return(NULL);
1771 if (ctxt->funcHash == NULL)
1772 return(NULL);
1773 if (name == NULL)
1774 return(NULL);
1775
1776 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1777}
1778
1779/**
1780 * xmlXPathRegisteredFuncsCleanup:
1781 * @ctxt: the XPath context
1782 *
1783 * Cleanup the XPath context data associated to registered functions
1784 */
1785void
1786xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1787 if (ctxt == NULL)
1788 return;
1789
1790 xmlHashFree(ctxt->funcHash, NULL);
1791 ctxt->funcHash = NULL;
1792}
1793
1794/************************************************************************
1795 * *
1796 * Routines to handle Variable *
1797 * *
1798 ************************************************************************/
1799
1800/**
1801 * xmlXPathRegisterVariable:
1802 * @ctxt: the XPath context
1803 * @name: the variable name
1804 * @value: the variable value or NULL
1805 *
1806 * Register a new variable value. If @value is NULL it unregisters
1807 * the variable
1808 *
1809 * Returns 0 in case of success, -1 in case of error
1810 */
1811int
1812xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1813 xmlXPathObjectPtr value) {
1814 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1815}
1816
1817/**
1818 * xmlXPathRegisterVariableNS:
1819 * @ctxt: the XPath context
1820 * @name: the variable name
1821 * @ns_uri: the variable namespace URI
1822 * @value: the variable value or NULL
1823 *
1824 * Register a new variable value. If @value is NULL it unregisters
1825 * the variable
1826 *
1827 * Returns 0 in case of success, -1 in case of error
1828 */
1829int
1830xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1831 const xmlChar *ns_uri,
1832 xmlXPathObjectPtr value) {
1833 if (ctxt == NULL)
1834 return(-1);
1835 if (name == NULL)
1836 return(-1);
1837
1838 if (ctxt->varHash == NULL)
1839 ctxt->varHash = xmlHashCreate(0);
1840 if (ctxt->varHash == NULL)
1841 return(-1);
1842 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1843 (void *) value,
1844 (xmlHashDeallocator)xmlXPathFreeObject));
1845}
1846
1847/**
1848 * xmlXPathRegisterVariableLookup:
1849 * @ctxt: the XPath context
1850 * @f: the lookup function
1851 * @data: the lookup data
1852 *
1853 * register an external mechanism to do variable lookup
1854 */
1855void
1856xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1857 xmlXPathVariableLookupFunc f, void *data) {
1858 if (ctxt == NULL)
1859 return;
1860 ctxt->varLookupFunc = (void *) f;
1861 ctxt->varLookupData = data;
1862}
1863
1864/**
1865 * xmlXPathVariableLookup:
1866 * @ctxt: the XPath context
1867 * @name: the variable name
1868 *
1869 * Search in the Variable array of the context for the given
1870 * variable value.
1871 *
1872 * Returns the value or NULL if not found
1873 */
1874xmlXPathObjectPtr
1875xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1876 if (ctxt == NULL)
1877 return(NULL);
1878
1879 if (ctxt->varLookupFunc != NULL) {
1880 xmlXPathObjectPtr ret;
1881
1882 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1883 (ctxt->varLookupData, name, NULL);
1884 if (ret != NULL) return(ret);
1885 }
1886 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1887}
1888
1889/**
1890 * xmlXPathVariableLookupNS:
1891 * @ctxt: the XPath context
1892 * @name: the variable name
1893 * @ns_uri: the variable namespace URI
1894 *
1895 * Search in the Variable array of the context for the given
1896 * variable value.
1897 *
1898 * Returns the value or NULL if not found
1899 */
1900xmlXPathObjectPtr
1901xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1902 const xmlChar *ns_uri) {
1903 if (ctxt == NULL)
1904 return(NULL);
1905
1906 if (ctxt->varLookupFunc != NULL) {
1907 xmlXPathObjectPtr ret;
1908
1909 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1910 (ctxt->varLookupData, name, ns_uri);
1911 if (ret != NULL) return(ret);
1912 }
1913
1914 if (ctxt->varHash == NULL)
1915 return(NULL);
1916 if (name == NULL)
1917 return(NULL);
1918
1919 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1920}
1921
1922/**
1923 * xmlXPathRegisteredVariablesCleanup:
1924 * @ctxt: the XPath context
1925 *
1926 * Cleanup the XPath context data associated to registered variables
1927 */
1928void
1929xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1930 if (ctxt == NULL)
1931 return;
1932
Daniel Veillard76d66f42001-05-16 21:05:17 +00001933 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00001934 ctxt->varHash = NULL;
1935}
1936
1937/**
1938 * xmlXPathRegisterNs:
1939 * @ctxt: the XPath context
1940 * @prefix: the namespace prefix
1941 * @ns_uri: the namespace name
1942 *
1943 * Register a new namespace. If @ns_uri is NULL it unregisters
1944 * the namespace
1945 *
1946 * Returns 0 in case of success, -1 in case of error
1947 */
1948int
1949xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1950 const xmlChar *ns_uri) {
1951 if (ctxt == NULL)
1952 return(-1);
1953 if (prefix == NULL)
1954 return(-1);
1955
1956 if (ctxt->nsHash == NULL)
1957 ctxt->nsHash = xmlHashCreate(10);
1958 if (ctxt->nsHash == NULL)
1959 return(-1);
1960 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1961 (xmlHashDeallocator)xmlFree));
1962}
1963
1964/**
1965 * xmlXPathNsLookup:
1966 * @ctxt: the XPath context
1967 * @prefix: the namespace prefix value
1968 *
1969 * Search in the namespace declaration array of the context for the given
1970 * namespace name associated to the given prefix
1971 *
1972 * Returns the value or NULL if not found
1973 */
1974const xmlChar *
1975xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1976 if (ctxt == NULL)
1977 return(NULL);
1978 if (prefix == NULL)
1979 return(NULL);
1980
1981#ifdef XML_XML_NAMESPACE
1982 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1983 return(XML_XML_NAMESPACE);
1984#endif
1985
Daniel Veillardc8f620b2001-04-30 20:31:33 +00001986 if (ctxt->namespaces != NULL) {
1987 int i;
1988
1989 for (i = 0;i < ctxt->nsNr;i++) {
1990 if ((ctxt->namespaces[i] != NULL) &&
1991 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
1992 return(ctxt->namespaces[i]->href);
1993 }
1994 }
Owen Taylor3473f882001-02-23 17:55:21 +00001995
1996 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1997}
1998
1999/**
2000 * xmlXPathRegisteredVariablesCleanup:
2001 * @ctxt: the XPath context
2002 *
2003 * Cleanup the XPath context data associated to registered variables
2004 */
2005void
2006xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2007 if (ctxt == NULL)
2008 return;
2009
2010 xmlHashFree(ctxt->nsHash, NULL);
2011 ctxt->nsHash = NULL;
2012}
2013
2014/************************************************************************
2015 * *
2016 * Routines to handle Values *
2017 * *
2018 ************************************************************************/
2019
2020/* Allocations are terrible, one need to optimize all this !!! */
2021
2022/**
2023 * xmlXPathNewFloat:
2024 * @val: the double value
2025 *
2026 * Create a new xmlXPathObjectPtr of type double and of value @val
2027 *
2028 * Returns the newly created object.
2029 */
2030xmlXPathObjectPtr
2031xmlXPathNewFloat(double val) {
2032 xmlXPathObjectPtr ret;
2033
2034 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2035 if (ret == NULL) {
2036 xmlGenericError(xmlGenericErrorContext,
2037 "xmlXPathNewFloat: out of memory\n");
2038 return(NULL);
2039 }
2040 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2041 ret->type = XPATH_NUMBER;
2042 ret->floatval = val;
2043 return(ret);
2044}
2045
2046/**
2047 * xmlXPathNewBoolean:
2048 * @val: the boolean value
2049 *
2050 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2051 *
2052 * Returns the newly created object.
2053 */
2054xmlXPathObjectPtr
2055xmlXPathNewBoolean(int val) {
2056 xmlXPathObjectPtr ret;
2057
2058 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2059 if (ret == NULL) {
2060 xmlGenericError(xmlGenericErrorContext,
2061 "xmlXPathNewBoolean: out of memory\n");
2062 return(NULL);
2063 }
2064 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2065 ret->type = XPATH_BOOLEAN;
2066 ret->boolval = (val != 0);
2067 return(ret);
2068}
2069
2070/**
2071 * xmlXPathNewString:
2072 * @val: the xmlChar * value
2073 *
2074 * Create a new xmlXPathObjectPtr of type string and of value @val
2075 *
2076 * Returns the newly created object.
2077 */
2078xmlXPathObjectPtr
2079xmlXPathNewString(const xmlChar *val) {
2080 xmlXPathObjectPtr ret;
2081
2082 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2083 if (ret == NULL) {
2084 xmlGenericError(xmlGenericErrorContext,
2085 "xmlXPathNewString: out of memory\n");
2086 return(NULL);
2087 }
2088 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2089 ret->type = XPATH_STRING;
2090 if (val != NULL)
2091 ret->stringval = xmlStrdup(val);
2092 else
2093 ret->stringval = xmlStrdup((const xmlChar *)"");
2094 return(ret);
2095}
2096
2097/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002098 * xmlXPathWrapString:
2099 * @val: the xmlChar * value
2100 *
2101 * Wraps the @val string into an XPath object.
2102 *
2103 * Returns the newly created object.
2104 */
2105xmlXPathObjectPtr
2106xmlXPathWrapString (xmlChar *val) {
2107 xmlXPathObjectPtr ret;
2108
2109 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2110 if (ret == NULL) {
2111 xmlGenericError(xmlGenericErrorContext,
2112 "xmlXPathWrapString: out of memory\n");
2113 return(NULL);
2114 }
2115 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2116 ret->type = XPATH_STRING;
2117 ret->stringval = val;
2118 return(ret);
2119}
2120
2121/**
Owen Taylor3473f882001-02-23 17:55:21 +00002122 * xmlXPathNewCString:
2123 * @val: the char * value
2124 *
2125 * Create a new xmlXPathObjectPtr of type string and of value @val
2126 *
2127 * Returns the newly created object.
2128 */
2129xmlXPathObjectPtr
2130xmlXPathNewCString(const char *val) {
2131 xmlXPathObjectPtr ret;
2132
2133 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2134 if (ret == NULL) {
2135 xmlGenericError(xmlGenericErrorContext,
2136 "xmlXPathNewCString: out of memory\n");
2137 return(NULL);
2138 }
2139 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2140 ret->type = XPATH_STRING;
2141 ret->stringval = xmlStrdup(BAD_CAST val);
2142 return(ret);
2143}
2144
2145/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002146 * xmlXPathWrapCString:
2147 * @val: the char * value
2148 *
2149 * Wraps a string into an XPath object.
2150 *
2151 * Returns the newly created object.
2152 */
2153xmlXPathObjectPtr
2154xmlXPathWrapCString (char * val) {
2155 return(xmlXPathWrapString((xmlChar *)(val)));
2156}
2157
2158/**
Owen Taylor3473f882001-02-23 17:55:21 +00002159 * xmlXPathObjectCopy:
2160 * @val: the original object
2161 *
2162 * allocate a new copy of a given object
2163 *
2164 * Returns the newly created object.
2165 */
2166xmlXPathObjectPtr
2167xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2168 xmlXPathObjectPtr ret;
2169
2170 if (val == NULL)
2171 return(NULL);
2172
2173 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2174 if (ret == NULL) {
2175 xmlGenericError(xmlGenericErrorContext,
2176 "xmlXPathObjectCopy: out of memory\n");
2177 return(NULL);
2178 }
2179 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2180 switch (val->type) {
2181 case XPATH_BOOLEAN:
2182 case XPATH_NUMBER:
2183 case XPATH_POINT:
2184 case XPATH_RANGE:
2185 break;
2186 case XPATH_STRING:
2187 ret->stringval = xmlStrdup(val->stringval);
2188 break;
2189 case XPATH_XSLT_TREE:
2190 if ((val->nodesetval != NULL) &&
2191 (val->nodesetval->nodeTab != NULL))
2192 ret->nodesetval = xmlXPathNodeSetCreate(
2193 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2194 else
2195 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2196 break;
2197 case XPATH_NODESET:
2198 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2199 break;
2200 case XPATH_LOCATIONSET:
2201#ifdef LIBXML_XPTR_ENABLED
2202 {
2203 xmlLocationSetPtr loc = val->user;
2204 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2205 break;
2206 }
2207#endif
2208 case XPATH_UNDEFINED:
2209 case XPATH_USERS:
2210 xmlGenericError(xmlGenericErrorContext,
2211 "xmlXPathObjectCopy: unsupported type %d\n",
2212 val->type);
2213 break;
2214 }
2215 return(ret);
2216}
2217
2218/**
2219 * xmlXPathFreeObject:
2220 * @obj: the object to free
2221 *
2222 * Free up an xmlXPathObjectPtr object.
2223 */
2224void
2225xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2226 if (obj == NULL) return;
2227 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002228 if (obj->boolval) {
2229 obj->type = XPATH_XSLT_TREE;
2230 if (obj->nodesetval != NULL)
2231 xmlXPathFreeValueTree(obj->nodesetval);
2232 } else {
2233 if (obj->nodesetval != NULL)
2234 xmlXPathFreeNodeSet(obj->nodesetval);
2235 }
Owen Taylor3473f882001-02-23 17:55:21 +00002236#ifdef LIBXML_XPTR_ENABLED
2237 } else if (obj->type == XPATH_LOCATIONSET) {
2238 if (obj->user != NULL)
2239 xmlXPtrFreeLocationSet(obj->user);
2240#endif
2241 } else if (obj->type == XPATH_STRING) {
2242 if (obj->stringval != NULL)
2243 xmlFree(obj->stringval);
2244 } else if (obj->type == XPATH_XSLT_TREE) {
2245 if (obj->nodesetval != NULL)
2246 xmlXPathFreeValueTree(obj->nodesetval);
2247 }
2248
Owen Taylor3473f882001-02-23 17:55:21 +00002249 xmlFree(obj);
2250}
2251
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002252
2253/************************************************************************
2254 * *
2255 * Type Casting Routines *
2256 * *
2257 ************************************************************************/
2258
2259/**
2260 * xmlXPathCastBooleanToString:
2261 * @val: a boolean
2262 *
2263 * Converts a boolean to its string value.
2264 *
2265 * Returns a newly allocated string.
2266 */
2267xmlChar *
2268xmlXPathCastBooleanToString (int val) {
2269 xmlChar *ret;
2270 if (val)
2271 ret = xmlStrdup((const xmlChar *) "true");
2272 else
2273 ret = xmlStrdup((const xmlChar *) "false");
2274 return(ret);
2275}
2276
2277/**
2278 * xmlXPathCastNumberToString:
2279 * @val: a number
2280 *
2281 * Converts a number to its string value.
2282 *
2283 * Returns a newly allocated string.
2284 */
2285xmlChar *
2286xmlXPathCastNumberToString (double val) {
2287 xmlChar *ret;
2288 switch (isinf(val)) {
2289 case 1:
2290 ret = xmlStrdup((const xmlChar *) "+Infinity");
2291 break;
2292 case -1:
2293 ret = xmlStrdup((const xmlChar *) "-Infinity");
2294 break;
2295 default:
2296 if (isnan(val)) {
2297 ret = xmlStrdup((const xmlChar *) "NaN");
2298 } else {
2299 /* could be improved */
2300 char buf[100];
2301 xmlXPathFormatNumber(val, buf, 100);
2302 ret = xmlStrdup((const xmlChar *) buf);
2303 }
2304 }
2305 return(ret);
2306}
2307
2308/**
2309 * xmlXPathCastNodeToString:
2310 * @node: a node
2311 *
2312 * Converts a node to its string value.
2313 *
2314 * Returns a newly allocated string.
2315 */
2316xmlChar *
2317xmlXPathCastNodeToString (xmlNodePtr node) {
2318 return(xmlNodeGetContent(node));
2319}
2320
2321/**
2322 * xmlXPathCastNodeSetToString:
2323 * @ns: a node-set
2324 *
2325 * Converts a node-set to its string value.
2326 *
2327 * Returns a newly allocated string.
2328 */
2329xmlChar *
2330xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2331 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2332 return(xmlStrdup((const xmlChar *) ""));
2333
2334 xmlXPathNodeSetSort(ns);
2335 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2336}
2337
2338/**
2339 * xmlXPathCastToString:
2340 * @val: an XPath object
2341 *
2342 * Converts an existing object to its string() equivalent
2343 *
2344 * Returns the string value of the object, NULL in case of error.
2345 * A new string is allocated only if needed (val isn't a
2346 * string object).
2347 */
2348xmlChar *
2349xmlXPathCastToString(xmlXPathObjectPtr val) {
2350 xmlChar *ret = NULL;
2351
2352 if (val == NULL)
2353 return(xmlStrdup((const xmlChar *) ""));
2354 switch (val->type) {
2355 case XPATH_UNDEFINED:
2356#ifdef DEBUG_EXPR
2357 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2358#endif
2359 ret = xmlStrdup((const xmlChar *) "");
2360 break;
2361 case XPATH_XSLT_TREE:
2362 case XPATH_NODESET:
2363 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2364 break;
2365 case XPATH_STRING:
2366 return(val->stringval);
2367 case XPATH_BOOLEAN:
2368 ret = xmlXPathCastBooleanToString(val->boolval);
2369 break;
2370 case XPATH_NUMBER: {
2371 ret = xmlXPathCastNumberToString(val->floatval);
2372 break;
2373 }
2374 case XPATH_USERS:
2375 case XPATH_POINT:
2376 case XPATH_RANGE:
2377 case XPATH_LOCATIONSET:
2378 TODO
2379 ret = xmlStrdup((const xmlChar *) "");
2380 break;
2381 }
2382 return(ret);
2383}
2384
2385/**
2386 * xmlXPathConvertString:
2387 * @val: an XPath object
2388 *
2389 * Converts an existing object to its string() equivalent
2390 *
2391 * Returns the new object, the old one is freed (or the operation
2392 * is done directly on @val)
2393 */
2394xmlXPathObjectPtr
2395xmlXPathConvertString(xmlXPathObjectPtr val) {
2396 xmlChar *res = NULL;
2397
2398 if (val == NULL)
2399 return(xmlXPathNewCString(""));
2400
2401 switch (val->type) {
2402 case XPATH_UNDEFINED:
2403#ifdef DEBUG_EXPR
2404 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2405#endif
2406 break;
2407 case XPATH_XSLT_TREE:
2408 case XPATH_NODESET:
2409 res = xmlXPathCastNodeSetToString(val->nodesetval);
2410 break;
2411 case XPATH_STRING:
2412 return(val);
2413 case XPATH_BOOLEAN:
2414 res = xmlXPathCastBooleanToString(val->boolval);
2415 break;
2416 case XPATH_NUMBER:
2417 res = xmlXPathCastNumberToString(val->floatval);
2418 break;
2419 case XPATH_USERS:
2420 case XPATH_POINT:
2421 case XPATH_RANGE:
2422 case XPATH_LOCATIONSET:
2423 TODO;
2424 break;
2425 }
2426 xmlXPathFreeObject(val);
2427 if (res == NULL)
2428 return(xmlXPathNewCString(""));
2429 return(xmlXPathWrapString(res));
2430}
2431
2432/**
2433 * xmlXPathCastBooleanToNumber:
2434 * @val: a boolean
2435 *
2436 * Converts a boolean to its number value
2437 *
2438 * Returns the number value
2439 */
2440double
2441xmlXPathCastBooleanToNumber(int val) {
2442 if (val)
2443 return(1.0);
2444 return(0.0);
2445}
2446
2447/**
2448 * xmlXPathCastStringToNumber:
2449 * @val: a string
2450 *
2451 * Converts a string to its number value
2452 *
2453 * Returns the number value
2454 */
2455double
2456xmlXPathCastStringToNumber(const xmlChar * val) {
2457 return(xmlXPathStringEvalNumber(val));
2458}
2459
2460/**
2461 * xmlXPathCastNodeToNumber:
2462 * @node: a node
2463 *
2464 * Converts a node to its number value
2465 *
2466 * Returns the number value
2467 */
2468double
2469xmlXPathCastNodeToNumber (xmlNodePtr node) {
2470 xmlChar *strval;
2471 double ret;
2472
2473 if (node == NULL)
2474 return(xmlXPathNAN);
2475 strval = xmlXPathCastNodeToString(node);
2476 if (strval == NULL)
2477 return(xmlXPathNAN);
2478 ret = xmlXPathCastStringToNumber(strval);
2479 xmlFree(strval);
2480
2481 return(ret);
2482}
2483
2484/**
2485 * xmlXPathCastNodeSetToNumber:
2486 * @ns: a node-set
2487 *
2488 * Converts a node-set to its number value
2489 *
2490 * Returns the number value
2491 */
2492double
2493xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
2494 xmlChar *str;
2495 double ret;
2496
2497 if (ns == NULL)
2498 return(xmlXPathNAN);
2499 str = xmlXPathCastNodeSetToString(ns);
2500 ret = xmlXPathCastStringToNumber(str);
2501 xmlFree(str);
2502 return(ret);
2503}
2504
2505/**
2506 * xmlXPathCastToNumber:
2507 * @val: an XPath object
2508 *
2509 * Converts an XPath object to its number value
2510 *
2511 * Returns the number value
2512 */
2513double
2514xmlXPathCastToNumber(xmlXPathObjectPtr val) {
2515 double ret = 0.0;
2516
2517 if (val == NULL)
2518 return(xmlXPathNAN);
2519 switch (val->type) {
2520 case XPATH_UNDEFINED:
2521#ifdef DEGUB_EXPR
2522 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
2523#endif
2524 ret = xmlXPathNAN;
2525 break;
2526 case XPATH_XSLT_TREE:
2527 case XPATH_NODESET:
2528 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
2529 break;
2530 case XPATH_STRING:
2531 ret = xmlXPathCastStringToNumber(val->stringval);
2532 break;
2533 case XPATH_NUMBER:
2534 ret = val->floatval;
2535 break;
2536 case XPATH_BOOLEAN:
2537 ret = xmlXPathCastBooleanToNumber(val->boolval);
2538 break;
2539 case XPATH_USERS:
2540 case XPATH_POINT:
2541 case XPATH_RANGE:
2542 case XPATH_LOCATIONSET:
2543 TODO;
2544 ret = xmlXPathNAN;
2545 break;
2546 }
2547 return(ret);
2548}
2549
2550/**
2551 * xmlXPathConvertNumber:
2552 * @val: an XPath object
2553 *
2554 * Converts an existing object to its number() equivalent
2555 *
2556 * Returns the new object, the old one is freed (or the operation
2557 * is done directly on @val)
2558 */
2559xmlXPathObjectPtr
2560xmlXPathConvertNumber(xmlXPathObjectPtr val) {
2561 xmlXPathObjectPtr ret;
2562
2563 if (val == NULL)
2564 return(xmlXPathNewFloat(0.0));
2565 if (val->type == XPATH_NUMBER)
2566 return(val);
2567 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
2568 xmlXPathFreeObject(val);
2569 return(ret);
2570}
2571
2572/**
2573 * xmlXPathCastNumberToBoolean:
2574 * @val: a number
2575 *
2576 * Converts a number to its boolean value
2577 *
2578 * Returns the boolean value
2579 */
2580int
2581xmlXPathCastNumberToBoolean (double val) {
2582 if (isnan(val) || (val == 0.0))
2583 return(0);
2584 return(1);
2585}
2586
2587/**
2588 * xmlXPathCastStringToBoolean:
2589 * @val: a string
2590 *
2591 * Converts a string to its boolean value
2592 *
2593 * Returns the boolean value
2594 */
2595int
2596xmlXPathCastStringToBoolean (const xmlChar *val) {
2597 if ((val == NULL) || (xmlStrlen(val) == 0))
2598 return(0);
2599 return(1);
2600}
2601
2602/**
2603 * xmlXPathCastNodeSetToBoolean:
2604 * @ns: a node-set
2605 *
2606 * Converts a node-set to its boolean value
2607 *
2608 * Returns the boolean value
2609 */
2610int
2611xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
2612 if ((ns == NULL) || (ns->nodeNr == 0))
2613 return(0);
2614 return(1);
2615}
2616
2617/**
2618 * xmlXpathCastToBoolean:
2619 * @val: an XPath object
2620 *
2621 * Converts an XPath object to its boolean value
2622 *
2623 * Returns the boolean value
2624 */
2625int
2626xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
2627 int ret = 0;
2628
2629 if (val == NULL)
2630 return(0);
2631 switch (val->type) {
2632 case XPATH_UNDEFINED:
2633#ifdef DEBUG_EXPR
2634 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
2635#endif
2636 ret = 0;
2637 break;
2638 case XPATH_XSLT_TREE:
2639 case XPATH_NODESET:
2640 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
2641 break;
2642 case XPATH_STRING:
2643 ret = xmlXPathCastStringToBoolean(val->stringval);
2644 break;
2645 case XPATH_NUMBER:
2646 ret = xmlXPathCastNumberToBoolean(val->floatval);
2647 break;
2648 case XPATH_BOOLEAN:
2649 ret = val->boolval;
2650 break;
2651 case XPATH_USERS:
2652 case XPATH_POINT:
2653 case XPATH_RANGE:
2654 case XPATH_LOCATIONSET:
2655 TODO;
2656 ret = 0;
2657 break;
2658 }
2659 return(ret);
2660}
2661
2662
2663/**
2664 * xmlXPathConvertBoolean:
2665 * @val: an XPath object
2666 *
2667 * Converts an existing object to its boolean() equivalent
2668 *
2669 * Returns the new object, the old one is freed (or the operation
2670 * is done directly on @val)
2671 */
2672xmlXPathObjectPtr
2673xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
2674 xmlXPathObjectPtr ret;
2675
2676 if (val == NULL)
2677 return(xmlXPathNewBoolean(0));
2678 if (val->type == XPATH_BOOLEAN)
2679 return(val);
2680 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
2681 xmlXPathFreeObject(val);
2682 return(ret);
2683}
2684
Owen Taylor3473f882001-02-23 17:55:21 +00002685/************************************************************************
2686 * *
2687 * Routines to handle XPath contexts *
2688 * *
2689 ************************************************************************/
2690
2691/**
2692 * xmlXPathNewContext:
2693 * @doc: the XML document
2694 *
2695 * Create a new xmlXPathContext
2696 *
2697 * Returns the xmlXPathContext just allocated.
2698 */
2699xmlXPathContextPtr
2700xmlXPathNewContext(xmlDocPtr doc) {
2701 xmlXPathContextPtr ret;
2702
2703 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2704 if (ret == NULL) {
2705 xmlGenericError(xmlGenericErrorContext,
2706 "xmlXPathNewContext: out of memory\n");
2707 return(NULL);
2708 }
2709 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2710 ret->doc = doc;
2711 ret->node = NULL;
2712
2713 ret->varHash = NULL;
2714
2715 ret->nb_types = 0;
2716 ret->max_types = 0;
2717 ret->types = NULL;
2718
2719 ret->funcHash = xmlHashCreate(0);
2720
2721 ret->nb_axis = 0;
2722 ret->max_axis = 0;
2723 ret->axis = NULL;
2724
2725 ret->nsHash = NULL;
2726 ret->user = NULL;
2727
2728 ret->contextSize = -1;
2729 ret->proximityPosition = -1;
2730
2731 xmlXPathRegisterAllFunctions(ret);
2732
2733 return(ret);
2734}
2735
2736/**
2737 * xmlXPathFreeContext:
2738 * @ctxt: the context to free
2739 *
2740 * Free up an xmlXPathContext
2741 */
2742void
2743xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2744 xmlXPathRegisteredNsCleanup(ctxt);
2745 xmlXPathRegisteredFuncsCleanup(ctxt);
2746 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002747 xmlFree(ctxt);
2748}
2749
2750/************************************************************************
2751 * *
2752 * Routines to handle XPath parser contexts *
2753 * *
2754 ************************************************************************/
2755
2756#define CHECK_CTXT(ctxt) \
2757 if (ctxt == NULL) { \
2758 xmlGenericError(xmlGenericErrorContext, \
2759 "%s:%d Internal error: ctxt == NULL\n", \
2760 __FILE__, __LINE__); \
2761 } \
2762
2763
2764#define CHECK_CONTEXT(ctxt) \
2765 if (ctxt == NULL) { \
2766 xmlGenericError(xmlGenericErrorContext, \
2767 "%s:%d Internal error: no context\n", \
2768 __FILE__, __LINE__); \
2769 } \
2770 else if (ctxt->doc == NULL) { \
2771 xmlGenericError(xmlGenericErrorContext, \
2772 "%s:%d Internal error: no document\n", \
2773 __FILE__, __LINE__); \
2774 } \
2775 else if (ctxt->doc->children == NULL) { \
2776 xmlGenericError(xmlGenericErrorContext, \
2777 "%s:%d Internal error: document without root\n", \
2778 __FILE__, __LINE__); \
2779 } \
2780
2781
2782/**
2783 * xmlXPathNewParserContext:
2784 * @str: the XPath expression
2785 * @ctxt: the XPath context
2786 *
2787 * Create a new xmlXPathParserContext
2788 *
2789 * Returns the xmlXPathParserContext just allocated.
2790 */
2791xmlXPathParserContextPtr
2792xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2793 xmlXPathParserContextPtr ret;
2794
2795 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2796 if (ret == NULL) {
2797 xmlGenericError(xmlGenericErrorContext,
2798 "xmlXPathNewParserContext: out of memory\n");
2799 return(NULL);
2800 }
2801 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2802 ret->cur = ret->base = str;
2803 ret->context = ctxt;
2804
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002805 ret->comp = xmlXPathNewCompExpr();
2806 if (ret->comp == NULL) {
2807 xmlFree(ret->valueTab);
2808 xmlFree(ret);
2809 return(NULL);
2810 }
2811
2812 return(ret);
2813}
2814
2815/**
2816 * xmlXPathCompParserContext:
2817 * @comp: the XPath compiled expression
2818 * @ctxt: the XPath context
2819 *
2820 * Create a new xmlXPathParserContext when processing a compiled expression
2821 *
2822 * Returns the xmlXPathParserContext just allocated.
2823 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002824static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002825xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2826 xmlXPathParserContextPtr ret;
2827
2828 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2829 if (ret == NULL) {
2830 xmlGenericError(xmlGenericErrorContext,
2831 "xmlXPathNewParserContext: out of memory\n");
2832 return(NULL);
2833 }
2834 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2835
Owen Taylor3473f882001-02-23 17:55:21 +00002836 /* Allocate the value stack */
2837 ret->valueTab = (xmlXPathObjectPtr *)
2838 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002839 if (ret->valueTab == NULL) {
2840 xmlFree(ret);
2841 xmlGenericError(xmlGenericErrorContext,
2842 "xmlXPathNewParserContext: out of memory\n");
2843 return(NULL);
2844 }
Owen Taylor3473f882001-02-23 17:55:21 +00002845 ret->valueNr = 0;
2846 ret->valueMax = 10;
2847 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002848
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002849 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002850 ret->comp = comp;
2851
Owen Taylor3473f882001-02-23 17:55:21 +00002852 return(ret);
2853}
2854
2855/**
2856 * xmlXPathFreeParserContext:
2857 * @ctxt: the context to free
2858 *
2859 * Free up an xmlXPathParserContext
2860 */
2861void
2862xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2863 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002864 xmlFree(ctxt->valueTab);
2865 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002866 if (ctxt->comp)
2867 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002868 xmlFree(ctxt);
2869}
2870
2871/************************************************************************
2872 * *
2873 * The implicit core function library *
2874 * *
2875 ************************************************************************/
2876
Owen Taylor3473f882001-02-23 17:55:21 +00002877/**
2878 * xmlXPathCompareNodeSetFloat:
2879 * @ctxt: the XPath Parser context
2880 * @inf: less than (1) or greater than (0)
2881 * @strict: is the comparison strict
2882 * @arg: the node set
2883 * @f: the value
2884 *
2885 * Implement the compare operation between a nodeset and a number
2886 * @ns < @val (1, 1, ...
2887 * @ns <= @val (1, 0, ...
2888 * @ns > @val (0, 1, ...
2889 * @ns >= @val (0, 0, ...
2890 *
2891 * If one object to be compared is a node-set and the other is a number,
2892 * then the comparison will be true if and only if there is a node in the
2893 * node-set such that the result of performing the comparison on the number
2894 * to be compared and on the result of converting the string-value of that
2895 * node to a number using the number function is true.
2896 *
2897 * Returns 0 or 1 depending on the results of the test.
2898 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002899static int
Owen Taylor3473f882001-02-23 17:55:21 +00002900xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2901 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2902 int i, ret = 0;
2903 xmlNodeSetPtr ns;
2904 xmlChar *str2;
2905
2906 if ((f == NULL) || (arg == NULL) ||
2907 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2908 xmlXPathFreeObject(arg);
2909 xmlXPathFreeObject(f);
2910 return(0);
2911 }
2912 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002913 if (ns != NULL) {
2914 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002915 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002916 if (str2 != NULL) {
2917 valuePush(ctxt,
2918 xmlXPathNewString(str2));
2919 xmlFree(str2);
2920 xmlXPathNumberFunction(ctxt, 1);
2921 valuePush(ctxt, xmlXPathObjectCopy(f));
2922 ret = xmlXPathCompareValues(ctxt, inf, strict);
2923 if (ret)
2924 break;
2925 }
2926 }
Owen Taylor3473f882001-02-23 17:55:21 +00002927 }
2928 xmlXPathFreeObject(arg);
2929 xmlXPathFreeObject(f);
2930 return(ret);
2931}
2932
2933/**
2934 * xmlXPathCompareNodeSetString:
2935 * @ctxt: the XPath Parser context
2936 * @inf: less than (1) or greater than (0)
2937 * @strict: is the comparison strict
2938 * @arg: the node set
2939 * @s: the value
2940 *
2941 * Implement the compare operation between a nodeset and a string
2942 * @ns < @val (1, 1, ...
2943 * @ns <= @val (1, 0, ...
2944 * @ns > @val (0, 1, ...
2945 * @ns >= @val (0, 0, ...
2946 *
2947 * If one object to be compared is a node-set and the other is a string,
2948 * then the comparison will be true if and only if there is a node in
2949 * the node-set such that the result of performing the comparison on the
2950 * string-value of the node and the other string is true.
2951 *
2952 * Returns 0 or 1 depending on the results of the test.
2953 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002954static int
Owen Taylor3473f882001-02-23 17:55:21 +00002955xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2956 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2957 int i, ret = 0;
2958 xmlNodeSetPtr ns;
2959 xmlChar *str2;
2960
2961 if ((s == NULL) || (arg == NULL) ||
2962 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2963 xmlXPathFreeObject(arg);
2964 xmlXPathFreeObject(s);
2965 return(0);
2966 }
2967 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002968 if (ns != NULL) {
2969 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002970 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002971 if (str2 != NULL) {
2972 valuePush(ctxt,
2973 xmlXPathNewString(str2));
2974 xmlFree(str2);
2975 valuePush(ctxt, xmlXPathObjectCopy(s));
2976 ret = xmlXPathCompareValues(ctxt, inf, strict);
2977 if (ret)
2978 break;
2979 }
2980 }
Owen Taylor3473f882001-02-23 17:55:21 +00002981 }
2982 xmlXPathFreeObject(arg);
2983 xmlXPathFreeObject(s);
2984 return(ret);
2985}
2986
2987/**
2988 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002989 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00002990 * @strict: is the comparison strict
2991 * @arg1: the fist node set object
2992 * @arg2: the second node set object
2993 *
2994 * Implement the compare operation on nodesets:
2995 *
2996 * If both objects to be compared are node-sets, then the comparison
2997 * will be true if and only if there is a node in the first node-set
2998 * and a node in the second node-set such that the result of performing
2999 * the comparison on the string-values of the two nodes is true.
3000 * ....
3001 * When neither object to be compared is a node-set and the operator
3002 * is <=, <, >= or >, then the objects are compared by converting both
3003 * objects to numbers and comparing the numbers according to IEEE 754.
3004 * ....
3005 * The number function converts its argument to a number as follows:
3006 * - a string that consists of optional whitespace followed by an
3007 * optional minus sign followed by a Number followed by whitespace
3008 * is converted to the IEEE 754 number that is nearest (according
3009 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3010 * represented by the string; any other string is converted to NaN
3011 *
3012 * Conclusion all nodes need to be converted first to their string value
3013 * and then the comparison must be done when possible
3014 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003015static int
3016xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003017 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3018 int i, j, init = 0;
3019 double val1;
3020 double *values2;
3021 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003022 xmlNodeSetPtr ns1;
3023 xmlNodeSetPtr ns2;
3024
3025 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003026 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3027 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003028 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003029 }
Owen Taylor3473f882001-02-23 17:55:21 +00003030 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003031 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3032 xmlXPathFreeObject(arg1);
3033 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003034 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003035 }
Owen Taylor3473f882001-02-23 17:55:21 +00003036
3037 ns1 = arg1->nodesetval;
3038 ns2 = arg2->nodesetval;
3039
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003040 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003041 xmlXPathFreeObject(arg1);
3042 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003043 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003044 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003045 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003046 xmlXPathFreeObject(arg1);
3047 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003048 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003049 }
Owen Taylor3473f882001-02-23 17:55:21 +00003050
3051 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3052 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003053 xmlXPathFreeObject(arg1);
3054 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003055 return(0);
3056 }
3057 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003058 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003059 if (isnan(val1))
3060 continue;
3061 for (j = 0;j < ns2->nodeNr;j++) {
3062 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003063 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003064 }
3065 if (isnan(values2[j]))
3066 continue;
3067 if (inf && strict)
3068 ret = (val1 < values2[j]);
3069 else if (inf && !strict)
3070 ret = (val1 <= values2[j]);
3071 else if (!inf && strict)
3072 ret = (val1 > values2[j]);
3073 else if (!inf && !strict)
3074 ret = (val1 >= values2[j]);
3075 if (ret)
3076 break;
3077 }
3078 if (ret)
3079 break;
3080 init = 1;
3081 }
3082 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003083 xmlXPathFreeObject(arg1);
3084 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003085 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003086}
3087
3088/**
3089 * xmlXPathCompareNodeSetValue:
3090 * @ctxt: the XPath Parser context
3091 * @inf: less than (1) or greater than (0)
3092 * @strict: is the comparison strict
3093 * @arg: the node set
3094 * @val: the value
3095 *
3096 * Implement the compare operation between a nodeset and a value
3097 * @ns < @val (1, 1, ...
3098 * @ns <= @val (1, 0, ...
3099 * @ns > @val (0, 1, ...
3100 * @ns >= @val (0, 0, ...
3101 *
3102 * If one object to be compared is a node-set and the other is a boolean,
3103 * then the comparison will be true if and only if the result of performing
3104 * the comparison on the boolean and on the result of converting
3105 * the node-set to a boolean using the boolean function is true.
3106 *
3107 * Returns 0 or 1 depending on the results of the test.
3108 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003109static int
Owen Taylor3473f882001-02-23 17:55:21 +00003110xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3111 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3112 if ((val == NULL) || (arg == NULL) ||
3113 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3114 return(0);
3115
3116 switch(val->type) {
3117 case XPATH_NUMBER:
3118 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3119 case XPATH_NODESET:
3120 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003121 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003122 case XPATH_STRING:
3123 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3124 case XPATH_BOOLEAN:
3125 valuePush(ctxt, arg);
3126 xmlXPathBooleanFunction(ctxt, 1);
3127 valuePush(ctxt, val);
3128 return(xmlXPathCompareValues(ctxt, inf, strict));
3129 default:
3130 TODO
3131 return(0);
3132 }
3133 return(0);
3134}
3135
3136/**
3137 * xmlXPathEqualNodeSetString
3138 * @arg: the nodeset object argument
3139 * @str: the string to compare to.
3140 *
3141 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3142 * If one object to be compared is a node-set and the other is a string,
3143 * then the comparison will be true if and only if there is a node in
3144 * the node-set such that the result of performing the comparison on the
3145 * string-value of the node and the other string is true.
3146 *
3147 * Returns 0 or 1 depending on the results of the test.
3148 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003149static int
Owen Taylor3473f882001-02-23 17:55:21 +00003150xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
3151 int i;
3152 xmlNodeSetPtr ns;
3153 xmlChar *str2;
3154
3155 if ((str == NULL) || (arg == NULL) ||
3156 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3157 return(0);
3158 ns = arg->nodesetval;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003159 if (ns == NULL)
3160 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003161 if (ns->nodeNr <= 0)
3162 return(0);
3163 for (i = 0;i < ns->nodeNr;i++) {
3164 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3165 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3166 xmlFree(str2);
3167 return(1);
3168 }
3169 if (str2 != NULL)
3170 xmlFree(str2);
3171 }
3172 return(0);
3173}
3174
3175/**
3176 * xmlXPathEqualNodeSetFloat
3177 * @arg: the nodeset object argument
3178 * @f: the float to compare to
3179 *
3180 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3181 * If one object to be compared is a node-set and the other is a number,
3182 * then the comparison will be true if and only if there is a node in
3183 * the node-set such that the result of performing the comparison on the
3184 * number to be compared and on the result of converting the string-value
3185 * of that node to a number using the number function is true.
3186 *
3187 * Returns 0 or 1 depending on the results of the test.
3188 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003189static int
Owen Taylor3473f882001-02-23 17:55:21 +00003190xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3191 char buf[100] = "";
3192
3193 if ((arg == NULL) ||
3194 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3195 return(0);
3196
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003197 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003198 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3199}
3200
3201
3202/**
3203 * xmlXPathEqualNodeSets
3204 * @arg1: first nodeset object argument
3205 * @arg2: second nodeset object argument
3206 *
3207 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3208 * If both objects to be compared are node-sets, then the comparison
3209 * will be true if and only if there is a node in the first node-set and
3210 * a node in the second node-set such that the result of performing the
3211 * comparison on the string-values of the two nodes is true.
3212 *
3213 * (needless to say, this is a costly operation)
3214 *
3215 * Returns 0 or 1 depending on the results of the test.
3216 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003217static int
Owen Taylor3473f882001-02-23 17:55:21 +00003218xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3219 int i, j;
3220 xmlChar **values1;
3221 xmlChar **values2;
3222 int ret = 0;
3223 xmlNodeSetPtr ns1;
3224 xmlNodeSetPtr ns2;
3225
3226 if ((arg1 == NULL) ||
3227 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3228 return(0);
3229 if ((arg2 == NULL) ||
3230 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3231 return(0);
3232
3233 ns1 = arg1->nodesetval;
3234 ns2 = arg2->nodesetval;
3235
Daniel Veillard911f49a2001-04-07 15:39:35 +00003236 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003237 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003238 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003239 return(0);
3240
3241 /*
3242 * check if there is a node pertaining to both sets
3243 */
3244 for (i = 0;i < ns1->nodeNr;i++)
3245 for (j = 0;j < ns2->nodeNr;j++)
3246 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3247 return(1);
3248
3249 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3250 if (values1 == NULL)
3251 return(0);
3252 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3253 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3254 if (values2 == NULL) {
3255 xmlFree(values1);
3256 return(0);
3257 }
3258 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3259 for (i = 0;i < ns1->nodeNr;i++) {
3260 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3261 for (j = 0;j < ns2->nodeNr;j++) {
3262 if (i == 0)
3263 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3264 ret = xmlStrEqual(values1[i], values2[j]);
3265 if (ret)
3266 break;
3267 }
3268 if (ret)
3269 break;
3270 }
3271 for (i = 0;i < ns1->nodeNr;i++)
3272 if (values1[i] != NULL)
3273 xmlFree(values1[i]);
3274 for (j = 0;j < ns2->nodeNr;j++)
3275 if (values2[j] != NULL)
3276 xmlFree(values2[j]);
3277 xmlFree(values1);
3278 xmlFree(values2);
3279 return(ret);
3280}
3281
3282/**
3283 * xmlXPathEqualValues:
3284 * @ctxt: the XPath Parser context
3285 *
3286 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3287 *
3288 * Returns 0 or 1 depending on the results of the test.
3289 */
3290int
3291xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
3292 xmlXPathObjectPtr arg1, arg2;
3293 int ret = 0;
3294
3295 arg1 = valuePop(ctxt);
3296 if (arg1 == NULL)
3297 XP_ERROR0(XPATH_INVALID_OPERAND);
3298
3299 arg2 = valuePop(ctxt);
3300 if (arg2 == NULL) {
3301 xmlXPathFreeObject(arg1);
3302 XP_ERROR0(XPATH_INVALID_OPERAND);
3303 }
3304
3305 if (arg1 == arg2) {
3306#ifdef DEBUG_EXPR
3307 xmlGenericError(xmlGenericErrorContext,
3308 "Equal: by pointer\n");
3309#endif
3310 return(1);
3311 }
3312
3313 switch (arg1->type) {
3314 case XPATH_UNDEFINED:
3315#ifdef DEBUG_EXPR
3316 xmlGenericError(xmlGenericErrorContext,
3317 "Equal: undefined\n");
3318#endif
3319 break;
3320 case XPATH_XSLT_TREE:
3321 case XPATH_NODESET:
3322 switch (arg2->type) {
3323 case XPATH_UNDEFINED:
3324#ifdef DEBUG_EXPR
3325 xmlGenericError(xmlGenericErrorContext,
3326 "Equal: undefined\n");
3327#endif
3328 break;
3329 case XPATH_XSLT_TREE:
3330 case XPATH_NODESET:
3331 ret = xmlXPathEqualNodeSets(arg1, arg2);
3332 break;
3333 case XPATH_BOOLEAN:
3334 if ((arg1->nodesetval == NULL) ||
3335 (arg1->nodesetval->nodeNr == 0)) ret = 0;
3336 else
3337 ret = 1;
3338 ret = (ret == arg2->boolval);
3339 break;
3340 case XPATH_NUMBER:
3341 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
3342 break;
3343 case XPATH_STRING:
3344 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
3345 break;
3346 case XPATH_USERS:
3347 case XPATH_POINT:
3348 case XPATH_RANGE:
3349 case XPATH_LOCATIONSET:
3350 TODO
3351 break;
3352 }
3353 break;
3354 case XPATH_BOOLEAN:
3355 switch (arg2->type) {
3356 case XPATH_UNDEFINED:
3357#ifdef DEBUG_EXPR
3358 xmlGenericError(xmlGenericErrorContext,
3359 "Equal: undefined\n");
3360#endif
3361 break;
3362 case XPATH_NODESET:
3363 case XPATH_XSLT_TREE:
3364 if ((arg2->nodesetval == NULL) ||
3365 (arg2->nodesetval->nodeNr == 0)) ret = 0;
3366 else
3367 ret = 1;
3368 break;
3369 case XPATH_BOOLEAN:
3370#ifdef DEBUG_EXPR
3371 xmlGenericError(xmlGenericErrorContext,
3372 "Equal: %d boolean %d \n",
3373 arg1->boolval, arg2->boolval);
3374#endif
3375 ret = (arg1->boolval == arg2->boolval);
3376 break;
3377 case XPATH_NUMBER:
3378 if (arg2->floatval) ret = 1;
3379 else ret = 0;
3380 ret = (arg1->boolval == ret);
3381 break;
3382 case XPATH_STRING:
3383 if ((arg2->stringval == NULL) ||
3384 (arg2->stringval[0] == 0)) ret = 0;
3385 else
3386 ret = 1;
3387 ret = (arg1->boolval == ret);
3388 break;
3389 case XPATH_USERS:
3390 case XPATH_POINT:
3391 case XPATH_RANGE:
3392 case XPATH_LOCATIONSET:
3393 TODO
3394 break;
3395 }
3396 break;
3397 case XPATH_NUMBER:
3398 switch (arg2->type) {
3399 case XPATH_UNDEFINED:
3400#ifdef DEBUG_EXPR
3401 xmlGenericError(xmlGenericErrorContext,
3402 "Equal: undefined\n");
3403#endif
3404 break;
3405 case XPATH_NODESET:
3406 case XPATH_XSLT_TREE:
3407 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
3408 break;
3409 case XPATH_BOOLEAN:
3410 if (arg1->floatval) ret = 1;
3411 else ret = 0;
3412 ret = (arg2->boolval == ret);
3413 break;
3414 case XPATH_STRING:
3415 valuePush(ctxt, arg2);
3416 xmlXPathNumberFunction(ctxt, 1);
3417 arg2 = valuePop(ctxt);
3418 /* no break on purpose */
3419 case XPATH_NUMBER:
3420 ret = (arg1->floatval == arg2->floatval);
3421 break;
3422 case XPATH_USERS:
3423 case XPATH_POINT:
3424 case XPATH_RANGE:
3425 case XPATH_LOCATIONSET:
3426 TODO
3427 break;
3428 }
3429 break;
3430 case XPATH_STRING:
3431 switch (arg2->type) {
3432 case XPATH_UNDEFINED:
3433#ifdef DEBUG_EXPR
3434 xmlGenericError(xmlGenericErrorContext,
3435 "Equal: undefined\n");
3436#endif
3437 break;
3438 case XPATH_NODESET:
3439 case XPATH_XSLT_TREE:
3440 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
3441 break;
3442 case XPATH_BOOLEAN:
3443 if ((arg1->stringval == NULL) ||
3444 (arg1->stringval[0] == 0)) ret = 0;
3445 else
3446 ret = 1;
3447 ret = (arg2->boolval == ret);
3448 break;
3449 case XPATH_STRING:
3450 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
3451 break;
3452 case XPATH_NUMBER:
3453 valuePush(ctxt, arg1);
3454 xmlXPathNumberFunction(ctxt, 1);
3455 arg1 = valuePop(ctxt);
3456 ret = (arg1->floatval == arg2->floatval);
3457 break;
3458 case XPATH_USERS:
3459 case XPATH_POINT:
3460 case XPATH_RANGE:
3461 case XPATH_LOCATIONSET:
3462 TODO
3463 break;
3464 }
3465 break;
3466 case XPATH_USERS:
3467 case XPATH_POINT:
3468 case XPATH_RANGE:
3469 case XPATH_LOCATIONSET:
3470 TODO
3471 break;
3472 }
3473 xmlXPathFreeObject(arg1);
3474 xmlXPathFreeObject(arg2);
3475 return(ret);
3476}
3477
3478
3479/**
3480 * xmlXPathCompareValues:
3481 * @ctxt: the XPath Parser context
3482 * @inf: less than (1) or greater than (0)
3483 * @strict: is the comparison strict
3484 *
3485 * Implement the compare operation on XPath objects:
3486 * @arg1 < @arg2 (1, 1, ...
3487 * @arg1 <= @arg2 (1, 0, ...
3488 * @arg1 > @arg2 (0, 1, ...
3489 * @arg1 >= @arg2 (0, 0, ...
3490 *
3491 * When neither object to be compared is a node-set and the operator is
3492 * <=, <, >=, >, then the objects are compared by converted both objects
3493 * to numbers and comparing the numbers according to IEEE 754. The <
3494 * comparison will be true if and only if the first number is less than the
3495 * second number. The <= comparison will be true if and only if the first
3496 * number is less than or equal to the second number. The > comparison
3497 * will be true if and only if the first number is greater than the second
3498 * number. The >= comparison will be true if and only if the first number
3499 * is greater than or equal to the second number.
3500 *
3501 * Returns 1 if the comparaison succeeded, 0 if it failed
3502 */
3503int
3504xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3505 int ret = 0;
3506 xmlXPathObjectPtr arg1, arg2;
3507
3508 arg2 = valuePop(ctxt);
3509 if (arg2 == NULL) {
3510 XP_ERROR0(XPATH_INVALID_OPERAND);
3511 }
3512
3513 arg1 = valuePop(ctxt);
3514 if (arg1 == NULL) {
3515 xmlXPathFreeObject(arg2);
3516 XP_ERROR0(XPATH_INVALID_OPERAND);
3517 }
3518
3519 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3520 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003521 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003522 } else {
3523 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003524 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3525 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003526 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003527 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3528 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003529 }
3530 }
3531 return(ret);
3532 }
3533
3534 if (arg1->type != XPATH_NUMBER) {
3535 valuePush(ctxt, arg1);
3536 xmlXPathNumberFunction(ctxt, 1);
3537 arg1 = valuePop(ctxt);
3538 }
3539 if (arg1->type != XPATH_NUMBER) {
3540 xmlXPathFreeObject(arg1);
3541 xmlXPathFreeObject(arg2);
3542 XP_ERROR0(XPATH_INVALID_OPERAND);
3543 }
3544 if (arg2->type != XPATH_NUMBER) {
3545 valuePush(ctxt, arg2);
3546 xmlXPathNumberFunction(ctxt, 1);
3547 arg2 = valuePop(ctxt);
3548 }
3549 if (arg2->type != XPATH_NUMBER) {
3550 xmlXPathFreeObject(arg1);
3551 xmlXPathFreeObject(arg2);
3552 XP_ERROR0(XPATH_INVALID_OPERAND);
3553 }
3554 /*
3555 * Add tests for infinity and nan
3556 * => feedback on 3.4 for Inf and NaN
3557 */
3558 if (inf && strict)
3559 ret = (arg1->floatval < arg2->floatval);
3560 else if (inf && !strict)
3561 ret = (arg1->floatval <= arg2->floatval);
3562 else if (!inf && strict)
3563 ret = (arg1->floatval > arg2->floatval);
3564 else if (!inf && !strict)
3565 ret = (arg1->floatval >= arg2->floatval);
3566 xmlXPathFreeObject(arg1);
3567 xmlXPathFreeObject(arg2);
3568 return(ret);
3569}
3570
3571/**
3572 * xmlXPathValueFlipSign:
3573 * @ctxt: the XPath Parser context
3574 *
3575 * Implement the unary - operation on an XPath object
3576 * The numeric operators convert their operands to numbers as if
3577 * by calling the number function.
3578 */
3579void
3580xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003581 CAST_TO_NUMBER;
3582 CHECK_TYPE(XPATH_NUMBER);
3583 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00003584}
3585
3586/**
3587 * xmlXPathAddValues:
3588 * @ctxt: the XPath Parser context
3589 *
3590 * Implement the add operation on XPath objects:
3591 * The numeric operators convert their operands to numbers as if
3592 * by calling the number function.
3593 */
3594void
3595xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3596 xmlXPathObjectPtr arg;
3597 double val;
3598
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003599 arg = valuePop(ctxt);
3600 if (arg == NULL)
3601 XP_ERROR(XPATH_INVALID_OPERAND);
3602 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003603 xmlXPathFreeObject(arg);
3604
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003605 CAST_TO_NUMBER;
3606 CHECK_TYPE(XPATH_NUMBER);
3607 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00003608}
3609
3610/**
3611 * xmlXPathSubValues:
3612 * @ctxt: the XPath Parser context
3613 *
3614 * Implement the substraction operation on XPath objects:
3615 * The numeric operators convert their operands to numbers as if
3616 * by calling the number function.
3617 */
3618void
3619xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3620 xmlXPathObjectPtr arg;
3621 double val;
3622
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003623 arg = valuePop(ctxt);
3624 if (arg == NULL)
3625 XP_ERROR(XPATH_INVALID_OPERAND);
3626 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003627 xmlXPathFreeObject(arg);
3628
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003629 CAST_TO_NUMBER;
3630 CHECK_TYPE(XPATH_NUMBER);
3631 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003632}
3633
3634/**
3635 * xmlXPathMultValues:
3636 * @ctxt: the XPath Parser context
3637 *
3638 * Implement the multiply operation on XPath objects:
3639 * The numeric operators convert their operands to numbers as if
3640 * by calling the number function.
3641 */
3642void
3643xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3644 xmlXPathObjectPtr arg;
3645 double val;
3646
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003647 arg = valuePop(ctxt);
3648 if (arg == NULL)
3649 XP_ERROR(XPATH_INVALID_OPERAND);
3650 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003651 xmlXPathFreeObject(arg);
3652
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003653 CAST_TO_NUMBER;
3654 CHECK_TYPE(XPATH_NUMBER);
3655 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003656}
3657
3658/**
3659 * xmlXPathDivValues:
3660 * @ctxt: the XPath Parser context
3661 *
3662 * Implement the div operation on XPath objects @arg1 / @arg2:
3663 * The numeric operators convert their operands to numbers as if
3664 * by calling the number function.
3665 */
3666void
3667xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3668 xmlXPathObjectPtr arg;
3669 double val;
3670
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003671 arg = valuePop(ctxt);
3672 if (arg == NULL)
3673 XP_ERROR(XPATH_INVALID_OPERAND);
3674 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003675 xmlXPathFreeObject(arg);
3676
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003677 CAST_TO_NUMBER;
3678 CHECK_TYPE(XPATH_NUMBER);
3679 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003680}
3681
3682/**
3683 * xmlXPathModValues:
3684 * @ctxt: the XPath Parser context
3685 *
3686 * Implement the mod operation on XPath objects: @arg1 / @arg2
3687 * The numeric operators convert their operands to numbers as if
3688 * by calling the number function.
3689 */
3690void
3691xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3692 xmlXPathObjectPtr arg;
3693 int arg1, arg2;
3694
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003695 arg = valuePop(ctxt);
3696 if (arg == NULL)
3697 XP_ERROR(XPATH_INVALID_OPERAND);
3698 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003699 xmlXPathFreeObject(arg);
3700
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003701 CAST_TO_NUMBER;
3702 CHECK_TYPE(XPATH_NUMBER);
3703 arg1 = (int) ctxt->value->floatval;
3704 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00003705}
3706
3707/************************************************************************
3708 * *
3709 * The traversal functions *
3710 * *
3711 ************************************************************************/
3712
Owen Taylor3473f882001-02-23 17:55:21 +00003713/*
3714 * A traversal function enumerates nodes along an axis.
3715 * Initially it must be called with NULL, and it indicates
3716 * termination on the axis by returning NULL.
3717 */
3718typedef xmlNodePtr (*xmlXPathTraversalFunction)
3719 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3720
3721/**
3722 * xmlXPathNextSelf:
3723 * @ctxt: the XPath Parser context
3724 * @cur: the current node in the traversal
3725 *
3726 * Traversal function for the "self" direction
3727 * The self axis contains just the context node itself
3728 *
3729 * Returns the next element following that axis
3730 */
3731xmlNodePtr
3732xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3733 if (cur == NULL)
3734 return(ctxt->context->node);
3735 return(NULL);
3736}
3737
3738/**
3739 * xmlXPathNextChild:
3740 * @ctxt: the XPath Parser context
3741 * @cur: the current node in the traversal
3742 *
3743 * Traversal function for the "child" direction
3744 * The child axis contains the children of the context node in document order.
3745 *
3746 * Returns the next element following that axis
3747 */
3748xmlNodePtr
3749xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3750 if (cur == NULL) {
3751 if (ctxt->context->node == NULL) return(NULL);
3752 switch (ctxt->context->node->type) {
3753 case XML_ELEMENT_NODE:
3754 case XML_TEXT_NODE:
3755 case XML_CDATA_SECTION_NODE:
3756 case XML_ENTITY_REF_NODE:
3757 case XML_ENTITY_NODE:
3758 case XML_PI_NODE:
3759 case XML_COMMENT_NODE:
3760 case XML_NOTATION_NODE:
3761 case XML_DTD_NODE:
3762 return(ctxt->context->node->children);
3763 case XML_DOCUMENT_NODE:
3764 case XML_DOCUMENT_TYPE_NODE:
3765 case XML_DOCUMENT_FRAG_NODE:
3766 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003767#ifdef LIBXML_DOCB_ENABLED
3768 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003769#endif
3770 return(((xmlDocPtr) ctxt->context->node)->children);
3771 case XML_ELEMENT_DECL:
3772 case XML_ATTRIBUTE_DECL:
3773 case XML_ENTITY_DECL:
3774 case XML_ATTRIBUTE_NODE:
3775 case XML_NAMESPACE_DECL:
3776 case XML_XINCLUDE_START:
3777 case XML_XINCLUDE_END:
3778 return(NULL);
3779 }
3780 return(NULL);
3781 }
3782 if ((cur->type == XML_DOCUMENT_NODE) ||
3783 (cur->type == XML_HTML_DOCUMENT_NODE))
3784 return(NULL);
3785 return(cur->next);
3786}
3787
3788/**
3789 * xmlXPathNextDescendant:
3790 * @ctxt: the XPath Parser context
3791 * @cur: the current node in the traversal
3792 *
3793 * Traversal function for the "descendant" direction
3794 * the descendant axis contains the descendants of the context node in document
3795 * order; a descendant is a child or a child of a child and so on.
3796 *
3797 * Returns the next element following that axis
3798 */
3799xmlNodePtr
3800xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3801 if (cur == NULL) {
3802 if (ctxt->context->node == NULL)
3803 return(NULL);
3804 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3805 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3806 return(NULL);
3807
3808 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3809 return(ctxt->context->doc->children);
3810 return(ctxt->context->node->children);
3811 }
3812
3813 if (cur->children != NULL)
3814 {
3815 if (cur->children->type != XML_ENTITY_DECL)
3816 return(cur->children);
3817 }
3818 if (cur->next != NULL) return(cur->next);
3819
3820 do {
3821 cur = cur->parent;
3822 if (cur == NULL) return(NULL);
3823 if (cur == ctxt->context->node) return(NULL);
3824 if (cur->next != NULL) {
3825 cur = cur->next;
3826 return(cur);
3827 }
3828 } while (cur != NULL);
3829 return(cur);
3830}
3831
3832/**
3833 * xmlXPathNextDescendantOrSelf:
3834 * @ctxt: the XPath Parser context
3835 * @cur: the current node in the traversal
3836 *
3837 * Traversal function for the "descendant-or-self" direction
3838 * the descendant-or-self axis contains the context node and the descendants
3839 * of the context node in document order; thus the context node is the first
3840 * node on the axis, and the first child of the context node is the second node
3841 * on the axis
3842 *
3843 * Returns the next element following that axis
3844 */
3845xmlNodePtr
3846xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3847 if (cur == NULL) {
3848 if (ctxt->context->node == NULL)
3849 return(NULL);
3850 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3851 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3852 return(NULL);
3853 return(ctxt->context->node);
3854 }
3855
3856 return(xmlXPathNextDescendant(ctxt, cur));
3857}
3858
3859/**
3860 * xmlXPathNextParent:
3861 * @ctxt: the XPath Parser context
3862 * @cur: the current node in the traversal
3863 *
3864 * Traversal function for the "parent" direction
3865 * The parent axis contains the parent of the context node, if there is one.
3866 *
3867 * Returns the next element following that axis
3868 */
3869xmlNodePtr
3870xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3871 /*
3872 * the parent of an attribute or namespace node is the element
3873 * to which the attribute or namespace node is attached
3874 * Namespace handling !!!
3875 */
3876 if (cur == NULL) {
3877 if (ctxt->context->node == NULL) return(NULL);
3878 switch (ctxt->context->node->type) {
3879 case XML_ELEMENT_NODE:
3880 case XML_TEXT_NODE:
3881 case XML_CDATA_SECTION_NODE:
3882 case XML_ENTITY_REF_NODE:
3883 case XML_ENTITY_NODE:
3884 case XML_PI_NODE:
3885 case XML_COMMENT_NODE:
3886 case XML_NOTATION_NODE:
3887 case XML_DTD_NODE:
3888 case XML_ELEMENT_DECL:
3889 case XML_ATTRIBUTE_DECL:
3890 case XML_XINCLUDE_START:
3891 case XML_XINCLUDE_END:
3892 case XML_ENTITY_DECL:
3893 if (ctxt->context->node->parent == NULL)
3894 return((xmlNodePtr) ctxt->context->doc);
3895 return(ctxt->context->node->parent);
3896 case XML_ATTRIBUTE_NODE: {
3897 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3898
3899 return(att->parent);
3900 }
3901 case XML_DOCUMENT_NODE:
3902 case XML_DOCUMENT_TYPE_NODE:
3903 case XML_DOCUMENT_FRAG_NODE:
3904 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003905#ifdef LIBXML_DOCB_ENABLED
3906 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003907#endif
3908 return(NULL);
3909 case XML_NAMESPACE_DECL:
3910 /*
3911 * TODO !!! may require extending struct _xmlNs with
3912 * parent field
3913 * C.f. Infoset case...
3914 */
3915 return(NULL);
3916 }
3917 }
3918 return(NULL);
3919}
3920
3921/**
3922 * xmlXPathNextAncestor:
3923 * @ctxt: the XPath Parser context
3924 * @cur: the current node in the traversal
3925 *
3926 * Traversal function for the "ancestor" direction
3927 * the ancestor axis contains the ancestors of the context node; the ancestors
3928 * of the context node consist of the parent of context node and the parent's
3929 * parent and so on; the nodes are ordered in reverse document order; thus the
3930 * parent is the first node on the axis, and the parent's parent is the second
3931 * node on the axis
3932 *
3933 * Returns the next element following that axis
3934 */
3935xmlNodePtr
3936xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3937 /*
3938 * the parent of an attribute or namespace node is the element
3939 * to which the attribute or namespace node is attached
3940 * !!!!!!!!!!!!!
3941 */
3942 if (cur == NULL) {
3943 if (ctxt->context->node == NULL) return(NULL);
3944 switch (ctxt->context->node->type) {
3945 case XML_ELEMENT_NODE:
3946 case XML_TEXT_NODE:
3947 case XML_CDATA_SECTION_NODE:
3948 case XML_ENTITY_REF_NODE:
3949 case XML_ENTITY_NODE:
3950 case XML_PI_NODE:
3951 case XML_COMMENT_NODE:
3952 case XML_DTD_NODE:
3953 case XML_ELEMENT_DECL:
3954 case XML_ATTRIBUTE_DECL:
3955 case XML_ENTITY_DECL:
3956 case XML_NOTATION_NODE:
3957 case XML_XINCLUDE_START:
3958 case XML_XINCLUDE_END:
3959 if (ctxt->context->node->parent == NULL)
3960 return((xmlNodePtr) ctxt->context->doc);
3961 return(ctxt->context->node->parent);
3962 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003963 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00003964
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003965 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003966 }
3967 case XML_DOCUMENT_NODE:
3968 case XML_DOCUMENT_TYPE_NODE:
3969 case XML_DOCUMENT_FRAG_NODE:
3970 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003971#ifdef LIBXML_DOCB_ENABLED
3972 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003973#endif
3974 return(NULL);
3975 case XML_NAMESPACE_DECL:
3976 /*
3977 * TODO !!! may require extending struct _xmlNs with
3978 * parent field
3979 * C.f. Infoset case...
3980 */
3981 return(NULL);
3982 }
3983 return(NULL);
3984 }
3985 if (cur == ctxt->context->doc->children)
3986 return((xmlNodePtr) ctxt->context->doc);
3987 if (cur == (xmlNodePtr) ctxt->context->doc)
3988 return(NULL);
3989 switch (cur->type) {
3990 case XML_ELEMENT_NODE:
3991 case XML_TEXT_NODE:
3992 case XML_CDATA_SECTION_NODE:
3993 case XML_ENTITY_REF_NODE:
3994 case XML_ENTITY_NODE:
3995 case XML_PI_NODE:
3996 case XML_COMMENT_NODE:
3997 case XML_NOTATION_NODE:
3998 case XML_DTD_NODE:
3999 case XML_ELEMENT_DECL:
4000 case XML_ATTRIBUTE_DECL:
4001 case XML_ENTITY_DECL:
4002 case XML_XINCLUDE_START:
4003 case XML_XINCLUDE_END:
4004 return(cur->parent);
4005 case XML_ATTRIBUTE_NODE: {
4006 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4007
4008 return(att->parent);
4009 }
4010 case XML_DOCUMENT_NODE:
4011 case XML_DOCUMENT_TYPE_NODE:
4012 case XML_DOCUMENT_FRAG_NODE:
4013 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004014#ifdef LIBXML_DOCB_ENABLED
4015 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004016#endif
4017 return(NULL);
4018 case XML_NAMESPACE_DECL:
4019 /*
4020 * TODO !!! may require extending struct _xmlNs with
4021 * parent field
4022 * C.f. Infoset case...
4023 */
4024 return(NULL);
4025 }
4026 return(NULL);
4027}
4028
4029/**
4030 * xmlXPathNextAncestorOrSelf:
4031 * @ctxt: the XPath Parser context
4032 * @cur: the current node in the traversal
4033 *
4034 * Traversal function for the "ancestor-or-self" direction
4035 * he ancestor-or-self axis contains the context node and ancestors of
4036 * the context node in reverse document order; thus the context node is
4037 * the first node on the axis, and the context node's parent the second;
4038 * parent here is defined the same as with the parent axis.
4039 *
4040 * Returns the next element following that axis
4041 */
4042xmlNodePtr
4043xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4044 if (cur == NULL)
4045 return(ctxt->context->node);
4046 return(xmlXPathNextAncestor(ctxt, cur));
4047}
4048
4049/**
4050 * xmlXPathNextFollowingSibling:
4051 * @ctxt: the XPath Parser context
4052 * @cur: the current node in the traversal
4053 *
4054 * Traversal function for the "following-sibling" direction
4055 * The following-sibling axis contains the following siblings of the context
4056 * node in document order.
4057 *
4058 * Returns the next element following that axis
4059 */
4060xmlNodePtr
4061xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4062 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4063 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4064 return(NULL);
4065 if (cur == (xmlNodePtr) ctxt->context->doc)
4066 return(NULL);
4067 if (cur == NULL)
4068 return(ctxt->context->node->next);
4069 return(cur->next);
4070}
4071
4072/**
4073 * xmlXPathNextPrecedingSibling:
4074 * @ctxt: the XPath Parser context
4075 * @cur: the current node in the traversal
4076 *
4077 * Traversal function for the "preceding-sibling" direction
4078 * The preceding-sibling axis contains the preceding siblings of the context
4079 * node in reverse document order; the first preceding sibling is first on the
4080 * axis; the sibling preceding that node is the second on the axis and so on.
4081 *
4082 * Returns the next element following that axis
4083 */
4084xmlNodePtr
4085xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4086 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4087 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4088 return(NULL);
4089 if (cur == (xmlNodePtr) ctxt->context->doc)
4090 return(NULL);
4091 if (cur == NULL)
4092 return(ctxt->context->node->prev);
4093 return(cur->prev);
4094}
4095
4096/**
4097 * xmlXPathNextFollowing:
4098 * @ctxt: the XPath Parser context
4099 * @cur: the current node in the traversal
4100 *
4101 * Traversal function for the "following" direction
4102 * The following axis contains all nodes in the same document as the context
4103 * node that are after the context node in document order, excluding any
4104 * descendants and excluding attribute nodes and namespace nodes; the nodes
4105 * are ordered in document order
4106 *
4107 * Returns the next element following that axis
4108 */
4109xmlNodePtr
4110xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4111 if (cur != NULL && cur->children != NULL)
4112 return cur->children ;
4113 if (cur == NULL) cur = ctxt->context->node;
4114 if (cur == NULL) return(NULL) ; /* ERROR */
4115 if (cur->next != NULL) return(cur->next) ;
4116 do {
4117 cur = cur->parent;
4118 if (cur == NULL) return(NULL);
4119 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4120 if (cur->next != NULL) return(cur->next);
4121 } while (cur != NULL);
4122 return(cur);
4123}
4124
4125/*
4126 * xmlXPathIsAncestor:
4127 * @ancestor: the ancestor node
4128 * @node: the current node
4129 *
4130 * Check that @ancestor is a @node's ancestor
4131 *
4132 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4133 */
4134static int
4135xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4136 if ((ancestor == NULL) || (node == NULL)) return(0);
4137 /* nodes need to be in the same document */
4138 if (ancestor->doc != node->doc) return(0);
4139 /* avoid searching if ancestor or node is the root node */
4140 if (ancestor == (xmlNodePtr) node->doc) return(1);
4141 if (node == (xmlNodePtr) ancestor->doc) return(0);
4142 while (node->parent != NULL) {
4143 if (node->parent == ancestor)
4144 return(1);
4145 node = node->parent;
4146 }
4147 return(0);
4148}
4149
4150/**
4151 * xmlXPathNextPreceding:
4152 * @ctxt: the XPath Parser context
4153 * @cur: the current node in the traversal
4154 *
4155 * Traversal function for the "preceding" direction
4156 * the preceding axis contains all nodes in the same document as the context
4157 * node that are before the context node in document order, excluding any
4158 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4159 * ordered in reverse document order
4160 *
4161 * Returns the next element following that axis
4162 */
4163xmlNodePtr
4164xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4165 if (cur == NULL)
4166 cur = ctxt->context->node ;
4167 do {
4168 if (cur->prev != NULL) {
4169 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
4170 ;
4171 return(cur) ;
4172 }
4173
4174 cur = cur->parent;
4175 if (cur == NULL) return(NULL);
4176 if (cur == ctxt->context->doc->children) return(NULL);
4177 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
4178 return(cur);
4179}
4180
4181/**
4182 * xmlXPathNextNamespace:
4183 * @ctxt: the XPath Parser context
4184 * @cur: the current attribute in the traversal
4185 *
4186 * Traversal function for the "namespace" direction
4187 * the namespace axis contains the namespace nodes of the context node;
4188 * the order of nodes on this axis is implementation-defined; the axis will
4189 * be empty unless the context node is an element
4190 *
4191 * Returns the next element following that axis
4192 */
4193xmlNodePtr
4194xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4195 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
4196 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
4197 if (ctxt->context->namespaces != NULL)
4198 xmlFree(ctxt->context->namespaces);
4199 ctxt->context->namespaces =
4200 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
4201 if (ctxt->context->namespaces == NULL) return(NULL);
4202 ctxt->context->nsNr = 0;
4203 }
4204 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
4205}
4206
4207/**
4208 * xmlXPathNextAttribute:
4209 * @ctxt: the XPath Parser context
4210 * @cur: the current attribute in the traversal
4211 *
4212 * Traversal function for the "attribute" direction
4213 * TODO: support DTD inherited default attributes
4214 *
4215 * Returns the next element following that axis
4216 */
4217xmlNodePtr
4218xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00004219 if (ctxt->context->node == NULL)
4220 return(NULL);
4221 if (ctxt->context->node->type != XML_ELEMENT_NODE)
4222 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004223 if (cur == NULL) {
4224 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4225 return(NULL);
4226 return((xmlNodePtr)ctxt->context->node->properties);
4227 }
4228 return((xmlNodePtr)cur->next);
4229}
4230
4231/************************************************************************
4232 * *
4233 * NodeTest Functions *
4234 * *
4235 ************************************************************************/
4236
Owen Taylor3473f882001-02-23 17:55:21 +00004237#define IS_FUNCTION 200
4238
Owen Taylor3473f882001-02-23 17:55:21 +00004239
4240/************************************************************************
4241 * *
4242 * Implicit tree core function library *
4243 * *
4244 ************************************************************************/
4245
4246/**
4247 * xmlXPathRoot:
4248 * @ctxt: the XPath Parser context
4249 *
4250 * Initialize the context to the root of the document
4251 */
4252void
4253xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
4254 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
4255 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4256}
4257
4258/************************************************************************
4259 * *
4260 * The explicit core function library *
4261 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
4262 * *
4263 ************************************************************************/
4264
4265
4266/**
4267 * xmlXPathLastFunction:
4268 * @ctxt: the XPath Parser context
4269 * @nargs: the number of arguments
4270 *
4271 * Implement the last() XPath function
4272 * number last()
4273 * The last function returns the number of nodes in the context node list.
4274 */
4275void
4276xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4277 CHECK_ARITY(0);
4278 if (ctxt->context->contextSize >= 0) {
4279 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
4280#ifdef DEBUG_EXPR
4281 xmlGenericError(xmlGenericErrorContext,
4282 "last() : %d\n", ctxt->context->contextSize);
4283#endif
4284 } else {
4285 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
4286 }
4287}
4288
4289/**
4290 * xmlXPathPositionFunction:
4291 * @ctxt: the XPath Parser context
4292 * @nargs: the number of arguments
4293 *
4294 * Implement the position() XPath function
4295 * number position()
4296 * The position function returns the position of the context node in the
4297 * context node list. The first position is 1, and so the last positionr
4298 * will be equal to last().
4299 */
4300void
4301xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4302 CHECK_ARITY(0);
4303 if (ctxt->context->proximityPosition >= 0) {
4304 valuePush(ctxt,
4305 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
4306#ifdef DEBUG_EXPR
4307 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
4308 ctxt->context->proximityPosition);
4309#endif
4310 } else {
4311 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
4312 }
4313}
4314
4315/**
4316 * xmlXPathCountFunction:
4317 * @ctxt: the XPath Parser context
4318 * @nargs: the number of arguments
4319 *
4320 * Implement the count() XPath function
4321 * number count(node-set)
4322 */
4323void
4324xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4325 xmlXPathObjectPtr cur;
4326
4327 CHECK_ARITY(1);
4328 if ((ctxt->value == NULL) ||
4329 ((ctxt->value->type != XPATH_NODESET) &&
4330 (ctxt->value->type != XPATH_XSLT_TREE)))
4331 XP_ERROR(XPATH_INVALID_TYPE);
4332 cur = valuePop(ctxt);
4333
Daniel Veillard911f49a2001-04-07 15:39:35 +00004334 if ((cur == NULL) || (cur->nodesetval == NULL))
4335 valuePush(ctxt, xmlXPathNewFloat((double) 0));
4336 else
4337 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00004338 xmlXPathFreeObject(cur);
4339}
4340
4341/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004342 * xmlXPathGetElementsByIds:
4343 * @doc: the document
4344 * @ids: a whitespace separated list of IDs
4345 *
4346 * Selects elements by their unique ID.
4347 *
4348 * Returns a node-set of selected elements.
4349 */
4350static xmlNodeSetPtr
4351xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
4352 xmlNodeSetPtr ret;
4353 const xmlChar *cur = ids;
4354 xmlChar *ID;
4355 xmlAttrPtr attr;
4356 xmlNodePtr elem = NULL;
4357
4358 ret = xmlXPathNodeSetCreate(NULL);
4359
4360 while (IS_BLANK(*cur)) cur++;
4361 while (*cur != 0) {
4362 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
4363 (*cur == '.') || (*cur == '-') ||
4364 (*cur == '_') || (*cur == ':') ||
4365 (IS_COMBINING(*cur)) ||
4366 (IS_EXTENDER(*cur)))
4367 cur++;
4368
4369 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
4370
4371 ID = xmlStrndup(ids, cur - ids);
4372 attr = xmlGetID(doc, ID);
4373 if (attr != NULL) {
4374 elem = attr->parent;
4375 xmlXPathNodeSetAdd(ret, elem);
4376 }
4377 if (ID != NULL)
4378 xmlFree(ID);
4379
4380 while (IS_BLANK(*cur)) cur++;
4381 ids = cur;
4382 }
4383 return(ret);
4384}
4385
4386/**
Owen Taylor3473f882001-02-23 17:55:21 +00004387 * xmlXPathIdFunction:
4388 * @ctxt: the XPath Parser context
4389 * @nargs: the number of arguments
4390 *
4391 * Implement the id() XPath function
4392 * node-set id(object)
4393 * The id function selects elements by their unique ID
4394 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
4395 * then the result is the union of the result of applying id to the
4396 * string value of each of the nodes in the argument node-set. When the
4397 * argument to id is of any other type, the argument is converted to a
4398 * string as if by a call to the string function; the string is split
4399 * into a whitespace-separated list of tokens (whitespace is any sequence
4400 * of characters matching the production S); the result is a node-set
4401 * containing the elements in the same document as the context node that
4402 * have a unique ID equal to any of the tokens in the list.
4403 */
4404void
4405xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004406 xmlChar *tokens;
4407 xmlNodeSetPtr ret;
4408 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00004409
4410 CHECK_ARITY(1);
4411 obj = valuePop(ctxt);
4412 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
4413 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004414 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00004415 int i;
4416
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004417 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004418
Daniel Veillard911f49a2001-04-07 15:39:35 +00004419 if (obj->nodesetval != NULL) {
4420 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004421 tokens =
4422 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
4423 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
4424 ret = xmlXPathNodeSetMerge(ret, ns);
4425 xmlXPathFreeNodeSet(ns);
4426 if (tokens != NULL)
4427 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004428 }
Owen Taylor3473f882001-02-23 17:55:21 +00004429 }
4430
4431 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004432 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004433 return;
4434 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004435 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00004436
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004437 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
4438 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004439
Owen Taylor3473f882001-02-23 17:55:21 +00004440 xmlXPathFreeObject(obj);
4441 return;
4442}
4443
4444/**
4445 * xmlXPathLocalNameFunction:
4446 * @ctxt: the XPath Parser context
4447 * @nargs: the number of arguments
4448 *
4449 * Implement the local-name() XPath function
4450 * string local-name(node-set?)
4451 * The local-name function returns a string containing the local part
4452 * of the name of the node in the argument node-set that is first in
4453 * document order. If the node-set is empty or the first node has no
4454 * name, an empty string is returned. If the argument is omitted it
4455 * defaults to the context node.
4456 */
4457void
4458xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4459 xmlXPathObjectPtr cur;
4460
4461 if (nargs == 0) {
4462 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4463 nargs = 1;
4464 }
4465
4466 CHECK_ARITY(1);
4467 if ((ctxt->value == NULL) ||
4468 ((ctxt->value->type != XPATH_NODESET) &&
4469 (ctxt->value->type != XPATH_XSLT_TREE)))
4470 XP_ERROR(XPATH_INVALID_TYPE);
4471 cur = valuePop(ctxt);
4472
Daniel Veillard911f49a2001-04-07 15:39:35 +00004473 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004474 valuePush(ctxt, xmlXPathNewCString(""));
4475 } else {
4476 int i = 0; /* Should be first in document order !!!!! */
4477 switch (cur->nodesetval->nodeTab[i]->type) {
4478 case XML_ELEMENT_NODE:
4479 case XML_ATTRIBUTE_NODE:
4480 case XML_PI_NODE:
4481 valuePush(ctxt,
4482 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4483 break;
4484 case XML_NAMESPACE_DECL:
4485 valuePush(ctxt, xmlXPathNewString(
4486 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4487 break;
4488 default:
4489 valuePush(ctxt, xmlXPathNewCString(""));
4490 }
4491 }
4492 xmlXPathFreeObject(cur);
4493}
4494
4495/**
4496 * xmlXPathNamespaceURIFunction:
4497 * @ctxt: the XPath Parser context
4498 * @nargs: the number of arguments
4499 *
4500 * Implement the namespace-uri() XPath function
4501 * string namespace-uri(node-set?)
4502 * The namespace-uri function returns a string containing the
4503 * namespace URI of the expanded name of the node in the argument
4504 * node-set that is first in document order. If the node-set is empty,
4505 * the first node has no name, or the expanded name has no namespace
4506 * URI, an empty string is returned. If the argument is omitted it
4507 * defaults to the context node.
4508 */
4509void
4510xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4511 xmlXPathObjectPtr cur;
4512
4513 if (nargs == 0) {
4514 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4515 nargs = 1;
4516 }
4517 CHECK_ARITY(1);
4518 if ((ctxt->value == NULL) ||
4519 ((ctxt->value->type != XPATH_NODESET) &&
4520 (ctxt->value->type != XPATH_XSLT_TREE)))
4521 XP_ERROR(XPATH_INVALID_TYPE);
4522 cur = valuePop(ctxt);
4523
Daniel Veillard911f49a2001-04-07 15:39:35 +00004524 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004525 valuePush(ctxt, xmlXPathNewCString(""));
4526 } else {
4527 int i = 0; /* Should be first in document order !!!!! */
4528 switch (cur->nodesetval->nodeTab[i]->type) {
4529 case XML_ELEMENT_NODE:
4530 case XML_ATTRIBUTE_NODE:
4531 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4532 valuePush(ctxt, xmlXPathNewCString(""));
4533 else
4534 valuePush(ctxt, xmlXPathNewString(
4535 cur->nodesetval->nodeTab[i]->ns->href));
4536 break;
4537 default:
4538 valuePush(ctxt, xmlXPathNewCString(""));
4539 }
4540 }
4541 xmlXPathFreeObject(cur);
4542}
4543
4544/**
4545 * xmlXPathNameFunction:
4546 * @ctxt: the XPath Parser context
4547 * @nargs: the number of arguments
4548 *
4549 * Implement the name() XPath function
4550 * string name(node-set?)
4551 * The name function returns a string containing a QName representing
4552 * the name of the node in the argument node-set that is first in documenti
4553 * order. The QName must represent the name with respect to the namespace
4554 * declarations in effect on the node whose name is being represented.
4555 * Typically, this will be the form in which the name occurred in the XML
4556 * source. This need not be the case if there are namespace declarations
4557 * in effect on the node that associate multiple prefixes with the same
4558 * namespace. However, an implementation may include information about
4559 * the original prefix in its representation of nodes; in this case, an
4560 * implementation can ensure that the returned string is always the same
4561 * as the QName used in the XML source. If the argument it omitted it
4562 * defaults to the context node.
4563 * Libxml keep the original prefix so the "real qualified name" used is
4564 * returned.
4565 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004566static void
Owen Taylor3473f882001-02-23 17:55:21 +00004567xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4568 xmlXPathObjectPtr cur;
4569
4570 if (nargs == 0) {
4571 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4572 nargs = 1;
4573 }
4574
4575 CHECK_ARITY(1);
4576 if ((ctxt->value == NULL) ||
4577 ((ctxt->value->type != XPATH_NODESET) &&
4578 (ctxt->value->type != XPATH_XSLT_TREE)))
4579 XP_ERROR(XPATH_INVALID_TYPE);
4580 cur = valuePop(ctxt);
4581
Daniel Veillard911f49a2001-04-07 15:39:35 +00004582 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004583 valuePush(ctxt, xmlXPathNewCString(""));
4584 } else {
4585 int i = 0; /* Should be first in document order !!!!! */
4586
4587 switch (cur->nodesetval->nodeTab[i]->type) {
4588 case XML_ELEMENT_NODE:
4589 case XML_ATTRIBUTE_NODE:
4590 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4591 valuePush(ctxt, xmlXPathNewString(
4592 cur->nodesetval->nodeTab[i]->name));
4593
4594 else {
4595 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004596 snprintf(name, sizeof(name), "%s:%s",
4597 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4598 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004599 name[sizeof(name) - 1] = 0;
4600 valuePush(ctxt, xmlXPathNewCString(name));
4601 }
4602 break;
4603 default:
4604 valuePush(ctxt,
4605 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4606 xmlXPathLocalNameFunction(ctxt, 1);
4607 }
4608 }
4609 xmlXPathFreeObject(cur);
4610}
4611
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004612
4613/**
Owen Taylor3473f882001-02-23 17:55:21 +00004614 * xmlXPathStringFunction:
4615 * @ctxt: the XPath Parser context
4616 * @nargs: the number of arguments
4617 *
4618 * Implement the string() XPath function
4619 * string string(object?)
4620 * he string function converts an object to a string as follows:
4621 * - A node-set is converted to a string by returning the value of
4622 * the node in the node-set that is first in document order.
4623 * If the node-set is empty, an empty string is returned.
4624 * - A number is converted to a string as follows
4625 * + NaN is converted to the string NaN
4626 * + positive zero is converted to the string 0
4627 * + negative zero is converted to the string 0
4628 * + positive infinity is converted to the string Infinity
4629 * + negative infinity is converted to the string -Infinity
4630 * + if the number is an integer, the number is represented in
4631 * decimal form as a Number with no decimal point and no leading
4632 * zeros, preceded by a minus sign (-) if the number is negative
4633 * + otherwise, the number is represented in decimal form as a
4634 * Number including a decimal point with at least one digit
4635 * before the decimal point and at least one digit after the
4636 * decimal point, preceded by a minus sign (-) if the number
4637 * is negative; there must be no leading zeros before the decimal
4638 * point apart possibly from the one required digit immediatelyi
4639 * before the decimal point; beyond the one required digit
4640 * after the decimal point there must be as many, but only as
4641 * many, more digits as are needed to uniquely distinguish the
4642 * number from all other IEEE 754 numeric values.
4643 * - The boolean false value is converted to the string false.
4644 * The boolean true value is converted to the string true.
4645 *
4646 * If the argument is omitted, it defaults to a node-set with the
4647 * context node as its only member.
4648 */
4649void
4650xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4651 xmlXPathObjectPtr cur;
4652
4653 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004654 valuePush(ctxt,
4655 xmlXPathWrapString(
4656 xmlXPathCastNodeToString(ctxt->context->node)));
4657 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004658 }
4659
4660 CHECK_ARITY(1);
4661 cur = valuePop(ctxt);
4662 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004663 cur = xmlXPathConvertString(cur);
4664 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004665}
4666
4667/**
4668 * xmlXPathStringLengthFunction:
4669 * @ctxt: the XPath Parser context
4670 * @nargs: the number of arguments
4671 *
4672 * Implement the string-length() XPath function
4673 * number string-length(string?)
4674 * The string-length returns the number of characters in the string
4675 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4676 * the context node converted to a string, in other words the value
4677 * of the context node.
4678 */
4679void
4680xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4681 xmlXPathObjectPtr cur;
4682
4683 if (nargs == 0) {
4684 if (ctxt->context->node == NULL) {
4685 valuePush(ctxt, xmlXPathNewFloat(0));
4686 } else {
4687 xmlChar *content;
4688
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004689 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004690 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004691 xmlFree(content);
4692 }
4693 return;
4694 }
4695 CHECK_ARITY(1);
4696 CAST_TO_STRING;
4697 CHECK_TYPE(XPATH_STRING);
4698 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004699 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004700 xmlXPathFreeObject(cur);
4701}
4702
4703/**
4704 * xmlXPathConcatFunction:
4705 * @ctxt: the XPath Parser context
4706 * @nargs: the number of arguments
4707 *
4708 * Implement the concat() XPath function
4709 * string concat(string, string, string*)
4710 * The concat function returns the concatenation of its arguments.
4711 */
4712void
4713xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4714 xmlXPathObjectPtr cur, newobj;
4715 xmlChar *tmp;
4716
4717 if (nargs < 2) {
4718 CHECK_ARITY(2);
4719 }
4720
4721 CAST_TO_STRING;
4722 cur = valuePop(ctxt);
4723 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4724 xmlXPathFreeObject(cur);
4725 return;
4726 }
4727 nargs--;
4728
4729 while (nargs > 0) {
4730 CAST_TO_STRING;
4731 newobj = valuePop(ctxt);
4732 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4733 xmlXPathFreeObject(newobj);
4734 xmlXPathFreeObject(cur);
4735 XP_ERROR(XPATH_INVALID_TYPE);
4736 }
4737 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4738 newobj->stringval = cur->stringval;
4739 cur->stringval = tmp;
4740
4741 xmlXPathFreeObject(newobj);
4742 nargs--;
4743 }
4744 valuePush(ctxt, cur);
4745}
4746
4747/**
4748 * xmlXPathContainsFunction:
4749 * @ctxt: the XPath Parser context
4750 * @nargs: the number of arguments
4751 *
4752 * Implement the contains() XPath function
4753 * boolean contains(string, string)
4754 * The contains function returns true if the first argument string
4755 * contains the second argument string, and otherwise returns false.
4756 */
4757void
4758xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4759 xmlXPathObjectPtr hay, needle;
4760
4761 CHECK_ARITY(2);
4762 CAST_TO_STRING;
4763 CHECK_TYPE(XPATH_STRING);
4764 needle = valuePop(ctxt);
4765 CAST_TO_STRING;
4766 hay = valuePop(ctxt);
4767 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4768 xmlXPathFreeObject(hay);
4769 xmlXPathFreeObject(needle);
4770 XP_ERROR(XPATH_INVALID_TYPE);
4771 }
4772 if (xmlStrstr(hay->stringval, needle->stringval))
4773 valuePush(ctxt, xmlXPathNewBoolean(1));
4774 else
4775 valuePush(ctxt, xmlXPathNewBoolean(0));
4776 xmlXPathFreeObject(hay);
4777 xmlXPathFreeObject(needle);
4778}
4779
4780/**
4781 * xmlXPathStartsWithFunction:
4782 * @ctxt: the XPath Parser context
4783 * @nargs: the number of arguments
4784 *
4785 * Implement the starts-with() XPath function
4786 * boolean starts-with(string, string)
4787 * The starts-with function returns true if the first argument string
4788 * starts with the second argument string, and otherwise returns false.
4789 */
4790void
4791xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4792 xmlXPathObjectPtr hay, needle;
4793 int n;
4794
4795 CHECK_ARITY(2);
4796 CAST_TO_STRING;
4797 CHECK_TYPE(XPATH_STRING);
4798 needle = valuePop(ctxt);
4799 CAST_TO_STRING;
4800 hay = valuePop(ctxt);
4801 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4802 xmlXPathFreeObject(hay);
4803 xmlXPathFreeObject(needle);
4804 XP_ERROR(XPATH_INVALID_TYPE);
4805 }
4806 n = xmlStrlen(needle->stringval);
4807 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4808 valuePush(ctxt, xmlXPathNewBoolean(0));
4809 else
4810 valuePush(ctxt, xmlXPathNewBoolean(1));
4811 xmlXPathFreeObject(hay);
4812 xmlXPathFreeObject(needle);
4813}
4814
4815/**
4816 * xmlXPathSubstringFunction:
4817 * @ctxt: the XPath Parser context
4818 * @nargs: the number of arguments
4819 *
4820 * Implement the substring() XPath function
4821 * string substring(string, number, number?)
4822 * The substring function returns the substring of the first argument
4823 * starting at the position specified in the second argument with
4824 * length specified in the third argument. For example,
4825 * substring("12345",2,3) returns "234". If the third argument is not
4826 * specified, it returns the substring starting at the position specified
4827 * in the second argument and continuing to the end of the string. For
4828 * example, substring("12345",2) returns "2345". More precisely, each
4829 * character in the string (see [3.6 Strings]) is considered to have a
4830 * numeric position: the position of the first character is 1, the position
4831 * of the second character is 2 and so on. The returned substring contains
4832 * those characters for which the position of the character is greater than
4833 * or equal to the second argument and, if the third argument is specified,
4834 * less than the sum of the second and third arguments; the comparisons
4835 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4836 * - substring("12345", 1.5, 2.6) returns "234"
4837 * - substring("12345", 0, 3) returns "12"
4838 * - substring("12345", 0 div 0, 3) returns ""
4839 * - substring("12345", 1, 0 div 0) returns ""
4840 * - substring("12345", -42, 1 div 0) returns "12345"
4841 * - substring("12345", -1 div 0, 1 div 0) returns ""
4842 */
4843void
4844xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4845 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00004846 double le=0, in;
4847 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00004848 xmlChar *ret;
4849
Owen Taylor3473f882001-02-23 17:55:21 +00004850 if (nargs < 2) {
4851 CHECK_ARITY(2);
4852 }
4853 if (nargs > 3) {
4854 CHECK_ARITY(3);
4855 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00004856 /*
4857 * take care of possible last (position) argument
4858 */
Owen Taylor3473f882001-02-23 17:55:21 +00004859 if (nargs == 3) {
4860 CAST_TO_NUMBER;
4861 CHECK_TYPE(XPATH_NUMBER);
4862 len = valuePop(ctxt);
4863 le = len->floatval;
4864 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00004865 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00004866
Owen Taylor3473f882001-02-23 17:55:21 +00004867 CAST_TO_NUMBER;
4868 CHECK_TYPE(XPATH_NUMBER);
4869 start = valuePop(ctxt);
4870 in = start->floatval;
4871 xmlXPathFreeObject(start);
4872 CAST_TO_STRING;
4873 CHECK_TYPE(XPATH_STRING);
4874 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00004875 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00004876
Daniel Veillard97ac1312001-05-30 19:14:17 +00004877 /*
4878 * If last pos not present, calculate last position
4879 */
4880 if (nargs != 3)
4881 le = m;
4882
4883 /*
4884 * To meet our requirements, initial index calculations
4885 * must be done before we convert to integer format
4886 *
4887 * First we normalize indices
4888 */
4889 in -= 1.0;
4890 le += in;
4891 if (in < 0.0)
4892 in = 0.0;
4893 if (le > (double)m)
4894 le = (double)m;
4895
4896 /*
4897 * Now we go to integer form, rounding up
4898 */
Owen Taylor3473f882001-02-23 17:55:21 +00004899 i = (int) in;
4900 if (((double)i) != in) i++;
4901
Owen Taylor3473f882001-02-23 17:55:21 +00004902 l = (int) le;
4903 if (((double)l) != le) l++;
4904
Daniel Veillard97ac1312001-05-30 19:14:17 +00004905 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00004906
4907 /* number of chars to copy */
4908 l -= i;
4909
Daniel Veillard97ac1312001-05-30 19:14:17 +00004910 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00004911 if (ret == NULL)
4912 valuePush(ctxt, xmlXPathNewCString(""));
4913 else {
4914 valuePush(ctxt, xmlXPathNewString(ret));
4915 xmlFree(ret);
4916 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00004917
Owen Taylor3473f882001-02-23 17:55:21 +00004918 xmlXPathFreeObject(str);
4919}
4920
4921/**
4922 * xmlXPathSubstringBeforeFunction:
4923 * @ctxt: the XPath Parser context
4924 * @nargs: the number of arguments
4925 *
4926 * Implement the substring-before() XPath function
4927 * string substring-before(string, string)
4928 * The substring-before function returns the substring of the first
4929 * argument string that precedes the first occurrence of the second
4930 * argument string in the first argument string, or the empty string
4931 * if the first argument string does not contain the second argument
4932 * string. For example, substring-before("1999/04/01","/") returns 1999.
4933 */
4934void
4935xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4936 xmlXPathObjectPtr str;
4937 xmlXPathObjectPtr find;
4938 xmlBufferPtr target;
4939 const xmlChar *point;
4940 int offset;
4941
4942 CHECK_ARITY(2);
4943 CAST_TO_STRING;
4944 find = valuePop(ctxt);
4945 CAST_TO_STRING;
4946 str = valuePop(ctxt);
4947
4948 target = xmlBufferCreate();
4949 if (target) {
4950 point = xmlStrstr(str->stringval, find->stringval);
4951 if (point) {
4952 offset = (int)(point - str->stringval);
4953 xmlBufferAdd(target, str->stringval, offset);
4954 }
4955 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4956 xmlBufferFree(target);
4957 }
4958
4959 xmlXPathFreeObject(str);
4960 xmlXPathFreeObject(find);
4961}
4962
4963/**
4964 * xmlXPathSubstringAfterFunction:
4965 * @ctxt: the XPath Parser context
4966 * @nargs: the number of arguments
4967 *
4968 * Implement the substring-after() XPath function
4969 * string substring-after(string, string)
4970 * The substring-after function returns the substring of the first
4971 * argument string that follows the first occurrence of the second
4972 * argument string in the first argument string, or the empty stringi
4973 * if the first argument string does not contain the second argument
4974 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4975 * and substring-after("1999/04/01","19") returns 99/04/01.
4976 */
4977void
4978xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4979 xmlXPathObjectPtr str;
4980 xmlXPathObjectPtr find;
4981 xmlBufferPtr target;
4982 const xmlChar *point;
4983 int offset;
4984
4985 CHECK_ARITY(2);
4986 CAST_TO_STRING;
4987 find = valuePop(ctxt);
4988 CAST_TO_STRING;
4989 str = valuePop(ctxt);
4990
4991 target = xmlBufferCreate();
4992 if (target) {
4993 point = xmlStrstr(str->stringval, find->stringval);
4994 if (point) {
4995 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4996 xmlBufferAdd(target, &str->stringval[offset],
4997 xmlStrlen(str->stringval) - offset);
4998 }
4999 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5000 xmlBufferFree(target);
5001 }
5002
5003 xmlXPathFreeObject(str);
5004 xmlXPathFreeObject(find);
5005}
5006
5007/**
5008 * xmlXPathNormalizeFunction:
5009 * @ctxt: the XPath Parser context
5010 * @nargs: the number of arguments
5011 *
5012 * Implement the normalize-space() XPath function
5013 * string normalize-space(string?)
5014 * The normalize-space function returns the argument string with white
5015 * space normalized by stripping leading and trailing whitespace
5016 * and replacing sequences of whitespace characters by a single
5017 * space. Whitespace characters are the same allowed by the S production
5018 * in XML. If the argument is omitted, it defaults to the context
5019 * node converted to a string, in other words the value of the context node.
5020 */
5021void
5022xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5023 xmlXPathObjectPtr obj = NULL;
5024 xmlChar *source = NULL;
5025 xmlBufferPtr target;
5026 xmlChar blank;
5027
5028 if (nargs == 0) {
5029 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005030 valuePush(ctxt,
5031 xmlXPathWrapString(
5032 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005033 nargs = 1;
5034 }
5035
5036 CHECK_ARITY(1);
5037 CAST_TO_STRING;
5038 CHECK_TYPE(XPATH_STRING);
5039 obj = valuePop(ctxt);
5040 source = obj->stringval;
5041
5042 target = xmlBufferCreate();
5043 if (target && source) {
5044
5045 /* Skip leading whitespaces */
5046 while (IS_BLANK(*source))
5047 source++;
5048
5049 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5050 blank = 0;
5051 while (*source) {
5052 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005053 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005054 } else {
5055 if (blank) {
5056 xmlBufferAdd(target, &blank, 1);
5057 blank = 0;
5058 }
5059 xmlBufferAdd(target, source, 1);
5060 }
5061 source++;
5062 }
5063
5064 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5065 xmlBufferFree(target);
5066 }
5067 xmlXPathFreeObject(obj);
5068}
5069
5070/**
5071 * xmlXPathTranslateFunction:
5072 * @ctxt: the XPath Parser context
5073 * @nargs: the number of arguments
5074 *
5075 * Implement the translate() XPath function
5076 * string translate(string, string, string)
5077 * The translate function returns the first argument string with
5078 * occurrences of characters in the second argument string replaced
5079 * by the character at the corresponding position in the third argument
5080 * string. For example, translate("bar","abc","ABC") returns the string
5081 * BAr. If there is a character in the second argument string with no
5082 * character at a corresponding position in the third argument string
5083 * (because the second argument string is longer than the third argument
5084 * string), then occurrences of that character in the first argument
5085 * string are removed. For example, translate("--aaa--","abc-","ABC")
5086 * returns "AAA". If a character occurs more than once in second
5087 * argument string, then the first occurrence determines the replacement
5088 * character. If the third argument string is longer than the second
5089 * argument string, then excess characters are ignored.
5090 */
5091void
5092xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005093 xmlXPathObjectPtr str;
5094 xmlXPathObjectPtr from;
5095 xmlXPathObjectPtr to;
5096 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005097 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005098 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005099 xmlChar *point;
5100 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005101
Daniel Veillarde043ee12001-04-16 14:08:07 +00005102 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005103
Daniel Veillarde043ee12001-04-16 14:08:07 +00005104 CAST_TO_STRING;
5105 to = valuePop(ctxt);
5106 CAST_TO_STRING;
5107 from = valuePop(ctxt);
5108 CAST_TO_STRING;
5109 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005110
Daniel Veillarde043ee12001-04-16 14:08:07 +00005111 target = xmlBufferCreate();
5112 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005113 max = xmlUTF8Strlen(to->stringval);
5114 for (cptr = str->stringval; (ch=*cptr); ) {
5115 offset = xmlUTF8Strloc(from->stringval, cptr);
5116 if (offset >= 0) {
5117 if (offset < max) {
5118 point = xmlUTF8Strpos(to->stringval, offset);
5119 if (point)
5120 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5121 }
5122 } else
5123 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5124
5125 /* Step to next character in input */
5126 cptr++;
5127 if ( ch & 0x80 ) {
5128 /* if not simple ascii, verify proper format */
5129 if ( (ch & 0xc0) != 0xc0 ) {
5130 xmlGenericError(xmlGenericErrorContext,
5131 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5132 break;
5133 }
5134 /* then skip over remaining bytes for this char */
5135 while ( (ch <<= 1) & 0x80 )
5136 if ( (*cptr++ & 0xc0) != 0x80 ) {
5137 xmlGenericError(xmlGenericErrorContext,
5138 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5139 break;
5140 }
5141 if (ch & 0x80) /* must have had error encountered */
5142 break;
5143 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005144 }
Owen Taylor3473f882001-02-23 17:55:21 +00005145 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005146 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5147 xmlBufferFree(target);
5148 xmlXPathFreeObject(str);
5149 xmlXPathFreeObject(from);
5150 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005151}
5152
5153/**
5154 * xmlXPathBooleanFunction:
5155 * @ctxt: the XPath Parser context
5156 * @nargs: the number of arguments
5157 *
5158 * Implement the boolean() XPath function
5159 * boolean boolean(object)
5160 * he boolean function converts its argument to a boolean as follows:
5161 * - a number is true if and only if it is neither positive or
5162 * negative zero nor NaN
5163 * - a node-set is true if and only if it is non-empty
5164 * - a string is true if and only if its length is non-zero
5165 */
5166void
5167xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5168 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005169
5170 CHECK_ARITY(1);
5171 cur = valuePop(ctxt);
5172 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005173 cur = xmlXPathConvertBoolean(cur);
5174 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005175}
5176
5177/**
5178 * xmlXPathNotFunction:
5179 * @ctxt: the XPath Parser context
5180 * @nargs: the number of arguments
5181 *
5182 * Implement the not() XPath function
5183 * boolean not(boolean)
5184 * The not function returns true if its argument is false,
5185 * and false otherwise.
5186 */
5187void
5188xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5189 CHECK_ARITY(1);
5190 CAST_TO_BOOLEAN;
5191 CHECK_TYPE(XPATH_BOOLEAN);
5192 ctxt->value->boolval = ! ctxt->value->boolval;
5193}
5194
5195/**
5196 * xmlXPathTrueFunction:
5197 * @ctxt: the XPath Parser context
5198 * @nargs: the number of arguments
5199 *
5200 * Implement the true() XPath function
5201 * boolean true()
5202 */
5203void
5204xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5205 CHECK_ARITY(0);
5206 valuePush(ctxt, xmlXPathNewBoolean(1));
5207}
5208
5209/**
5210 * xmlXPathFalseFunction:
5211 * @ctxt: the XPath Parser context
5212 * @nargs: the number of arguments
5213 *
5214 * Implement the false() XPath function
5215 * boolean false()
5216 */
5217void
5218xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5219 CHECK_ARITY(0);
5220 valuePush(ctxt, xmlXPathNewBoolean(0));
5221}
5222
5223/**
5224 * xmlXPathLangFunction:
5225 * @ctxt: the XPath Parser context
5226 * @nargs: the number of arguments
5227 *
5228 * Implement the lang() XPath function
5229 * boolean lang(string)
5230 * The lang function returns true or false depending on whether the
5231 * language of the context node as specified by xml:lang attributes
5232 * is the same as or is a sublanguage of the language specified by
5233 * the argument string. The language of the context node is determined
5234 * by the value of the xml:lang attribute on the context node, or, if
5235 * the context node has no xml:lang attribute, by the value of the
5236 * xml:lang attribute on the nearest ancestor of the context node that
5237 * has an xml:lang attribute. If there is no such attribute, then lang
5238 * returns false. If there is such an attribute, then lang returns
5239 * true if the attribute value is equal to the argument ignoring case,
5240 * or if there is some suffix starting with - such that the attribute
5241 * value is equal to the argument ignoring that suffix of the attribute
5242 * value and ignoring case.
5243 */
5244void
5245xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5246 xmlXPathObjectPtr val;
5247 const xmlChar *theLang;
5248 const xmlChar *lang;
5249 int ret = 0;
5250 int i;
5251
5252 CHECK_ARITY(1);
5253 CAST_TO_STRING;
5254 CHECK_TYPE(XPATH_STRING);
5255 val = valuePop(ctxt);
5256 lang = val->stringval;
5257 theLang = xmlNodeGetLang(ctxt->context->node);
5258 if ((theLang != NULL) && (lang != NULL)) {
5259 for (i = 0;lang[i] != 0;i++)
5260 if (toupper(lang[i]) != toupper(theLang[i]))
5261 goto not_equal;
5262 ret = 1;
5263 }
5264not_equal:
5265 xmlXPathFreeObject(val);
5266 valuePush(ctxt, xmlXPathNewBoolean(ret));
5267}
5268
5269/**
5270 * xmlXPathNumberFunction:
5271 * @ctxt: the XPath Parser context
5272 * @nargs: the number of arguments
5273 *
5274 * Implement the number() XPath function
5275 * number number(object?)
5276 */
5277void
5278xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5279 xmlXPathObjectPtr cur;
5280 double res;
5281
5282 if (nargs == 0) {
5283 if (ctxt->context->node == NULL) {
5284 valuePush(ctxt, xmlXPathNewFloat(0.0));
5285 } else {
5286 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
5287
5288 res = xmlXPathStringEvalNumber(content);
5289 valuePush(ctxt, xmlXPathNewFloat(res));
5290 xmlFree(content);
5291 }
5292 return;
5293 }
5294
5295 CHECK_ARITY(1);
5296 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005297 cur = xmlXPathConvertNumber(cur);
5298 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005299}
5300
5301/**
5302 * xmlXPathSumFunction:
5303 * @ctxt: the XPath Parser context
5304 * @nargs: the number of arguments
5305 *
5306 * Implement the sum() XPath function
5307 * number sum(node-set)
5308 * The sum function returns the sum of the values of the nodes in
5309 * the argument node-set.
5310 */
5311void
5312xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5313 xmlXPathObjectPtr cur;
5314 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005315 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00005316
5317 CHECK_ARITY(1);
5318 if ((ctxt->value == NULL) ||
5319 ((ctxt->value->type != XPATH_NODESET) &&
5320 (ctxt->value->type != XPATH_XSLT_TREE)))
5321 XP_ERROR(XPATH_INVALID_TYPE);
5322 cur = valuePop(ctxt);
5323
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005324 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005325 valuePush(ctxt, xmlXPathNewFloat(0.0));
5326 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005327 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
5328 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00005329 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005330 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00005331 }
5332 xmlXPathFreeObject(cur);
5333}
5334
5335/**
5336 * xmlXPathFloorFunction:
5337 * @ctxt: the XPath Parser context
5338 * @nargs: the number of arguments
5339 *
5340 * Implement the floor() XPath function
5341 * number floor(number)
5342 * The floor function returns the largest (closest to positive infinity)
5343 * number that is not greater than the argument and that is an integer.
5344 */
5345void
5346xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5347 CHECK_ARITY(1);
5348 CAST_TO_NUMBER;
5349 CHECK_TYPE(XPATH_NUMBER);
5350#if 0
5351 ctxt->value->floatval = floor(ctxt->value->floatval);
5352#else
5353 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5354 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5355#endif
5356}
5357
5358/**
5359 * xmlXPathCeilingFunction:
5360 * @ctxt: the XPath Parser context
5361 * @nargs: the number of arguments
5362 *
5363 * Implement the ceiling() XPath function
5364 * number ceiling(number)
5365 * The ceiling function returns the smallest (closest to negative infinity)
5366 * number that is not less than the argument and that is an integer.
5367 */
5368void
5369xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5370 double f;
5371
5372 CHECK_ARITY(1);
5373 CAST_TO_NUMBER;
5374 CHECK_TYPE(XPATH_NUMBER);
5375
5376#if 0
5377 ctxt->value->floatval = ceil(ctxt->value->floatval);
5378#else
5379 f = (double)((int) ctxt->value->floatval);
5380 if (f != ctxt->value->floatval)
5381 ctxt->value->floatval = f + 1;
5382#endif
5383}
5384
5385/**
5386 * xmlXPathRoundFunction:
5387 * @ctxt: the XPath Parser context
5388 * @nargs: the number of arguments
5389 *
5390 * Implement the round() XPath function
5391 * number round(number)
5392 * The round function returns the number that is closest to the
5393 * argument and that is an integer. If there are two such numbers,
5394 * then the one that is even is returned.
5395 */
5396void
5397xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5398 double f;
5399
5400 CHECK_ARITY(1);
5401 CAST_TO_NUMBER;
5402 CHECK_TYPE(XPATH_NUMBER);
5403
5404 if ((ctxt->value->floatval == xmlXPathNAN) ||
5405 (ctxt->value->floatval == xmlXPathPINF) ||
5406 (ctxt->value->floatval == xmlXPathNINF) ||
5407 (ctxt->value->floatval == 0.0))
5408 return;
5409
5410#if 0
5411 f = floor(ctxt->value->floatval);
5412#else
5413 f = (double)((int) ctxt->value->floatval);
5414#endif
5415 if (ctxt->value->floatval < f + 0.5)
5416 ctxt->value->floatval = f;
5417 else
5418 ctxt->value->floatval = f + 1;
5419}
5420
5421/************************************************************************
5422 * *
5423 * The Parser *
5424 * *
5425 ************************************************************************/
5426
5427/*
5428 * a couple of forward declarations since we use a recursive call based
5429 * implementation.
5430 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005431static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005432static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005433static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005434#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005435static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5436#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005437#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005438static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005439#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005440static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5441 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005442
5443/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005444 * xmlXPathCurrentChar:
5445 * @ctxt: the XPath parser context
5446 * @cur: pointer to the beginning of the char
5447 * @len: pointer to the length of the char read
5448 *
5449 * The current char value, if using UTF-8 this may actaully span multiple
5450 * bytes in the input buffer.
5451 *
5452 * Returns the current char value and its lenght
5453 */
5454
5455static int
5456xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5457 unsigned char c;
5458 unsigned int val;
5459 const xmlChar *cur;
5460
5461 if (ctxt == NULL)
5462 return(0);
5463 cur = ctxt->cur;
5464
5465 /*
5466 * We are supposed to handle UTF8, check it's valid
5467 * From rfc2044: encoding of the Unicode values on UTF-8:
5468 *
5469 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5470 * 0000 0000-0000 007F 0xxxxxxx
5471 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5472 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5473 *
5474 * Check for the 0x110000 limit too
5475 */
5476 c = *cur;
5477 if (c & 0x80) {
5478 if ((cur[1] & 0xc0) != 0x80)
5479 goto encoding_error;
5480 if ((c & 0xe0) == 0xe0) {
5481
5482 if ((cur[2] & 0xc0) != 0x80)
5483 goto encoding_error;
5484 if ((c & 0xf0) == 0xf0) {
5485 if (((c & 0xf8) != 0xf0) ||
5486 ((cur[3] & 0xc0) != 0x80))
5487 goto encoding_error;
5488 /* 4-byte code */
5489 *len = 4;
5490 val = (cur[0] & 0x7) << 18;
5491 val |= (cur[1] & 0x3f) << 12;
5492 val |= (cur[2] & 0x3f) << 6;
5493 val |= cur[3] & 0x3f;
5494 } else {
5495 /* 3-byte code */
5496 *len = 3;
5497 val = (cur[0] & 0xf) << 12;
5498 val |= (cur[1] & 0x3f) << 6;
5499 val |= cur[2] & 0x3f;
5500 }
5501 } else {
5502 /* 2-byte code */
5503 *len = 2;
5504 val = (cur[0] & 0x1f) << 6;
5505 val |= cur[1] & 0x3f;
5506 }
5507 if (!IS_CHAR(val)) {
5508 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5509 }
5510 return(val);
5511 } else {
5512 /* 1-byte code */
5513 *len = 1;
5514 return((int) *cur);
5515 }
5516encoding_error:
5517 /*
5518 * If we detect an UTF8 error that probably mean that the
5519 * input encoding didn't get properly advertized in the
5520 * declaration header. Report the error and switch the encoding
5521 * to ISO-Latin-1 (if you don't like this policy, just declare the
5522 * encoding !)
5523 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00005524 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00005525 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005526}
5527
5528/**
Owen Taylor3473f882001-02-23 17:55:21 +00005529 * xmlXPathParseNCName:
5530 * @ctxt: the XPath Parser context
5531 *
5532 * parse an XML namespace non qualified name.
5533 *
5534 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5535 *
5536 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5537 * CombiningChar | Extender
5538 *
5539 * Returns the namespace name or NULL
5540 */
5541
5542xmlChar *
5543xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005544 const xmlChar *in;
5545 xmlChar *ret;
5546 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005547
Daniel Veillard2156a562001-04-28 12:24:34 +00005548 /*
5549 * Accelerator for simple ASCII names
5550 */
5551 in = ctxt->cur;
5552 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5553 ((*in >= 0x41) && (*in <= 0x5A)) ||
5554 (*in == '_')) {
5555 in++;
5556 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5557 ((*in >= 0x41) && (*in <= 0x5A)) ||
5558 ((*in >= 0x30) && (*in <= 0x39)) ||
5559 (*in == '_'))
5560 in++;
5561 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5562 (*in == '[') || (*in == ']') || (*in == ':') ||
5563 (*in == '@') || (*in == '*')) {
5564 count = in - ctxt->cur;
5565 if (count == 0)
5566 return(NULL);
5567 ret = xmlStrndup(ctxt->cur, count);
5568 ctxt->cur = in;
5569 return(ret);
5570 }
5571 }
5572 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005573}
5574
Daniel Veillard2156a562001-04-28 12:24:34 +00005575
Owen Taylor3473f882001-02-23 17:55:21 +00005576/**
5577 * xmlXPathParseQName:
5578 * @ctxt: the XPath Parser context
5579 * @prefix: a xmlChar **
5580 *
5581 * parse an XML qualified name
5582 *
5583 * [NS 5] QName ::= (Prefix ':')? LocalPart
5584 *
5585 * [NS 6] Prefix ::= NCName
5586 *
5587 * [NS 7] LocalPart ::= NCName
5588 *
5589 * Returns the function returns the local part, and prefix is updated
5590 * to get the Prefix if any.
5591 */
5592
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005593static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005594xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5595 xmlChar *ret = NULL;
5596
5597 *prefix = NULL;
5598 ret = xmlXPathParseNCName(ctxt);
5599 if (CUR == ':') {
5600 *prefix = ret;
5601 NEXT;
5602 ret = xmlXPathParseNCName(ctxt);
5603 }
5604 return(ret);
5605}
5606
5607/**
5608 * xmlXPathParseName:
5609 * @ctxt: the XPath Parser context
5610 *
5611 * parse an XML name
5612 *
5613 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5614 * CombiningChar | Extender
5615 *
5616 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5617 *
5618 * Returns the namespace name or NULL
5619 */
5620
5621xmlChar *
5622xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005623 const xmlChar *in;
5624 xmlChar *ret;
5625 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005626
Daniel Veillard61d80a22001-04-27 17:13:01 +00005627 /*
5628 * Accelerator for simple ASCII names
5629 */
5630 in = ctxt->cur;
5631 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5632 ((*in >= 0x41) && (*in <= 0x5A)) ||
5633 (*in == '_') || (*in == ':')) {
5634 in++;
5635 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5636 ((*in >= 0x41) && (*in <= 0x5A)) ||
5637 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00005638 (*in == '_') || (*in == '-') ||
5639 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00005640 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00005641 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005642 count = in - ctxt->cur;
5643 ret = xmlStrndup(ctxt->cur, count);
5644 ctxt->cur = in;
5645 return(ret);
5646 }
5647 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005648 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005649}
5650
Daniel Veillard61d80a22001-04-27 17:13:01 +00005651static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005652xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005653 xmlChar buf[XML_MAX_NAMELEN + 5];
5654 int len = 0, l;
5655 int c;
5656
5657 /*
5658 * Handler for more complex cases
5659 */
5660 c = CUR_CHAR(l);
5661 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005662 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5663 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005664 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005665 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005666 return(NULL);
5667 }
5668
5669 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5670 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5671 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005672 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005673 (IS_COMBINING(c)) ||
5674 (IS_EXTENDER(c)))) {
5675 COPY_BUF(l,buf,len,c);
5676 NEXTL(l);
5677 c = CUR_CHAR(l);
5678 if (len >= XML_MAX_NAMELEN) {
5679 /*
5680 * Okay someone managed to make a huge name, so he's ready to pay
5681 * for the processing speed.
5682 */
5683 xmlChar *buffer;
5684 int max = len * 2;
5685
5686 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5687 if (buffer == NULL) {
5688 XP_ERROR0(XPATH_MEMORY_ERROR);
5689 }
5690 memcpy(buffer, buf, len);
5691 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5692 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005693 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005694 (IS_COMBINING(c)) ||
5695 (IS_EXTENDER(c))) {
5696 if (len + 10 > max) {
5697 max *= 2;
5698 buffer = (xmlChar *) xmlRealloc(buffer,
5699 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00005700 if (buffer == NULL) {
5701 XP_ERROR0(XPATH_MEMORY_ERROR);
5702 }
5703 }
5704 COPY_BUF(l,buffer,len,c);
5705 NEXTL(l);
5706 c = CUR_CHAR(l);
5707 }
5708 buffer[len] = 0;
5709 return(buffer);
5710 }
5711 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005712 if (len == 0)
5713 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005714 return(xmlStrndup(buf, len));
5715}
Owen Taylor3473f882001-02-23 17:55:21 +00005716/**
5717 * xmlXPathStringEvalNumber:
5718 * @str: A string to scan
5719 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005720 * [30a] Float ::= Number ('e' Digits?)?
5721 *
Owen Taylor3473f882001-02-23 17:55:21 +00005722 * [30] Number ::= Digits ('.' Digits?)?
5723 * | '.' Digits
5724 * [31] Digits ::= [0-9]+
5725 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005726 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005727 * In complement of the Number expression, this function also handles
5728 * negative values : '-' Number.
5729 *
5730 * Returns the double value.
5731 */
5732double
5733xmlXPathStringEvalNumber(const xmlChar *str) {
5734 const xmlChar *cur = str;
5735 double ret = 0.0;
5736 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005737 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005738 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005739 int exponent = 0;
5740 int is_exponent_negative = 0;
5741
Owen Taylor3473f882001-02-23 17:55:21 +00005742 while (IS_BLANK(*cur)) cur++;
5743 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5744 return(xmlXPathNAN);
5745 }
5746 if (*cur == '-') {
5747 isneg = 1;
5748 cur++;
5749 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005750 /*
5751 * tmp is a workaroudn against a gcc compiler bug
5752 */
Owen Taylor3473f882001-02-23 17:55:21 +00005753 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005754 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00005755 ok = 1;
5756 cur++;
5757 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005758 ret = (double) tmp;
5759
Owen Taylor3473f882001-02-23 17:55:21 +00005760 if (*cur == '.') {
5761 cur++;
5762 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5763 return(xmlXPathNAN);
5764 }
5765 while ((*cur >= '0') && (*cur <= '9')) {
5766 mult /= 10;
5767 ret = ret + (*cur - '0') * mult;
5768 cur++;
5769 }
5770 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005771 if ((*cur == 'e') || (*cur == 'E')) {
5772 cur++;
5773 if (*cur == '-') {
5774 is_exponent_negative = 1;
5775 cur++;
5776 }
5777 while ((*cur >= '0') && (*cur <= '9')) {
5778 exponent = exponent * 10 + (*cur - '0');
5779 cur++;
5780 }
5781 }
Owen Taylor3473f882001-02-23 17:55:21 +00005782 while (IS_BLANK(*cur)) cur++;
5783 if (*cur != 0) return(xmlXPathNAN);
5784 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005785 if (is_exponent_negative) exponent = -exponent;
5786 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005787 return(ret);
5788}
5789
5790/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005791 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005792 * @ctxt: the XPath Parser context
5793 *
5794 * [30] Number ::= Digits ('.' Digits?)?
5795 * | '.' Digits
5796 * [31] Digits ::= [0-9]+
5797 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005798 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005799 *
5800 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005801static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005802xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
5803{
Owen Taylor3473f882001-02-23 17:55:21 +00005804 double ret = 0.0;
5805 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005806 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005807 int exponent = 0;
5808 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005809
5810 CHECK_ERROR;
5811 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5812 XP_ERROR(XPATH_NUMBER_ERROR);
5813 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005814 /*
5815 * Try to work around a gcc optimizer bug
5816 */
Owen Taylor3473f882001-02-23 17:55:21 +00005817 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005818 tmp = tmp * 10 + (CUR - '0');
5819 ok = 1;
5820 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00005821 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005822 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005823 if (CUR == '.') {
5824 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005825 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5826 XP_ERROR(XPATH_NUMBER_ERROR);
5827 }
5828 while ((CUR >= '0') && (CUR <= '9')) {
5829 mult /= 10;
5830 ret = ret + (CUR - '0') * mult;
5831 NEXT;
5832 }
Owen Taylor3473f882001-02-23 17:55:21 +00005833 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005834 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005835 NEXT;
5836 if (CUR == '-') {
5837 is_exponent_negative = 1;
5838 NEXT;
5839 }
5840 while ((CUR >= '0') && (CUR <= '9')) {
5841 exponent = exponent * 10 + (CUR - '0');
5842 NEXT;
5843 }
5844 if (is_exponent_negative)
5845 exponent = -exponent;
5846 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005847 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005848 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005849 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005850}
5851
5852/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005853 * xmlXPathParseLiteral:
5854 * @ctxt: the XPath Parser context
5855 *
5856 * Parse a Literal
5857 *
5858 * [29] Literal ::= '"' [^"]* '"'
5859 * | "'" [^']* "'"
5860 *
5861 * Returns the value found or NULL in case of error
5862 */
5863static xmlChar *
5864xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5865 const xmlChar *q;
5866 xmlChar *ret = NULL;
5867
5868 if (CUR == '"') {
5869 NEXT;
5870 q = CUR_PTR;
5871 while ((IS_CHAR(CUR)) && (CUR != '"'))
5872 NEXT;
5873 if (!IS_CHAR(CUR)) {
5874 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5875 } else {
5876 ret = xmlStrndup(q, CUR_PTR - q);
5877 NEXT;
5878 }
5879 } else if (CUR == '\'') {
5880 NEXT;
5881 q = CUR_PTR;
5882 while ((IS_CHAR(CUR)) && (CUR != '\''))
5883 NEXT;
5884 if (!IS_CHAR(CUR)) {
5885 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5886 } else {
5887 ret = xmlStrndup(q, CUR_PTR - q);
5888 NEXT;
5889 }
5890 } else {
5891 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5892 }
5893 return(ret);
5894}
5895
5896/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005897 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005898 * @ctxt: the XPath Parser context
5899 *
5900 * Parse a Literal and push it on the stack.
5901 *
5902 * [29] Literal ::= '"' [^"]* '"'
5903 * | "'" [^']* "'"
5904 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005905 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005906 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005907static void
5908xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005909 const xmlChar *q;
5910 xmlChar *ret = NULL;
5911
5912 if (CUR == '"') {
5913 NEXT;
5914 q = CUR_PTR;
5915 while ((IS_CHAR(CUR)) && (CUR != '"'))
5916 NEXT;
5917 if (!IS_CHAR(CUR)) {
5918 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5919 } else {
5920 ret = xmlStrndup(q, CUR_PTR - q);
5921 NEXT;
5922 }
5923 } else if (CUR == '\'') {
5924 NEXT;
5925 q = CUR_PTR;
5926 while ((IS_CHAR(CUR)) && (CUR != '\''))
5927 NEXT;
5928 if (!IS_CHAR(CUR)) {
5929 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5930 } else {
5931 ret = xmlStrndup(q, CUR_PTR - q);
5932 NEXT;
5933 }
5934 } else {
5935 XP_ERROR(XPATH_START_LITERAL_ERROR);
5936 }
5937 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005938 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5939 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005940 xmlFree(ret);
5941}
5942
5943/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005944 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005945 * @ctxt: the XPath Parser context
5946 *
5947 * Parse a VariableReference, evaluate it and push it on the stack.
5948 *
5949 * The variable bindings consist of a mapping from variable names
5950 * to variable values. The value of a variable is an object, which
5951 * of any of the types that are possible for the value of an expression,
5952 * and may also be of additional types not specified here.
5953 *
5954 * Early evaluation is possible since:
5955 * The variable bindings [...] used to evaluate a subexpression are
5956 * always the same as those used to evaluate the containing expression.
5957 *
5958 * [36] VariableReference ::= '$' QName
5959 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005960static void
5961xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005962 xmlChar *name;
5963 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005964
5965 SKIP_BLANKS;
5966 if (CUR != '$') {
5967 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5968 }
5969 NEXT;
5970 name = xmlXPathParseQName(ctxt, &prefix);
5971 if (name == NULL) {
5972 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5973 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005974 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005975 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5976 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005977 SKIP_BLANKS;
5978}
5979
5980/**
5981 * xmlXPathIsNodeType:
5982 * @ctxt: the XPath Parser context
5983 * @name: a name string
5984 *
5985 * Is the name given a NodeType one.
5986 *
5987 * [38] NodeType ::= 'comment'
5988 * | 'text'
5989 * | 'processing-instruction'
5990 * | 'node'
5991 *
5992 * Returns 1 if true 0 otherwise
5993 */
5994int
5995xmlXPathIsNodeType(const xmlChar *name) {
5996 if (name == NULL)
5997 return(0);
5998
5999 if (xmlStrEqual(name, BAD_CAST "comment"))
6000 return(1);
6001 if (xmlStrEqual(name, BAD_CAST "text"))
6002 return(1);
6003 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6004 return(1);
6005 if (xmlStrEqual(name, BAD_CAST "node"))
6006 return(1);
6007 return(0);
6008}
6009
6010/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006011 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006012 * @ctxt: the XPath Parser context
6013 *
6014 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6015 * [17] Argument ::= Expr
6016 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006017 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006018 * pushed on the stack
6019 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006020static void
6021xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006022 xmlChar *name;
6023 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006024 int nbargs = 0;
6025
6026 name = xmlXPathParseQName(ctxt, &prefix);
6027 if (name == NULL) {
6028 XP_ERROR(XPATH_EXPR_ERROR);
6029 }
6030 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006031#ifdef DEBUG_EXPR
6032 if (prefix == NULL)
6033 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6034 name);
6035 else
6036 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6037 prefix, name);
6038#endif
6039
Owen Taylor3473f882001-02-23 17:55:21 +00006040 if (CUR != '(') {
6041 XP_ERROR(XPATH_EXPR_ERROR);
6042 }
6043 NEXT;
6044 SKIP_BLANKS;
6045
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006046 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006047 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006048 int op1 = ctxt->comp->last;
6049 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006050 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006051 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006052 nbargs++;
6053 if (CUR == ')') break;
6054 if (CUR != ',') {
6055 XP_ERROR(XPATH_EXPR_ERROR);
6056 }
6057 NEXT;
6058 SKIP_BLANKS;
6059 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006060 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6061 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006062 NEXT;
6063 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006064}
6065
6066/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006067 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006068 * @ctxt: the XPath Parser context
6069 *
6070 * [15] PrimaryExpr ::= VariableReference
6071 * | '(' Expr ')'
6072 * | Literal
6073 * | Number
6074 * | FunctionCall
6075 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006076 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006077 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006078static void
6079xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006080 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006081 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006082 else if (CUR == '(') {
6083 NEXT;
6084 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006085 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006086 if (CUR != ')') {
6087 XP_ERROR(XPATH_EXPR_ERROR);
6088 }
6089 NEXT;
6090 SKIP_BLANKS;
6091 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006092 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006093 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006094 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006095 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006096 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006097 }
6098 SKIP_BLANKS;
6099}
6100
6101/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006102 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006103 * @ctxt: the XPath Parser context
6104 *
6105 * [20] FilterExpr ::= PrimaryExpr
6106 * | FilterExpr Predicate
6107 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006108 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006109 * Square brackets are used to filter expressions in the same way that
6110 * they are used in location paths. It is an error if the expression to
6111 * be filtered does not evaluate to a node-set. The context node list
6112 * used for evaluating the expression in square brackets is the node-set
6113 * to be filtered listed in document order.
6114 */
6115
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006116static void
6117xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6118 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006119 CHECK_ERROR;
6120 SKIP_BLANKS;
6121
6122 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006123 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006124 SKIP_BLANKS;
6125 }
6126
6127
6128}
6129
6130/**
6131 * xmlXPathScanName:
6132 * @ctxt: the XPath Parser context
6133 *
6134 * Trickery: parse an XML name but without consuming the input flow
6135 * Needed to avoid insanity in the parser state.
6136 *
6137 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6138 * CombiningChar | Extender
6139 *
6140 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6141 *
6142 * [6] Names ::= Name (S Name)*
6143 *
6144 * Returns the Name parsed or NULL
6145 */
6146
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006147static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006148xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6149 xmlChar buf[XML_MAX_NAMELEN];
6150 int len = 0;
6151
6152 SKIP_BLANKS;
6153 if (!IS_LETTER(CUR) && (CUR != '_') &&
6154 (CUR != ':')) {
6155 return(NULL);
6156 }
6157
6158 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6159 (NXT(len) == '.') || (NXT(len) == '-') ||
6160 (NXT(len) == '_') || (NXT(len) == ':') ||
6161 (IS_COMBINING(NXT(len))) ||
6162 (IS_EXTENDER(NXT(len)))) {
6163 buf[len] = NXT(len);
6164 len++;
6165 if (len >= XML_MAX_NAMELEN) {
6166 xmlGenericError(xmlGenericErrorContext,
6167 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6168 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6169 (NXT(len) == '.') || (NXT(len) == '-') ||
6170 (NXT(len) == '_') || (NXT(len) == ':') ||
6171 (IS_COMBINING(NXT(len))) ||
6172 (IS_EXTENDER(NXT(len))))
6173 len++;
6174 break;
6175 }
6176 }
6177 return(xmlStrndup(buf, len));
6178}
6179
6180/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006181 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006182 * @ctxt: the XPath Parser context
6183 *
6184 * [19] PathExpr ::= LocationPath
6185 * | FilterExpr
6186 * | FilterExpr '/' RelativeLocationPath
6187 * | FilterExpr '//' RelativeLocationPath
6188 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006189 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006190 * The / operator and // operators combine an arbitrary expression
6191 * and a relative location path. It is an error if the expression
6192 * does not evaluate to a node-set.
6193 * The / operator does composition in the same way as when / is
6194 * used in a location path. As in location paths, // is short for
6195 * /descendant-or-self::node()/.
6196 */
6197
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006198static void
6199xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006200 int lc = 1; /* Should we branch to LocationPath ? */
6201 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6202
6203 SKIP_BLANKS;
6204 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6205 (CUR == '\'') || (CUR == '"')) {
6206 lc = 0;
6207 } else if (CUR == '*') {
6208 /* relative or absolute location path */
6209 lc = 1;
6210 } else if (CUR == '/') {
6211 /* relative or absolute location path */
6212 lc = 1;
6213 } else if (CUR == '@') {
6214 /* relative abbreviated attribute location path */
6215 lc = 1;
6216 } else if (CUR == '.') {
6217 /* relative abbreviated attribute location path */
6218 lc = 1;
6219 } else {
6220 /*
6221 * Problem is finding if we have a name here whether it's:
6222 * - a nodetype
6223 * - a function call in which case it's followed by '('
6224 * - an axis in which case it's followed by ':'
6225 * - a element name
6226 * We do an a priori analysis here rather than having to
6227 * maintain parsed token content through the recursive function
6228 * calls. This looks uglier but makes the code quite easier to
6229 * read/write/debug.
6230 */
6231 SKIP_BLANKS;
6232 name = xmlXPathScanName(ctxt);
6233 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6234#ifdef DEBUG_STEP
6235 xmlGenericError(xmlGenericErrorContext,
6236 "PathExpr: Axis\n");
6237#endif
6238 lc = 1;
6239 xmlFree(name);
6240 } else if (name != NULL) {
6241 int len =xmlStrlen(name);
6242 int blank = 0;
6243
6244
6245 while (NXT(len) != 0) {
6246 if (NXT(len) == '/') {
6247 /* element name */
6248#ifdef DEBUG_STEP
6249 xmlGenericError(xmlGenericErrorContext,
6250 "PathExpr: AbbrRelLocation\n");
6251#endif
6252 lc = 1;
6253 break;
6254 } else if (IS_BLANK(NXT(len))) {
6255 /* skip to next */
6256 blank = 1;
6257 } else if (NXT(len) == ':') {
6258#ifdef DEBUG_STEP
6259 xmlGenericError(xmlGenericErrorContext,
6260 "PathExpr: AbbrRelLocation\n");
6261#endif
6262 lc = 1;
6263 break;
6264 } else if ((NXT(len) == '(')) {
6265 /* Note Type or Function */
6266 if (xmlXPathIsNodeType(name)) {
6267#ifdef DEBUG_STEP
6268 xmlGenericError(xmlGenericErrorContext,
6269 "PathExpr: Type search\n");
6270#endif
6271 lc = 1;
6272 } else {
6273#ifdef DEBUG_STEP
6274 xmlGenericError(xmlGenericErrorContext,
6275 "PathExpr: function call\n");
6276#endif
6277 lc = 0;
6278 }
6279 break;
6280 } else if ((NXT(len) == '[')) {
6281 /* element name */
6282#ifdef DEBUG_STEP
6283 xmlGenericError(xmlGenericErrorContext,
6284 "PathExpr: AbbrRelLocation\n");
6285#endif
6286 lc = 1;
6287 break;
6288 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6289 (NXT(len) == '=')) {
6290 lc = 1;
6291 break;
6292 } else {
6293 lc = 1;
6294 break;
6295 }
6296 len++;
6297 }
6298 if (NXT(len) == 0) {
6299#ifdef DEBUG_STEP
6300 xmlGenericError(xmlGenericErrorContext,
6301 "PathExpr: AbbrRelLocation\n");
6302#endif
6303 /* element name */
6304 lc = 1;
6305 }
6306 xmlFree(name);
6307 } else {
6308 /* make sure all cases are covered explicitely */
6309 XP_ERROR(XPATH_EXPR_ERROR);
6310 }
6311 }
6312
6313 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006314 if (CUR == '/') {
6315 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6316 } else {
6317 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006318 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006319 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006320 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006321 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006322 CHECK_ERROR;
6323 if ((CUR == '/') && (NXT(1) == '/')) {
6324 SKIP(2);
6325 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006326
6327 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6328 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6329 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6330
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006331 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006332 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006333 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006334 }
6335 }
6336 SKIP_BLANKS;
6337}
6338
6339/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006340 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006341 * @ctxt: the XPath Parser context
6342 *
6343 * [18] UnionExpr ::= PathExpr
6344 * | UnionExpr '|' PathExpr
6345 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006346 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006347 */
6348
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006349static void
6350xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6351 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006352 CHECK_ERROR;
6353 SKIP_BLANKS;
6354 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006355 int op1 = ctxt->comp->last;
6356 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006357
6358 NEXT;
6359 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006360 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006361
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006362 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6363
Owen Taylor3473f882001-02-23 17:55:21 +00006364 SKIP_BLANKS;
6365 }
Owen Taylor3473f882001-02-23 17:55:21 +00006366}
6367
6368/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006369 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006370 * @ctxt: the XPath Parser context
6371 *
6372 * [27] UnaryExpr ::= UnionExpr
6373 * | '-' UnaryExpr
6374 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006375 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006376 */
6377
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006378static void
6379xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006380 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006381 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006382
6383 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006384 while (CUR == '-') {
6385 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006386 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006387 NEXT;
6388 SKIP_BLANKS;
6389 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006390
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006391 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006392 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006393 if (found) {
6394 if (minus)
6395 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6396 else
6397 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006398 }
6399}
6400
6401/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006402 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006403 * @ctxt: the XPath Parser context
6404 *
6405 * [26] MultiplicativeExpr ::= UnaryExpr
6406 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6407 * | MultiplicativeExpr 'div' UnaryExpr
6408 * | MultiplicativeExpr 'mod' UnaryExpr
6409 * [34] MultiplyOperator ::= '*'
6410 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006411 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006412 */
6413
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006414static void
6415xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6416 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006417 CHECK_ERROR;
6418 SKIP_BLANKS;
6419 while ((CUR == '*') ||
6420 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6421 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6422 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006423 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006424
6425 if (CUR == '*') {
6426 op = 0;
6427 NEXT;
6428 } else if (CUR == 'd') {
6429 op = 1;
6430 SKIP(3);
6431 } else if (CUR == 'm') {
6432 op = 2;
6433 SKIP(3);
6434 }
6435 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006436 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006437 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006438 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006439 SKIP_BLANKS;
6440 }
6441}
6442
6443/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006444 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006445 * @ctxt: the XPath Parser context
6446 *
6447 * [25] AdditiveExpr ::= MultiplicativeExpr
6448 * | AdditiveExpr '+' MultiplicativeExpr
6449 * | AdditiveExpr '-' MultiplicativeExpr
6450 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006451 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006452 */
6453
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006454static void
6455xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006456
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006457 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006458 CHECK_ERROR;
6459 SKIP_BLANKS;
6460 while ((CUR == '+') || (CUR == '-')) {
6461 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006462 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006463
6464 if (CUR == '+') plus = 1;
6465 else plus = 0;
6466 NEXT;
6467 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006468 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006469 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006470 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006471 SKIP_BLANKS;
6472 }
6473}
6474
6475/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006476 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006477 * @ctxt: the XPath Parser context
6478 *
6479 * [24] RelationalExpr ::= AdditiveExpr
6480 * | RelationalExpr '<' AdditiveExpr
6481 * | RelationalExpr '>' AdditiveExpr
6482 * | RelationalExpr '<=' AdditiveExpr
6483 * | RelationalExpr '>=' AdditiveExpr
6484 *
6485 * A <= B > C is allowed ? Answer from James, yes with
6486 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6487 * which is basically what got implemented.
6488 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006489 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006490 * on the stack
6491 */
6492
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006493static void
6494xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6495 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006496 CHECK_ERROR;
6497 SKIP_BLANKS;
6498 while ((CUR == '<') ||
6499 (CUR == '>') ||
6500 ((CUR == '<') && (NXT(1) == '=')) ||
6501 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006502 int inf, strict;
6503 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006504
6505 if (CUR == '<') inf = 1;
6506 else inf = 0;
6507 if (NXT(1) == '=') strict = 0;
6508 else strict = 1;
6509 NEXT;
6510 if (!strict) NEXT;
6511 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006512 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006513 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006514 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006515 SKIP_BLANKS;
6516 }
6517}
6518
6519/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006520 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006521 * @ctxt: the XPath Parser context
6522 *
6523 * [23] EqualityExpr ::= RelationalExpr
6524 * | EqualityExpr '=' RelationalExpr
6525 * | EqualityExpr '!=' RelationalExpr
6526 *
6527 * A != B != C is allowed ? Answer from James, yes with
6528 * (RelationalExpr = RelationalExpr) = RelationalExpr
6529 * (RelationalExpr != RelationalExpr) != RelationalExpr
6530 * which is basically what got implemented.
6531 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006532 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006533 *
6534 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006535static void
6536xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6537 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006538 CHECK_ERROR;
6539 SKIP_BLANKS;
6540 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006541 int eq;
6542 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006543
6544 if (CUR == '=') eq = 1;
6545 else eq = 0;
6546 NEXT;
6547 if (!eq) NEXT;
6548 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006549 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006550 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006551 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006552 SKIP_BLANKS;
6553 }
6554}
6555
6556/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006557 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006558 * @ctxt: the XPath Parser context
6559 *
6560 * [22] AndExpr ::= EqualityExpr
6561 * | AndExpr 'and' EqualityExpr
6562 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006563 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006564 *
6565 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006566static void
6567xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6568 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006569 CHECK_ERROR;
6570 SKIP_BLANKS;
6571 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006572 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006573 SKIP(3);
6574 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006575 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006576 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006577 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006578 SKIP_BLANKS;
6579 }
6580}
6581
6582/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006583 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006584 * @ctxt: the XPath Parser context
6585 *
6586 * [14] Expr ::= OrExpr
6587 * [21] OrExpr ::= AndExpr
6588 * | OrExpr 'or' AndExpr
6589 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006590 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006591 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006592static void
6593xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6594 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006595 CHECK_ERROR;
6596 SKIP_BLANKS;
6597 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006598 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006599 SKIP(2);
6600 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006601 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006602 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006603 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6604 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006605 SKIP_BLANKS;
6606 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006607 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6608 /* more ops could be optimized too */
6609 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6610 }
Owen Taylor3473f882001-02-23 17:55:21 +00006611}
6612
6613/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006614 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006615 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006616 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006617 *
6618 * [8] Predicate ::= '[' PredicateExpr ']'
6619 * [9] PredicateExpr ::= Expr
6620 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006621 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006622 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006623static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006624xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006625 int op1 = ctxt->comp->last;
6626
6627 SKIP_BLANKS;
6628 if (CUR != '[') {
6629 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6630 }
6631 NEXT;
6632 SKIP_BLANKS;
6633
6634 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006635 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006636 CHECK_ERROR;
6637
6638 if (CUR != ']') {
6639 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6640 }
6641
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006642 if (filter)
6643 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6644 else
6645 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006646
6647 NEXT;
6648 SKIP_BLANKS;
6649}
6650
6651/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006652 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006653 * @ctxt: the XPath Parser context
6654 * @test: pointer to a xmlXPathTestVal
6655 * @type: pointer to a xmlXPathTypeVal
6656 * @prefix: placeholder for a possible name prefix
6657 *
6658 * [7] NodeTest ::= NameTest
6659 * | NodeType '(' ')'
6660 * | 'processing-instruction' '(' Literal ')'
6661 *
6662 * [37] NameTest ::= '*'
6663 * | NCName ':' '*'
6664 * | QName
6665 * [38] NodeType ::= 'comment'
6666 * | 'text'
6667 * | 'processing-instruction'
6668 * | 'node'
6669 *
6670 * Returns the name found and update @test, @type and @prefix appropriately
6671 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006672static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006673xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6674 xmlXPathTypeVal *type, const xmlChar **prefix,
6675 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006676 int blanks;
6677
6678 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6679 STRANGE;
6680 return(NULL);
6681 }
6682 *type = 0;
6683 *test = 0;
6684 *prefix = NULL;
6685 SKIP_BLANKS;
6686
6687 if ((name == NULL) && (CUR == '*')) {
6688 /*
6689 * All elements
6690 */
6691 NEXT;
6692 *test = NODE_TEST_ALL;
6693 return(NULL);
6694 }
6695
6696 if (name == NULL)
6697 name = xmlXPathParseNCName(ctxt);
6698 if (name == NULL) {
6699 XP_ERROR0(XPATH_EXPR_ERROR);
6700 }
6701
6702 blanks = IS_BLANK(CUR);
6703 SKIP_BLANKS;
6704 if (CUR == '(') {
6705 NEXT;
6706 /*
6707 * NodeType or PI search
6708 */
6709 if (xmlStrEqual(name, BAD_CAST "comment"))
6710 *type = NODE_TYPE_COMMENT;
6711 else if (xmlStrEqual(name, BAD_CAST "node"))
6712 *type = NODE_TYPE_NODE;
6713 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6714 *type = NODE_TYPE_PI;
6715 else if (xmlStrEqual(name, BAD_CAST "text"))
6716 *type = NODE_TYPE_TEXT;
6717 else {
6718 if (name != NULL)
6719 xmlFree(name);
6720 XP_ERROR0(XPATH_EXPR_ERROR);
6721 }
6722
6723 *test = NODE_TEST_TYPE;
6724
6725 SKIP_BLANKS;
6726 if (*type == NODE_TYPE_PI) {
6727 /*
6728 * Specific case: search a PI by name.
6729 */
Owen Taylor3473f882001-02-23 17:55:21 +00006730 if (name != NULL)
6731 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006732 name = NULL;
6733 if (CUR != ')') {
6734 name = xmlXPathParseLiteral(ctxt);
6735 CHECK_ERROR 0;
6736 SKIP_BLANKS;
6737 }
Owen Taylor3473f882001-02-23 17:55:21 +00006738 }
6739 if (CUR != ')') {
6740 if (name != NULL)
6741 xmlFree(name);
6742 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6743 }
6744 NEXT;
6745 return(name);
6746 }
6747 *test = NODE_TEST_NAME;
6748 if ((!blanks) && (CUR == ':')) {
6749 NEXT;
6750
6751 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006752 * Since currently the parser context don't have a
6753 * namespace list associated:
6754 * The namespace name for this prefix can be computed
6755 * only at evaluation time. The compilation is done
6756 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006757 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006758#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006759 *prefix = xmlXPathNsLookup(ctxt->context, name);
6760 if (name != NULL)
6761 xmlFree(name);
6762 if (*prefix == NULL) {
6763 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6764 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006765#else
6766 *prefix = name;
6767#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006768
6769 if (CUR == '*') {
6770 /*
6771 * All elements
6772 */
6773 NEXT;
6774 *test = NODE_TEST_ALL;
6775 return(NULL);
6776 }
6777
6778 name = xmlXPathParseNCName(ctxt);
6779 if (name == NULL) {
6780 XP_ERROR0(XPATH_EXPR_ERROR);
6781 }
6782 }
6783 return(name);
6784}
6785
6786/**
6787 * xmlXPathIsAxisName:
6788 * @name: a preparsed name token
6789 *
6790 * [6] AxisName ::= 'ancestor'
6791 * | 'ancestor-or-self'
6792 * | 'attribute'
6793 * | 'child'
6794 * | 'descendant'
6795 * | 'descendant-or-self'
6796 * | 'following'
6797 * | 'following-sibling'
6798 * | 'namespace'
6799 * | 'parent'
6800 * | 'preceding'
6801 * | 'preceding-sibling'
6802 * | 'self'
6803 *
6804 * Returns the axis or 0
6805 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006806static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006807xmlXPathIsAxisName(const xmlChar *name) {
6808 xmlXPathAxisVal ret = 0;
6809 switch (name[0]) {
6810 case 'a':
6811 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6812 ret = AXIS_ANCESTOR;
6813 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6814 ret = AXIS_ANCESTOR_OR_SELF;
6815 if (xmlStrEqual(name, BAD_CAST "attribute"))
6816 ret = AXIS_ATTRIBUTE;
6817 break;
6818 case 'c':
6819 if (xmlStrEqual(name, BAD_CAST "child"))
6820 ret = AXIS_CHILD;
6821 break;
6822 case 'd':
6823 if (xmlStrEqual(name, BAD_CAST "descendant"))
6824 ret = AXIS_DESCENDANT;
6825 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6826 ret = AXIS_DESCENDANT_OR_SELF;
6827 break;
6828 case 'f':
6829 if (xmlStrEqual(name, BAD_CAST "following"))
6830 ret = AXIS_FOLLOWING;
6831 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6832 ret = AXIS_FOLLOWING_SIBLING;
6833 break;
6834 case 'n':
6835 if (xmlStrEqual(name, BAD_CAST "namespace"))
6836 ret = AXIS_NAMESPACE;
6837 break;
6838 case 'p':
6839 if (xmlStrEqual(name, BAD_CAST "parent"))
6840 ret = AXIS_PARENT;
6841 if (xmlStrEqual(name, BAD_CAST "preceding"))
6842 ret = AXIS_PRECEDING;
6843 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6844 ret = AXIS_PRECEDING_SIBLING;
6845 break;
6846 case 's':
6847 if (xmlStrEqual(name, BAD_CAST "self"))
6848 ret = AXIS_SELF;
6849 break;
6850 }
6851 return(ret);
6852}
6853
6854/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006855 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006856 * @ctxt: the XPath Parser context
6857 *
6858 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6859 * | AbbreviatedStep
6860 *
6861 * [12] AbbreviatedStep ::= '.' | '..'
6862 *
6863 * [5] AxisSpecifier ::= AxisName '::'
6864 * | AbbreviatedAxisSpecifier
6865 *
6866 * [13] AbbreviatedAxisSpecifier ::= '@'?
6867 *
6868 * Modified for XPtr range support as:
6869 *
6870 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6871 * | AbbreviatedStep
6872 * | 'range-to' '(' Expr ')' Predicate*
6873 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006874 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006875 * A location step of . is short for self::node(). This is
6876 * particularly useful in conjunction with //. For example, the
6877 * location path .//para is short for
6878 * self::node()/descendant-or-self::node()/child::para
6879 * and so will select all para descendant elements of the context
6880 * node.
6881 * Similarly, a location step of .. is short for parent::node().
6882 * For example, ../title is short for parent::node()/child::title
6883 * and so will select the title children of the parent of the context
6884 * node.
6885 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006886static void
6887xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006888#ifdef LIBXML_XPTR_ENABLED
6889 int rangeto = 0;
6890 int op2 = -1;
6891#endif
6892
Owen Taylor3473f882001-02-23 17:55:21 +00006893 SKIP_BLANKS;
6894 if ((CUR == '.') && (NXT(1) == '.')) {
6895 SKIP(2);
6896 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006897 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6898 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006899 } else if (CUR == '.') {
6900 NEXT;
6901 SKIP_BLANKS;
6902 } else {
6903 xmlChar *name = NULL;
6904 const xmlChar *prefix = NULL;
6905 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006906 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006907 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006908 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006909
6910 /*
6911 * The modification needed for XPointer change to the production
6912 */
6913#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006914 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006915 name = xmlXPathParseNCName(ctxt);
6916 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006917 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006918 xmlFree(name);
6919 SKIP_BLANKS;
6920 if (CUR != '(') {
6921 XP_ERROR(XPATH_EXPR_ERROR);
6922 }
6923 NEXT;
6924 SKIP_BLANKS;
6925
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006926 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006927 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006928 CHECK_ERROR;
6929
6930 SKIP_BLANKS;
6931 if (CUR != ')') {
6932 XP_ERROR(XPATH_EXPR_ERROR);
6933 }
6934 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006935 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006936 goto eval_predicates;
6937 }
6938 }
6939#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006940 if (CUR == '*') {
6941 axis = AXIS_CHILD;
6942 } else {
6943 if (name == NULL)
6944 name = xmlXPathParseNCName(ctxt);
6945 if (name != NULL) {
6946 axis = xmlXPathIsAxisName(name);
6947 if (axis != 0) {
6948 SKIP_BLANKS;
6949 if ((CUR == ':') && (NXT(1) == ':')) {
6950 SKIP(2);
6951 xmlFree(name);
6952 name = NULL;
6953 } else {
6954 /* an element name can conflict with an axis one :-\ */
6955 axis = AXIS_CHILD;
6956 }
Owen Taylor3473f882001-02-23 17:55:21 +00006957 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00006958 axis = AXIS_CHILD;
6959 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006960 } else if (CUR == '@') {
6961 NEXT;
6962 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00006963 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00006964 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00006965 }
Owen Taylor3473f882001-02-23 17:55:21 +00006966 }
6967
6968 CHECK_ERROR;
6969
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006970 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006971 if (test == 0)
6972 return;
6973
6974#ifdef DEBUG_STEP
6975 xmlGenericError(xmlGenericErrorContext,
6976 "Basis : computing new set\n");
6977#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006978
Owen Taylor3473f882001-02-23 17:55:21 +00006979#ifdef DEBUG_STEP
6980 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006981 if (ctxt->value == NULL)
6982 xmlGenericError(xmlGenericErrorContext, "no value\n");
6983 else if (ctxt->value->nodesetval == NULL)
6984 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6985 else
6986 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006987#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006988
6989eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006990 op1 = ctxt->comp->last;
6991 ctxt->comp->last = -1;
6992
Owen Taylor3473f882001-02-23 17:55:21 +00006993 SKIP_BLANKS;
6994 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006995 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006996 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006997
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006998#ifdef LIBXML_XPTR_ENABLED
6999 if (rangeto) {
7000 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7001 } else
7002#endif
7003 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7004 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007005
Owen Taylor3473f882001-02-23 17:55:21 +00007006 }
7007#ifdef DEBUG_STEP
7008 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007009 if (ctxt->value == NULL)
7010 xmlGenericError(xmlGenericErrorContext, "no value\n");
7011 else if (ctxt->value->nodesetval == NULL)
7012 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7013 else
7014 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7015 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007016#endif
7017}
7018
7019/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007020 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007021 * @ctxt: the XPath Parser context
7022 *
7023 * [3] RelativeLocationPath ::= Step
7024 * | RelativeLocationPath '/' Step
7025 * | AbbreviatedRelativeLocationPath
7026 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7027 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007028 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007029 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007030static void
Owen Taylor3473f882001-02-23 17:55:21 +00007031#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007032xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007033#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007034xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007035#endif
7036(xmlXPathParserContextPtr ctxt) {
7037 SKIP_BLANKS;
7038 if ((CUR == '/') && (NXT(1) == '/')) {
7039 SKIP(2);
7040 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007041 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7042 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007043 } else if (CUR == '/') {
7044 NEXT;
7045 SKIP_BLANKS;
7046 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007047 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007048 SKIP_BLANKS;
7049 while (CUR == '/') {
7050 if ((CUR == '/') && (NXT(1) == '/')) {
7051 SKIP(2);
7052 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007053 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007054 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007055 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007056 } else if (CUR == '/') {
7057 NEXT;
7058 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007059 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007060 }
7061 SKIP_BLANKS;
7062 }
7063}
7064
7065/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007066 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007067 * @ctxt: the XPath Parser context
7068 *
7069 * [1] LocationPath ::= RelativeLocationPath
7070 * | AbsoluteLocationPath
7071 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7072 * | AbbreviatedAbsoluteLocationPath
7073 * [10] AbbreviatedAbsoluteLocationPath ::=
7074 * '//' RelativeLocationPath
7075 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007076 * Compile a location path
7077 *
Owen Taylor3473f882001-02-23 17:55:21 +00007078 * // is short for /descendant-or-self::node()/. For example,
7079 * //para is short for /descendant-or-self::node()/child::para and
7080 * so will select any para element in the document (even a para element
7081 * that is a document element will be selected by //para since the
7082 * document element node is a child of the root node); div//para is
7083 * short for div/descendant-or-self::node()/child::para and so will
7084 * select all para descendants of div children.
7085 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007086static void
7087xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007088 SKIP_BLANKS;
7089 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007090 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007091 } else {
7092 while (CUR == '/') {
7093 if ((CUR == '/') && (NXT(1) == '/')) {
7094 SKIP(2);
7095 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007096 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7097 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007098 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007099 } else if (CUR == '/') {
7100 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007101 SKIP_BLANKS;
7102 if ((CUR != 0 ) &&
7103 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7104 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007105 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007106 }
7107 }
7108 }
7109}
7110
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007111/************************************************************************
7112 * *
7113 * XPath precompiled expression evaluation *
7114 * *
7115 ************************************************************************/
7116
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007117static void
7118xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7119
7120/**
7121 * xmlXPathNodeCollectAndTest:
7122 * @ctxt: the XPath Parser context
7123 * @op: the XPath precompiled step operation
7124 *
7125 * This is the function implementing a step: based on the current list
7126 * of nodes, it builds up a new list, looking at all nodes under that
7127 * axis and selecting them it also do the predicate filtering
7128 *
7129 * Pushes the new NodeSet resulting from the search.
7130 */
7131static void
7132xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
7133 xmlXPathStepOpPtr op) {
7134 xmlXPathAxisVal axis = op->value;
7135 xmlXPathTestVal test = op->value2;
7136 xmlXPathTypeVal type = op->value3;
7137 const xmlChar *prefix = op->value4;
7138 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007139 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007140
7141#ifdef DEBUG_STEP
7142 int n = 0, t = 0;
7143#endif
7144 int i;
7145 xmlNodeSetPtr ret, list;
7146 xmlXPathTraversalFunction next = NULL;
7147 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
7148 xmlNodePtr cur = NULL;
7149 xmlXPathObjectPtr obj;
7150 xmlNodeSetPtr nodelist;
7151 xmlNodePtr tmp;
7152
7153 CHECK_TYPE(XPATH_NODESET);
7154 obj = valuePop(ctxt);
7155 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007156 if (prefix != NULL) {
7157 URI = xmlXPathNsLookup(ctxt->context, prefix);
7158 if (URI == NULL)
7159 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
7160 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007161
7162#ifdef DEBUG_STEP
7163 xmlGenericError(xmlGenericErrorContext,
7164 "new step : ");
7165#endif
7166 switch (axis) {
7167 case AXIS_ANCESTOR:
7168#ifdef DEBUG_STEP
7169 xmlGenericError(xmlGenericErrorContext,
7170 "axis 'ancestors' ");
7171#endif
7172 next = xmlXPathNextAncestor; break;
7173 case AXIS_ANCESTOR_OR_SELF:
7174#ifdef DEBUG_STEP
7175 xmlGenericError(xmlGenericErrorContext,
7176 "axis 'ancestors-or-self' ");
7177#endif
7178 next = xmlXPathNextAncestorOrSelf; break;
7179 case AXIS_ATTRIBUTE:
7180#ifdef DEBUG_STEP
7181 xmlGenericError(xmlGenericErrorContext,
7182 "axis 'attributes' ");
7183#endif
7184 next = xmlXPathNextAttribute; break;
7185 break;
7186 case AXIS_CHILD:
7187#ifdef DEBUG_STEP
7188 xmlGenericError(xmlGenericErrorContext,
7189 "axis 'child' ");
7190#endif
7191 next = xmlXPathNextChild; break;
7192 case AXIS_DESCENDANT:
7193#ifdef DEBUG_STEP
7194 xmlGenericError(xmlGenericErrorContext,
7195 "axis 'descendant' ");
7196#endif
7197 next = xmlXPathNextDescendant; break;
7198 case AXIS_DESCENDANT_OR_SELF:
7199#ifdef DEBUG_STEP
7200 xmlGenericError(xmlGenericErrorContext,
7201 "axis 'descendant-or-self' ");
7202#endif
7203 next = xmlXPathNextDescendantOrSelf; break;
7204 case AXIS_FOLLOWING:
7205#ifdef DEBUG_STEP
7206 xmlGenericError(xmlGenericErrorContext,
7207 "axis 'following' ");
7208#endif
7209 next = xmlXPathNextFollowing; break;
7210 case AXIS_FOLLOWING_SIBLING:
7211#ifdef DEBUG_STEP
7212 xmlGenericError(xmlGenericErrorContext,
7213 "axis 'following-siblings' ");
7214#endif
7215 next = xmlXPathNextFollowingSibling; break;
7216 case AXIS_NAMESPACE:
7217#ifdef DEBUG_STEP
7218 xmlGenericError(xmlGenericErrorContext,
7219 "axis 'namespace' ");
7220#endif
7221 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
7222 break;
7223 case AXIS_PARENT:
7224#ifdef DEBUG_STEP
7225 xmlGenericError(xmlGenericErrorContext,
7226 "axis 'parent' ");
7227#endif
7228 next = xmlXPathNextParent; break;
7229 case AXIS_PRECEDING:
7230#ifdef DEBUG_STEP
7231 xmlGenericError(xmlGenericErrorContext,
7232 "axis 'preceding' ");
7233#endif
7234 next = xmlXPathNextPreceding; break;
7235 case AXIS_PRECEDING_SIBLING:
7236#ifdef DEBUG_STEP
7237 xmlGenericError(xmlGenericErrorContext,
7238 "axis 'preceding-sibling' ");
7239#endif
7240 next = xmlXPathNextPrecedingSibling; break;
7241 case AXIS_SELF:
7242#ifdef DEBUG_STEP
7243 xmlGenericError(xmlGenericErrorContext,
7244 "axis 'self' ");
7245#endif
7246 next = xmlXPathNextSelf; break;
7247 }
7248 if (next == NULL)
7249 return;
7250
7251 nodelist = obj->nodesetval;
7252 if (nodelist == NULL) {
7253 xmlXPathFreeObject(obj);
7254 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7255 return;
7256 }
7257 addNode = xmlXPathNodeSetAddUnique;
7258 ret = NULL;
7259#ifdef DEBUG_STEP
7260 xmlGenericError(xmlGenericErrorContext,
7261 " context contains %d nodes\n",
7262 nodelist->nodeNr);
7263 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007264 case NODE_TEST_NONE:
7265 xmlGenericError(xmlGenericErrorContext,
7266 " searching for none !!!\n");
7267 break;
7268 case NODE_TEST_TYPE:
7269 xmlGenericError(xmlGenericErrorContext,
7270 " searching for type %d\n", type);
7271 break;
7272 case NODE_TEST_PI:
7273 xmlGenericError(xmlGenericErrorContext,
7274 " searching for PI !!!\n");
7275 break;
7276 case NODE_TEST_ALL:
7277 xmlGenericError(xmlGenericErrorContext,
7278 " searching for *\n");
7279 break;
7280 case NODE_TEST_NS:
7281 xmlGenericError(xmlGenericErrorContext,
7282 " searching for namespace %s\n",
7283 prefix);
7284 break;
7285 case NODE_TEST_NAME:
7286 xmlGenericError(xmlGenericErrorContext,
7287 " searching for name %s\n", name);
7288 if (prefix != NULL)
7289 xmlGenericError(xmlGenericErrorContext,
7290 " with namespace %s\n",
7291 prefix);
7292 break;
7293 }
7294 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7295#endif
7296 /*
7297 * 2.3 Node Tests
7298 * - For the attribute axis, the principal node type is attribute.
7299 * - For the namespace axis, the principal node type is namespace.
7300 * - For other axes, the principal node type is element.
7301 *
7302 * A node test * is true for any node of the
7303 * principal node type. For example, child::* willi
7304 * select all element children of the context node
7305 */
7306 tmp = ctxt->context->node;
7307 for (i = 0;i < nodelist->nodeNr; i++) {
7308 ctxt->context->node = nodelist->nodeTab[i];
7309
7310 cur = NULL;
7311 list = xmlXPathNodeSetCreate(NULL);
7312 do {
7313 cur = next(ctxt, cur);
7314 if (cur == NULL) break;
7315#ifdef DEBUG_STEP
7316 t++;
7317 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7318#endif
7319 switch (test) {
7320 case NODE_TEST_NONE:
7321 ctxt->context->node = tmp;
7322 STRANGE
7323 return;
7324 case NODE_TEST_TYPE:
7325 if ((cur->type == type) ||
7326 ((type == NODE_TYPE_NODE) &&
7327 ((cur->type == XML_DOCUMENT_NODE) ||
7328 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7329 (cur->type == XML_ELEMENT_NODE) ||
7330 (cur->type == XML_PI_NODE) ||
7331 (cur->type == XML_COMMENT_NODE) ||
7332 (cur->type == XML_CDATA_SECTION_NODE) ||
7333 (cur->type == XML_TEXT_NODE)))) {
7334#ifdef DEBUG_STEP
7335 n++;
7336#endif
7337 addNode(list, cur);
7338 }
7339 break;
7340 case NODE_TEST_PI:
7341 if (cur->type == XML_PI_NODE) {
7342 if ((name != NULL) &&
7343 (!xmlStrEqual(name, cur->name)))
7344 break;
7345#ifdef DEBUG_STEP
7346 n++;
7347#endif
7348 addNode(list, cur);
7349 }
7350 break;
7351 case NODE_TEST_ALL:
7352 if (axis == AXIS_ATTRIBUTE) {
7353 if (cur->type == XML_ATTRIBUTE_NODE) {
7354#ifdef DEBUG_STEP
7355 n++;
7356#endif
7357 addNode(list, cur);
7358 }
7359 } else if (axis == AXIS_NAMESPACE) {
7360 if (cur->type == XML_NAMESPACE_DECL) {
7361#ifdef DEBUG_STEP
7362 n++;
7363#endif
7364 addNode(list, cur);
7365 }
7366 } else {
Daniel Veillard8cf14d52001-06-23 16:32:46 +00007367 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007368 if (prefix == NULL) {
7369#ifdef DEBUG_STEP
7370 n++;
7371#endif
7372 addNode(list, cur);
7373 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007374 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007375 cur->ns->href))) {
7376#ifdef DEBUG_STEP
7377 n++;
7378#endif
7379 addNode(list, cur);
7380 }
7381 }
7382 }
7383 break;
7384 case NODE_TEST_NS: {
7385 TODO;
7386 break;
7387 }
7388 case NODE_TEST_NAME:
7389 switch (cur->type) {
7390 case XML_ELEMENT_NODE:
7391 if (xmlStrEqual(name, cur->name)) {
7392 if (prefix == NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00007393 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007394#ifdef DEBUG_STEP
7395 n++;
7396#endif
7397 addNode(list, cur);
7398 }
7399 } else {
7400 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007401 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007402 cur->ns->href))) {
7403#ifdef DEBUG_STEP
7404 n++;
7405#endif
7406 addNode(list, cur);
7407 }
7408 }
7409 }
7410 break;
7411 case XML_ATTRIBUTE_NODE: {
7412 xmlAttrPtr attr = (xmlAttrPtr) cur;
7413 if (xmlStrEqual(name, attr->name)) {
7414 if (prefix == NULL) {
7415 if ((attr->ns == NULL) ||
7416 (attr->ns->prefix == NULL)) {
7417#ifdef DEBUG_STEP
7418 n++;
7419#endif
7420 addNode(list, (xmlNodePtr) attr);
7421 }
7422 } else {
7423 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007424 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007425 attr->ns->href))) {
7426#ifdef DEBUG_STEP
7427 n++;
7428#endif
7429 addNode(list, (xmlNodePtr) attr);
7430 }
7431 }
7432 }
7433 break;
7434 }
Daniel Veillard8b8d2252001-06-16 21:24:56 +00007435 case XML_NAMESPACE_DECL:
7436 if (cur->type == XML_NAMESPACE_DECL) {
7437 xmlNsPtr ns = (xmlNsPtr) cur;
7438 if ((ns->prefix != NULL) && (name != NULL) &&
7439 (xmlStrEqual(ns->prefix, name))) {
7440#ifdef DEBUG_STEP
7441 n++;
7442#endif
7443 addNode(list, cur);
7444 }
7445 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007446 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007447 default:
7448 break;
7449 }
7450 break;
7451 }
7452 } while (cur != NULL);
7453
7454 /*
7455 * If there is some predicate filtering do it now
7456 */
7457 if (op->ch2 != -1) {
7458 xmlXPathObjectPtr obj2;
7459
7460 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7461 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7462 CHECK_TYPE(XPATH_NODESET);
7463 obj2 = valuePop(ctxt);
7464 list = obj2->nodesetval;
7465 obj2->nodesetval = NULL;
7466 xmlXPathFreeObject(obj2);
7467 }
7468 if (ret == NULL) {
7469 ret = list;
7470 } else {
7471 ret = xmlXPathNodeSetMerge(ret, list);
7472 xmlXPathFreeNodeSet(list);
7473 }
7474 }
7475 ctxt->context->node = tmp;
7476#ifdef DEBUG_STEP
7477 xmlGenericError(xmlGenericErrorContext,
7478 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7479#endif
7480 xmlXPathFreeObject(obj);
7481 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7482}
7483
Owen Taylor3473f882001-02-23 17:55:21 +00007484/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007485 * xmlXPathCompOpEval:
7486 * @ctxt: the XPath parser context with the compiled expression
7487 * @op: an XPath compiled operation
7488 *
7489 * Evaluate the Precompiled XPath operation
7490 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007491static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007492xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7493 int equal, ret;
7494 xmlXPathCompExprPtr comp;
7495 xmlXPathObjectPtr arg1, arg2;
7496
7497 comp = ctxt->comp;
7498 switch (op->op) {
7499 case XPATH_OP_END:
7500 return;
7501 case XPATH_OP_AND:
7502 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7503 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007504 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007505 return;
7506 arg2 = valuePop(ctxt);
7507 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7508 xmlXPathBooleanFunction(ctxt, 1);
7509 arg1 = valuePop(ctxt);
7510 arg1->boolval &= arg2->boolval;
7511 valuePush(ctxt, arg1);
7512 xmlXPathFreeObject(arg2);
7513 return;
7514 case XPATH_OP_OR:
7515 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7516 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007517 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007518 return;
7519 arg2 = valuePop(ctxt);
7520 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7521 xmlXPathBooleanFunction(ctxt, 1);
7522 arg1 = valuePop(ctxt);
7523 arg1->boolval |= arg2->boolval;
7524 valuePush(ctxt, arg1);
7525 xmlXPathFreeObject(arg2);
7526 return;
7527 case XPATH_OP_EQUAL:
7528 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7529 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7530 equal = xmlXPathEqualValues(ctxt);
7531 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7532 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7533 return;
7534 case XPATH_OP_CMP:
7535 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7536 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7537 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7538 valuePush(ctxt, xmlXPathNewBoolean(ret));
7539 return;
7540 case XPATH_OP_PLUS:
7541 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7542 if (op->ch2 != -1)
7543 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7544 if (op->value == 0) xmlXPathSubValues(ctxt);
7545 else if (op->value == 1) xmlXPathAddValues(ctxt);
7546 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7547 else if (op->value == 3) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007548 CAST_TO_NUMBER;
7549 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007550 }
7551 return;
7552 case XPATH_OP_MULT:
7553 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7554 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7555 if (op->value == 0) xmlXPathMultValues(ctxt);
7556 else if (op->value == 1) xmlXPathDivValues(ctxt);
7557 else if (op->value == 2) xmlXPathModValues(ctxt);
7558 return;
7559 case XPATH_OP_UNION:
7560 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7561 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7562 CHECK_TYPE(XPATH_NODESET);
7563 arg2 = valuePop(ctxt);
7564
7565 CHECK_TYPE(XPATH_NODESET);
7566 arg1 = valuePop(ctxt);
7567
7568 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7569 arg2->nodesetval);
7570 valuePush(ctxt, arg1);
7571 xmlXPathFreeObject(arg2);
7572 return;
7573 case XPATH_OP_ROOT:
7574 xmlXPathRoot(ctxt);
7575 return;
7576 case XPATH_OP_NODE:
7577 if (op->ch1 != -1)
7578 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7579 if (op->ch2 != -1)
7580 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7581 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7582 return;
7583 case XPATH_OP_RESET:
7584 if (op->ch1 != -1)
7585 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7586 if (op->ch2 != -1)
7587 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7588 ctxt->context->node = NULL;
7589 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007590 case XPATH_OP_COLLECT: {
7591 if (op->ch1 == -1)
7592 return;
7593
7594 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7595 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007596 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007597 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007598 case XPATH_OP_VALUE:
7599 valuePush(ctxt,
7600 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7601 return;
7602 case XPATH_OP_VARIABLE: {
7603 if (op->ch1 != -1)
7604 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7605 if (op->value5 == NULL)
7606 valuePush(ctxt,
7607 xmlXPathVariableLookup(ctxt->context, op->value4));
7608 else {
7609 const xmlChar *URI;
7610 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7611 if (URI == NULL) {
7612 xmlGenericError(xmlGenericErrorContext,
7613 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7614 op->value4, op->value5);
7615 return;
7616 }
7617 valuePush(ctxt,
7618 xmlXPathVariableLookupNS(ctxt->context,
7619 op->value4, URI));
7620 }
7621 return;
7622 }
7623 case XPATH_OP_FUNCTION: {
7624 xmlXPathFunction func;
Daniel Veillard42596ad2001-05-22 16:57:14 +00007625 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007626
7627 if (op->ch1 != -1)
7628 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007629 if (op->cache != NULL)
7630 func = (xmlXPathFunction) op->cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007631 else {
Daniel Veillard42596ad2001-05-22 16:57:14 +00007632 const xmlChar *URI = NULL;
7633
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007634 if (op->value5 == NULL)
7635 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7636 else {
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007637 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7638 if (URI == NULL) {
7639 xmlGenericError(xmlGenericErrorContext,
7640 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7641 op->value4, op->value5);
7642 return;
7643 }
7644 func = xmlXPathFunctionLookupNS(ctxt->context,
7645 op->value4, URI);
7646 }
7647 if (func == NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007648 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007649 "xmlXPathRunEval: function %s not found\n",
7650 op->value4);
7651 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007652 return;
7653 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007654 op->cache = (void *) func;
Daniel Veillard42596ad2001-05-22 16:57:14 +00007655 op->cacheURI = (void *) URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007656 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00007657 oldFunc = ctxt->context->function;
7658 oldFuncURI = ctxt->context->functionURI;
7659 ctxt->context->function = op->value4;
7660 ctxt->context->functionURI = op->cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007661 func(ctxt, op->value);
Daniel Veillard42596ad2001-05-22 16:57:14 +00007662 ctxt->context->function = oldFunc;
7663 ctxt->context->functionURI = oldFuncURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007664 return;
7665 }
7666 case XPATH_OP_ARG:
7667 if (op->ch1 != -1)
7668 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7669 if (op->ch2 != -1)
7670 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7671 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007672 case XPATH_OP_PREDICATE:
7673 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007674 xmlXPathObjectPtr res;
7675 xmlXPathObjectPtr obj, tmp;
7676 xmlNodeSetPtr newset = NULL;
7677 xmlNodeSetPtr oldset;
7678 xmlNodePtr oldnode;
7679 int i;
7680
7681 if (op->ch1 != -1)
7682 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7683 if (op->ch2 == -1)
7684 return;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007685 if (ctxt->value == NULL)
7686 return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007687
7688 oldnode = ctxt->context->node;
7689
7690#ifdef LIBXML_XPTR_ENABLED
7691 /*
7692 * Hum are we filtering the result of an XPointer expression
7693 */
7694 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007695 xmlLocationSetPtr newlocset = NULL;
7696 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007697
7698 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007699 * Extract the old locset, and then evaluate the result of the
7700 * expression for all the element in the locset. use it to grow
7701 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007702 */
7703 CHECK_TYPE(XPATH_LOCATIONSET);
7704 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007705 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007706 ctxt->context->node = NULL;
7707
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007708 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007709 ctxt->context->contextSize = 0;
7710 ctxt->context->proximityPosition = 0;
7711 if (op->ch2 != -1)
7712 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7713 res = valuePop(ctxt);
7714 if (res != NULL)
7715 xmlXPathFreeObject(res);
7716 valuePush(ctxt, obj);
7717 CHECK_ERROR;
7718 return;
7719 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007720 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007721
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007722 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007723 /*
7724 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007725 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007726 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007727 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007728 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7729 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007730 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007731 ctxt->context->proximityPosition = i + 1;
7732
7733 if (op->ch2 != -1)
7734 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7735 CHECK_ERROR;
7736
7737 /*
7738 * The result of the evaluation need to be tested to
7739 * decided whether the filter succeeded or not
7740 */
7741 res = valuePop(ctxt);
7742 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007743 xmlXPtrLocationSetAdd(newlocset,
7744 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007745 }
7746
7747 /*
7748 * Cleanup
7749 */
7750 if (res != NULL)
7751 xmlXPathFreeObject(res);
7752 if (ctxt->value == tmp) {
7753 res = valuePop(ctxt);
7754 xmlXPathFreeObject(res);
7755 }
7756
7757 ctxt->context->node = NULL;
7758 }
7759
7760 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007761 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007762 */
7763 xmlXPathFreeObject(obj);
7764 ctxt->context->node = NULL;
7765 ctxt->context->contextSize = -1;
7766 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007767 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007768 ctxt->context->node = oldnode;
7769 return;
7770 }
7771#endif /* LIBXML_XPTR_ENABLED */
7772
7773 /*
7774 * Extract the old set, and then evaluate the result of the
7775 * expression for all the element in the set. use it to grow
7776 * up a new set.
7777 */
7778 CHECK_TYPE(XPATH_NODESET);
7779 obj = valuePop(ctxt);
7780 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007781
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007782 oldnode = ctxt->context->node;
7783 ctxt->context->node = NULL;
7784
7785 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7786 ctxt->context->contextSize = 0;
7787 ctxt->context->proximityPosition = 0;
7788 if (op->ch2 != -1)
7789 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7790 res = valuePop(ctxt);
7791 if (res != NULL)
7792 xmlXPathFreeObject(res);
7793 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007794 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007795 CHECK_ERROR;
7796 } else {
7797 /*
7798 * Initialize the new set.
7799 */
7800 newset = xmlXPathNodeSetCreate(NULL);
7801
7802 for (i = 0; i < oldset->nodeNr; i++) {
7803 /*
7804 * Run the evaluation with a node list made of
7805 * a single item in the nodeset.
7806 */
7807 ctxt->context->node = oldset->nodeTab[i];
7808 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7809 valuePush(ctxt, tmp);
7810 ctxt->context->contextSize = oldset->nodeNr;
7811 ctxt->context->proximityPosition = i + 1;
7812
7813 if (op->ch2 != -1)
7814 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7815 CHECK_ERROR;
7816
7817 /*
7818 * The result of the evaluation need to be tested to
7819 * decided whether the filter succeeded or not
7820 */
7821 res = valuePop(ctxt);
7822 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7823 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7824 }
7825
7826 /*
7827 * Cleanup
7828 */
7829 if (res != NULL)
7830 xmlXPathFreeObject(res);
7831 if (ctxt->value == tmp) {
7832 res = valuePop(ctxt);
7833 xmlXPathFreeObject(res);
7834 }
7835
7836 ctxt->context->node = NULL;
7837 }
7838
7839 /*
7840 * The result is used as the new evaluation set.
7841 */
7842 xmlXPathFreeObject(obj);
7843 ctxt->context->node = NULL;
7844 ctxt->context->contextSize = -1;
7845 ctxt->context->proximityPosition = -1;
7846 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7847 }
7848 ctxt->context->node = oldnode;
7849 return;
7850 }
7851 case XPATH_OP_SORT:
7852 if (op->ch1 != -1)
7853 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7854 if ((ctxt->value != NULL) &&
7855 (ctxt->value->type == XPATH_NODESET) &&
7856 (ctxt->value->nodesetval != NULL))
7857 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7858 return;
7859#ifdef LIBXML_XPTR_ENABLED
7860 case XPATH_OP_RANGETO: {
7861 xmlXPathObjectPtr range;
7862 xmlXPathObjectPtr res, obj;
7863 xmlXPathObjectPtr tmp;
7864 xmlLocationSetPtr newset = NULL;
7865 xmlNodeSetPtr oldset;
7866 int i;
7867
7868 if (op->ch1 != -1)
7869 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7870 if (op->ch2 == -1)
7871 return;
7872
7873 CHECK_TYPE(XPATH_NODESET);
7874 obj = valuePop(ctxt);
7875 oldset = obj->nodesetval;
7876 ctxt->context->node = NULL;
7877
7878 newset = xmlXPtrLocationSetCreate(NULL);
7879
Daniel Veillard911f49a2001-04-07 15:39:35 +00007880 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007881 for (i = 0; i < oldset->nodeNr; i++) {
7882 /*
7883 * Run the evaluation with a node list made of a single item
7884 * in the nodeset.
7885 */
7886 ctxt->context->node = oldset->nodeTab[i];
7887 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7888 valuePush(ctxt, tmp);
7889
7890 if (op->ch2 != -1)
7891 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7892 CHECK_ERROR;
7893
7894 /*
7895 * The result of the evaluation need to be tested to
7896 * decided whether the filter succeeded or not
7897 */
7898 res = valuePop(ctxt);
7899 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7900 if (range != NULL) {
7901 xmlXPtrLocationSetAdd(newset, range);
7902 }
7903
7904 /*
7905 * Cleanup
7906 */
7907 if (res != NULL)
7908 xmlXPathFreeObject(res);
7909 if (ctxt->value == tmp) {
7910 res = valuePop(ctxt);
7911 xmlXPathFreeObject(res);
7912 }
7913
7914 ctxt->context->node = NULL;
7915 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007916 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007917
7918 /*
7919 * The result is used as the new evaluation set.
7920 */
7921 xmlXPathFreeObject(obj);
7922 ctxt->context->node = NULL;
7923 ctxt->context->contextSize = -1;
7924 ctxt->context->proximityPosition = -1;
7925 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7926 return;
7927 }
7928#endif /* LIBXML_XPTR_ENABLED */
7929 }
7930 xmlGenericError(xmlGenericErrorContext,
7931 "XPath: unknown precompiled operation %d\n",
7932 op->op);
7933 return;
7934}
7935
7936/**
7937 * xmlXPathRunEval:
7938 * @ctxt: the XPath parser context with the compiled expression
7939 *
7940 * Evaluate the Precompiled XPath expression in the given context.
7941 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007942static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007943xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7944 xmlXPathCompExprPtr comp;
7945
7946 if ((ctxt == NULL) || (ctxt->comp == NULL))
7947 return;
7948
7949 if (ctxt->valueTab == NULL) {
7950 /* Allocate the value stack */
7951 ctxt->valueTab = (xmlXPathObjectPtr *)
7952 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7953 if (ctxt->valueTab == NULL) {
7954 xmlFree(ctxt);
7955 xmlGenericError(xmlGenericErrorContext,
7956 "xmlXPathRunEval: out of memory\n");
7957 return;
7958 }
7959 ctxt->valueNr = 0;
7960 ctxt->valueMax = 10;
7961 ctxt->value = NULL;
7962 }
7963 comp = ctxt->comp;
7964 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7965}
7966
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007967/************************************************************************
7968 * *
7969 * Public interfaces *
7970 * *
7971 ************************************************************************/
7972
7973/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007974 * xmlXPathEvalPredicate:
7975 * @ctxt: the XPath context
7976 * @res: the Predicate Expression evaluation result
7977 *
7978 * Evaluate a predicate result for the current node.
7979 * A PredicateExpr is evaluated by evaluating the Expr and converting
7980 * the result to a boolean. If the result is a number, the result will
7981 * be converted to true if the number is equal to the position of the
7982 * context node in the context node list (as returned by the position
7983 * function) and will be converted to false otherwise; if the result
7984 * is not a number, then the result will be converted as if by a call
7985 * to the boolean function.
7986 *
7987 * Return 1 if predicate is true, 0 otherwise
7988 */
7989int
7990xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7991 if (res == NULL) return(0);
7992 switch (res->type) {
7993 case XPATH_BOOLEAN:
7994 return(res->boolval);
7995 case XPATH_NUMBER:
7996 return(res->floatval == ctxt->proximityPosition);
7997 case XPATH_NODESET:
7998 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007999 if (res->nodesetval == NULL)
8000 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008001 return(res->nodesetval->nodeNr != 0);
8002 case XPATH_STRING:
8003 return((res->stringval != NULL) &&
8004 (xmlStrlen(res->stringval) != 0));
8005 default:
8006 STRANGE
8007 }
8008 return(0);
8009}
8010
8011/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008012 * xmlXPathEvaluatePredicateResult:
8013 * @ctxt: the XPath Parser context
8014 * @res: the Predicate Expression evaluation result
8015 *
8016 * Evaluate a predicate result for the current node.
8017 * A PredicateExpr is evaluated by evaluating the Expr and converting
8018 * the result to a boolean. If the result is a number, the result will
8019 * be converted to true if the number is equal to the position of the
8020 * context node in the context node list (as returned by the position
8021 * function) and will be converted to false otherwise; if the result
8022 * is not a number, then the result will be converted as if by a call
8023 * to the boolean function.
8024 *
8025 * Return 1 if predicate is true, 0 otherwise
8026 */
8027int
8028xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
8029 xmlXPathObjectPtr res) {
8030 if (res == NULL) return(0);
8031 switch (res->type) {
8032 case XPATH_BOOLEAN:
8033 return(res->boolval);
8034 case XPATH_NUMBER:
8035 return(res->floatval == ctxt->context->proximityPosition);
8036 case XPATH_NODESET:
8037 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00008038 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00008039 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008040 return(res->nodesetval->nodeNr != 0);
8041 case XPATH_STRING:
8042 return((res->stringval != NULL) &&
8043 (xmlStrlen(res->stringval) != 0));
8044 default:
8045 STRANGE
8046 }
8047 return(0);
8048}
8049
8050/**
8051 * xmlXPathCompile:
8052 * @str: the XPath expression
8053 *
8054 * Compile an XPath expression
8055 *
8056 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8057 * the caller has to free the object.
8058 */
8059xmlXPathCompExprPtr
8060xmlXPathCompile(const xmlChar *str) {
8061 xmlXPathParserContextPtr ctxt;
8062 xmlXPathCompExprPtr comp;
8063
8064 xmlXPathInit();
8065
8066 ctxt = xmlXPathNewParserContext(str, NULL);
8067 xmlXPathCompileExpr(ctxt);
8068
Daniel Veillard40af6492001-04-22 08:50:55 +00008069 if (*ctxt->cur != 0) {
8070 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8071 comp = NULL;
8072 } else {
8073 comp = ctxt->comp;
8074 ctxt->comp = NULL;
8075 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008076 xmlXPathFreeParserContext(ctxt);
8077 return(comp);
8078}
8079
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008080/**
8081 * xmlXPathCompiledEval:
8082 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00008083 * @ctx: the XPath context
8084 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008085 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00008086 *
8087 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8088 * the caller has to free the object.
8089 */
8090xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008091xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00008092 xmlXPathParserContextPtr ctxt;
8093 xmlXPathObjectPtr res, tmp, init = NULL;
8094 int stack = 0;
8095
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008096 if ((comp == NULL) || (ctx == NULL))
8097 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008098 xmlXPathInit();
8099
8100 CHECK_CONTEXT(ctx)
8101
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008102 ctxt = xmlXPathCompParserContext(comp, ctx);
8103 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008104
8105 if (ctxt->value == NULL) {
8106 xmlGenericError(xmlGenericErrorContext,
8107 "xmlXPathEval: evaluation failed\n");
8108 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00008109 } else {
8110 res = valuePop(ctxt);
8111 }
8112
8113 do {
8114 tmp = valuePop(ctxt);
8115 if (tmp != NULL) {
8116 if (tmp != init)
8117 stack++;
8118 xmlXPathFreeObject(tmp);
8119 }
8120 } while (tmp != NULL);
8121 if ((stack != 0) && (res != NULL)) {
8122 xmlGenericError(xmlGenericErrorContext,
8123 "xmlXPathEval: %d object left on the stack\n",
8124 stack);
8125 }
8126 if (ctxt->error != XPATH_EXPRESSION_OK) {
8127 xmlXPathFreeObject(res);
8128 res = NULL;
8129 }
8130
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008131
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008132 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008133 xmlXPathFreeParserContext(ctxt);
8134 return(res);
8135}
8136
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008137/**
8138 * xmlXPathEvalExpr:
8139 * @ctxt: the XPath Parser context
8140 *
8141 * Parse and evaluate an XPath expression in the given context,
8142 * then push the result on the context stack
8143 */
8144void
8145xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
8146 xmlXPathCompileExpr(ctxt);
8147 xmlXPathRunEval(ctxt);
8148}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008149
8150/**
8151 * xmlXPathEval:
8152 * @str: the XPath expression
8153 * @ctx: the XPath context
8154 *
8155 * Evaluate the XPath Location Path in the given context.
8156 *
8157 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8158 * the caller has to free the object.
8159 */
8160xmlXPathObjectPtr
8161xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
8162 xmlXPathParserContextPtr ctxt;
8163 xmlXPathObjectPtr res, tmp, init = NULL;
8164 int stack = 0;
8165
8166 xmlXPathInit();
8167
8168 CHECK_CONTEXT(ctx)
8169
8170 ctxt = xmlXPathNewParserContext(str, ctx);
8171 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008172
8173 if (ctxt->value == NULL) {
8174 xmlGenericError(xmlGenericErrorContext,
8175 "xmlXPathEval: evaluation failed\n");
8176 res = NULL;
8177 } else if (*ctxt->cur != 0) {
8178 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8179 res = NULL;
8180 } else {
8181 res = valuePop(ctxt);
8182 }
8183
8184 do {
8185 tmp = valuePop(ctxt);
8186 if (tmp != NULL) {
8187 if (tmp != init)
8188 stack++;
8189 xmlXPathFreeObject(tmp);
8190 }
8191 } while (tmp != NULL);
8192 if ((stack != 0) && (res != NULL)) {
8193 xmlGenericError(xmlGenericErrorContext,
8194 "xmlXPathEval: %d object left on the stack\n",
8195 stack);
8196 }
8197 if (ctxt->error != XPATH_EXPRESSION_OK) {
8198 xmlXPathFreeObject(res);
8199 res = NULL;
8200 }
8201
Owen Taylor3473f882001-02-23 17:55:21 +00008202 xmlXPathFreeParserContext(ctxt);
8203 return(res);
8204}
8205
8206/**
8207 * xmlXPathEvalExpression:
8208 * @str: the XPath expression
8209 * @ctxt: the XPath context
8210 *
8211 * Evaluate the XPath expression in the given context.
8212 *
8213 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
8214 * the caller has to free the object.
8215 */
8216xmlXPathObjectPtr
8217xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
8218 xmlXPathParserContextPtr pctxt;
8219 xmlXPathObjectPtr res, tmp;
8220 int stack = 0;
8221
8222 xmlXPathInit();
8223
8224 CHECK_CONTEXT(ctxt)
8225
8226 pctxt = xmlXPathNewParserContext(str, ctxt);
8227 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008228
8229 if (*pctxt->cur != 0) {
8230 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8231 res = NULL;
8232 } else {
8233 res = valuePop(pctxt);
8234 }
8235 do {
8236 tmp = valuePop(pctxt);
8237 if (tmp != NULL) {
8238 xmlXPathFreeObject(tmp);
8239 stack++;
8240 }
8241 } while (tmp != NULL);
8242 if ((stack != 0) && (res != NULL)) {
8243 xmlGenericError(xmlGenericErrorContext,
8244 "xmlXPathEvalExpression: %d object left on the stack\n",
8245 stack);
8246 }
8247 xmlXPathFreeParserContext(pctxt);
8248 return(res);
8249}
8250
8251/**
8252 * xmlXPathRegisterAllFunctions:
8253 * @ctxt: the XPath context
8254 *
8255 * Registers all default XPath functions in this context
8256 */
8257void
8258xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
8259{
8260 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
8261 xmlXPathBooleanFunction);
8262 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
8263 xmlXPathCeilingFunction);
8264 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
8265 xmlXPathCountFunction);
8266 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
8267 xmlXPathConcatFunction);
8268 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
8269 xmlXPathContainsFunction);
8270 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
8271 xmlXPathIdFunction);
8272 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
8273 xmlXPathFalseFunction);
8274 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
8275 xmlXPathFloorFunction);
8276 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
8277 xmlXPathLastFunction);
8278 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
8279 xmlXPathLangFunction);
8280 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
8281 xmlXPathLocalNameFunction);
8282 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
8283 xmlXPathNotFunction);
8284 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
8285 xmlXPathNameFunction);
8286 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
8287 xmlXPathNamespaceURIFunction);
8288 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
8289 xmlXPathNormalizeFunction);
8290 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
8291 xmlXPathNumberFunction);
8292 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
8293 xmlXPathPositionFunction);
8294 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
8295 xmlXPathRoundFunction);
8296 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
8297 xmlXPathStringFunction);
8298 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
8299 xmlXPathStringLengthFunction);
8300 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
8301 xmlXPathStartsWithFunction);
8302 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
8303 xmlXPathSubstringFunction);
8304 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
8305 xmlXPathSubstringBeforeFunction);
8306 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
8307 xmlXPathSubstringAfterFunction);
8308 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
8309 xmlXPathSumFunction);
8310 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
8311 xmlXPathTrueFunction);
8312 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
8313 xmlXPathTranslateFunction);
8314}
8315
8316#endif /* LIBXML_XPATH_ENABLED */