blob: 0741920a837357d3a3ca3489c36c9d1e798eea9b [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
Daniel Veillarda3067d12001-06-24 21:39:39 +00001020 integer_place = 0;
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)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00005559 (*in == '_') || (*in == '.') ||
5560 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00005561 in++;
5562 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5563 (*in == '[') || (*in == ']') || (*in == ':') ||
5564 (*in == '@') || (*in == '*')) {
5565 count = in - ctxt->cur;
5566 if (count == 0)
5567 return(NULL);
5568 ret = xmlStrndup(ctxt->cur, count);
5569 ctxt->cur = in;
5570 return(ret);
5571 }
5572 }
5573 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005574}
5575
Daniel Veillard2156a562001-04-28 12:24:34 +00005576
Owen Taylor3473f882001-02-23 17:55:21 +00005577/**
5578 * xmlXPathParseQName:
5579 * @ctxt: the XPath Parser context
5580 * @prefix: a xmlChar **
5581 *
5582 * parse an XML qualified name
5583 *
5584 * [NS 5] QName ::= (Prefix ':')? LocalPart
5585 *
5586 * [NS 6] Prefix ::= NCName
5587 *
5588 * [NS 7] LocalPart ::= NCName
5589 *
5590 * Returns the function returns the local part, and prefix is updated
5591 * to get the Prefix if any.
5592 */
5593
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005594static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005595xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5596 xmlChar *ret = NULL;
5597
5598 *prefix = NULL;
5599 ret = xmlXPathParseNCName(ctxt);
5600 if (CUR == ':') {
5601 *prefix = ret;
5602 NEXT;
5603 ret = xmlXPathParseNCName(ctxt);
5604 }
5605 return(ret);
5606}
5607
5608/**
5609 * xmlXPathParseName:
5610 * @ctxt: the XPath Parser context
5611 *
5612 * parse an XML name
5613 *
5614 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5615 * CombiningChar | Extender
5616 *
5617 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5618 *
5619 * Returns the namespace name or NULL
5620 */
5621
5622xmlChar *
5623xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005624 const xmlChar *in;
5625 xmlChar *ret;
5626 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005627
Daniel Veillard61d80a22001-04-27 17:13:01 +00005628 /*
5629 * Accelerator for simple ASCII names
5630 */
5631 in = ctxt->cur;
5632 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5633 ((*in >= 0x41) && (*in <= 0x5A)) ||
5634 (*in == '_') || (*in == ':')) {
5635 in++;
5636 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5637 ((*in >= 0x41) && (*in <= 0x5A)) ||
5638 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00005639 (*in == '_') || (*in == '-') ||
5640 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00005641 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00005642 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005643 count = in - ctxt->cur;
5644 ret = xmlStrndup(ctxt->cur, count);
5645 ctxt->cur = in;
5646 return(ret);
5647 }
5648 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005649 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005650}
5651
Daniel Veillard61d80a22001-04-27 17:13:01 +00005652static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005653xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005654 xmlChar buf[XML_MAX_NAMELEN + 5];
5655 int len = 0, l;
5656 int c;
5657
5658 /*
5659 * Handler for more complex cases
5660 */
5661 c = CUR_CHAR(l);
5662 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005663 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5664 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005665 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005666 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005667 return(NULL);
5668 }
5669
5670 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5671 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5672 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005673 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005674 (IS_COMBINING(c)) ||
5675 (IS_EXTENDER(c)))) {
5676 COPY_BUF(l,buf,len,c);
5677 NEXTL(l);
5678 c = CUR_CHAR(l);
5679 if (len >= XML_MAX_NAMELEN) {
5680 /*
5681 * Okay someone managed to make a huge name, so he's ready to pay
5682 * for the processing speed.
5683 */
5684 xmlChar *buffer;
5685 int max = len * 2;
5686
5687 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5688 if (buffer == NULL) {
5689 XP_ERROR0(XPATH_MEMORY_ERROR);
5690 }
5691 memcpy(buffer, buf, len);
5692 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5693 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005694 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005695 (IS_COMBINING(c)) ||
5696 (IS_EXTENDER(c))) {
5697 if (len + 10 > max) {
5698 max *= 2;
5699 buffer = (xmlChar *) xmlRealloc(buffer,
5700 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00005701 if (buffer == NULL) {
5702 XP_ERROR0(XPATH_MEMORY_ERROR);
5703 }
5704 }
5705 COPY_BUF(l,buffer,len,c);
5706 NEXTL(l);
5707 c = CUR_CHAR(l);
5708 }
5709 buffer[len] = 0;
5710 return(buffer);
5711 }
5712 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005713 if (len == 0)
5714 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005715 return(xmlStrndup(buf, len));
5716}
Owen Taylor3473f882001-02-23 17:55:21 +00005717/**
5718 * xmlXPathStringEvalNumber:
5719 * @str: A string to scan
5720 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005721 * [30a] Float ::= Number ('e' Digits?)?
5722 *
Owen Taylor3473f882001-02-23 17:55:21 +00005723 * [30] Number ::= Digits ('.' Digits?)?
5724 * | '.' Digits
5725 * [31] Digits ::= [0-9]+
5726 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005727 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005728 * In complement of the Number expression, this function also handles
5729 * negative values : '-' Number.
5730 *
5731 * Returns the double value.
5732 */
5733double
5734xmlXPathStringEvalNumber(const xmlChar *str) {
5735 const xmlChar *cur = str;
5736 double ret = 0.0;
5737 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005738 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005739 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005740 int exponent = 0;
5741 int is_exponent_negative = 0;
5742
Owen Taylor3473f882001-02-23 17:55:21 +00005743 while (IS_BLANK(*cur)) cur++;
5744 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5745 return(xmlXPathNAN);
5746 }
5747 if (*cur == '-') {
5748 isneg = 1;
5749 cur++;
5750 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005751 /*
5752 * tmp is a workaroudn against a gcc compiler bug
5753 */
Owen Taylor3473f882001-02-23 17:55:21 +00005754 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005755 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00005756 ok = 1;
5757 cur++;
5758 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005759 ret = (double) tmp;
5760
Owen Taylor3473f882001-02-23 17:55:21 +00005761 if (*cur == '.') {
5762 cur++;
5763 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5764 return(xmlXPathNAN);
5765 }
5766 while ((*cur >= '0') && (*cur <= '9')) {
5767 mult /= 10;
5768 ret = ret + (*cur - '0') * mult;
5769 cur++;
5770 }
5771 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005772 if ((*cur == 'e') || (*cur == 'E')) {
5773 cur++;
5774 if (*cur == '-') {
5775 is_exponent_negative = 1;
5776 cur++;
5777 }
5778 while ((*cur >= '0') && (*cur <= '9')) {
5779 exponent = exponent * 10 + (*cur - '0');
5780 cur++;
5781 }
5782 }
Owen Taylor3473f882001-02-23 17:55:21 +00005783 while (IS_BLANK(*cur)) cur++;
5784 if (*cur != 0) return(xmlXPathNAN);
5785 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005786 if (is_exponent_negative) exponent = -exponent;
5787 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005788 return(ret);
5789}
5790
5791/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005792 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005793 * @ctxt: the XPath Parser context
5794 *
5795 * [30] Number ::= Digits ('.' Digits?)?
5796 * | '.' Digits
5797 * [31] Digits ::= [0-9]+
5798 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005799 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005800 *
5801 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005802static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005803xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
5804{
Owen Taylor3473f882001-02-23 17:55:21 +00005805 double ret = 0.0;
5806 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005807 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005808 int exponent = 0;
5809 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005810
5811 CHECK_ERROR;
5812 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5813 XP_ERROR(XPATH_NUMBER_ERROR);
5814 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005815 /*
5816 * Try to work around a gcc optimizer bug
5817 */
Owen Taylor3473f882001-02-23 17:55:21 +00005818 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005819 tmp = tmp * 10 + (CUR - '0');
5820 ok = 1;
5821 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00005822 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005823 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005824 if (CUR == '.') {
5825 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005826 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5827 XP_ERROR(XPATH_NUMBER_ERROR);
5828 }
5829 while ((CUR >= '0') && (CUR <= '9')) {
5830 mult /= 10;
5831 ret = ret + (CUR - '0') * mult;
5832 NEXT;
5833 }
Owen Taylor3473f882001-02-23 17:55:21 +00005834 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005835 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005836 NEXT;
5837 if (CUR == '-') {
5838 is_exponent_negative = 1;
5839 NEXT;
5840 }
5841 while ((CUR >= '0') && (CUR <= '9')) {
5842 exponent = exponent * 10 + (CUR - '0');
5843 NEXT;
5844 }
5845 if (is_exponent_negative)
5846 exponent = -exponent;
5847 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005848 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005849 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005850 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005851}
5852
5853/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005854 * xmlXPathParseLiteral:
5855 * @ctxt: the XPath Parser context
5856 *
5857 * Parse a Literal
5858 *
5859 * [29] Literal ::= '"' [^"]* '"'
5860 * | "'" [^']* "'"
5861 *
5862 * Returns the value found or NULL in case of error
5863 */
5864static xmlChar *
5865xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5866 const xmlChar *q;
5867 xmlChar *ret = NULL;
5868
5869 if (CUR == '"') {
5870 NEXT;
5871 q = CUR_PTR;
5872 while ((IS_CHAR(CUR)) && (CUR != '"'))
5873 NEXT;
5874 if (!IS_CHAR(CUR)) {
5875 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5876 } else {
5877 ret = xmlStrndup(q, CUR_PTR - q);
5878 NEXT;
5879 }
5880 } else if (CUR == '\'') {
5881 NEXT;
5882 q = CUR_PTR;
5883 while ((IS_CHAR(CUR)) && (CUR != '\''))
5884 NEXT;
5885 if (!IS_CHAR(CUR)) {
5886 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5887 } else {
5888 ret = xmlStrndup(q, CUR_PTR - q);
5889 NEXT;
5890 }
5891 } else {
5892 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5893 }
5894 return(ret);
5895}
5896
5897/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005898 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005899 * @ctxt: the XPath Parser context
5900 *
5901 * Parse a Literal and push it on the stack.
5902 *
5903 * [29] Literal ::= '"' [^"]* '"'
5904 * | "'" [^']* "'"
5905 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005906 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005907 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005908static void
5909xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005910 const xmlChar *q;
5911 xmlChar *ret = NULL;
5912
5913 if (CUR == '"') {
5914 NEXT;
5915 q = CUR_PTR;
5916 while ((IS_CHAR(CUR)) && (CUR != '"'))
5917 NEXT;
5918 if (!IS_CHAR(CUR)) {
5919 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5920 } else {
5921 ret = xmlStrndup(q, CUR_PTR - q);
5922 NEXT;
5923 }
5924 } else if (CUR == '\'') {
5925 NEXT;
5926 q = CUR_PTR;
5927 while ((IS_CHAR(CUR)) && (CUR != '\''))
5928 NEXT;
5929 if (!IS_CHAR(CUR)) {
5930 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5931 } else {
5932 ret = xmlStrndup(q, CUR_PTR - q);
5933 NEXT;
5934 }
5935 } else {
5936 XP_ERROR(XPATH_START_LITERAL_ERROR);
5937 }
5938 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005939 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5940 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005941 xmlFree(ret);
5942}
5943
5944/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005945 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005946 * @ctxt: the XPath Parser context
5947 *
5948 * Parse a VariableReference, evaluate it and push it on the stack.
5949 *
5950 * The variable bindings consist of a mapping from variable names
5951 * to variable values. The value of a variable is an object, which
5952 * of any of the types that are possible for the value of an expression,
5953 * and may also be of additional types not specified here.
5954 *
5955 * Early evaluation is possible since:
5956 * The variable bindings [...] used to evaluate a subexpression are
5957 * always the same as those used to evaluate the containing expression.
5958 *
5959 * [36] VariableReference ::= '$' QName
5960 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005961static void
5962xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005963 xmlChar *name;
5964 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005965
5966 SKIP_BLANKS;
5967 if (CUR != '$') {
5968 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5969 }
5970 NEXT;
5971 name = xmlXPathParseQName(ctxt, &prefix);
5972 if (name == NULL) {
5973 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5974 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005975 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005976 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5977 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005978 SKIP_BLANKS;
5979}
5980
5981/**
5982 * xmlXPathIsNodeType:
5983 * @ctxt: the XPath Parser context
5984 * @name: a name string
5985 *
5986 * Is the name given a NodeType one.
5987 *
5988 * [38] NodeType ::= 'comment'
5989 * | 'text'
5990 * | 'processing-instruction'
5991 * | 'node'
5992 *
5993 * Returns 1 if true 0 otherwise
5994 */
5995int
5996xmlXPathIsNodeType(const xmlChar *name) {
5997 if (name == NULL)
5998 return(0);
5999
6000 if (xmlStrEqual(name, BAD_CAST "comment"))
6001 return(1);
6002 if (xmlStrEqual(name, BAD_CAST "text"))
6003 return(1);
6004 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6005 return(1);
6006 if (xmlStrEqual(name, BAD_CAST "node"))
6007 return(1);
6008 return(0);
6009}
6010
6011/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006012 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006013 * @ctxt: the XPath Parser context
6014 *
6015 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6016 * [17] Argument ::= Expr
6017 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006018 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006019 * pushed on the stack
6020 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006021static void
6022xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006023 xmlChar *name;
6024 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006025 int nbargs = 0;
6026
6027 name = xmlXPathParseQName(ctxt, &prefix);
6028 if (name == NULL) {
6029 XP_ERROR(XPATH_EXPR_ERROR);
6030 }
6031 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006032#ifdef DEBUG_EXPR
6033 if (prefix == NULL)
6034 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6035 name);
6036 else
6037 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6038 prefix, name);
6039#endif
6040
Owen Taylor3473f882001-02-23 17:55:21 +00006041 if (CUR != '(') {
6042 XP_ERROR(XPATH_EXPR_ERROR);
6043 }
6044 NEXT;
6045 SKIP_BLANKS;
6046
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006047 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006048 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006049 int op1 = ctxt->comp->last;
6050 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006051 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006052 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006053 nbargs++;
6054 if (CUR == ')') break;
6055 if (CUR != ',') {
6056 XP_ERROR(XPATH_EXPR_ERROR);
6057 }
6058 NEXT;
6059 SKIP_BLANKS;
6060 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006061 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6062 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006063 NEXT;
6064 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006065}
6066
6067/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006068 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006069 * @ctxt: the XPath Parser context
6070 *
6071 * [15] PrimaryExpr ::= VariableReference
6072 * | '(' Expr ')'
6073 * | Literal
6074 * | Number
6075 * | FunctionCall
6076 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006077 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006078 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006079static void
6080xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006081 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006082 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006083 else if (CUR == '(') {
6084 NEXT;
6085 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006086 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006087 if (CUR != ')') {
6088 XP_ERROR(XPATH_EXPR_ERROR);
6089 }
6090 NEXT;
6091 SKIP_BLANKS;
6092 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006093 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006094 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006095 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006096 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006097 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006098 }
6099 SKIP_BLANKS;
6100}
6101
6102/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006103 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006104 * @ctxt: the XPath Parser context
6105 *
6106 * [20] FilterExpr ::= PrimaryExpr
6107 * | FilterExpr Predicate
6108 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006109 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006110 * Square brackets are used to filter expressions in the same way that
6111 * they are used in location paths. It is an error if the expression to
6112 * be filtered does not evaluate to a node-set. The context node list
6113 * used for evaluating the expression in square brackets is the node-set
6114 * to be filtered listed in document order.
6115 */
6116
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006117static void
6118xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6119 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006120 CHECK_ERROR;
6121 SKIP_BLANKS;
6122
6123 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006124 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006125 SKIP_BLANKS;
6126 }
6127
6128
6129}
6130
6131/**
6132 * xmlXPathScanName:
6133 * @ctxt: the XPath Parser context
6134 *
6135 * Trickery: parse an XML name but without consuming the input flow
6136 * Needed to avoid insanity in the parser state.
6137 *
6138 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6139 * CombiningChar | Extender
6140 *
6141 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6142 *
6143 * [6] Names ::= Name (S Name)*
6144 *
6145 * Returns the Name parsed or NULL
6146 */
6147
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006148static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006149xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6150 xmlChar buf[XML_MAX_NAMELEN];
6151 int len = 0;
6152
6153 SKIP_BLANKS;
6154 if (!IS_LETTER(CUR) && (CUR != '_') &&
6155 (CUR != ':')) {
6156 return(NULL);
6157 }
6158
6159 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6160 (NXT(len) == '.') || (NXT(len) == '-') ||
6161 (NXT(len) == '_') || (NXT(len) == ':') ||
6162 (IS_COMBINING(NXT(len))) ||
6163 (IS_EXTENDER(NXT(len)))) {
6164 buf[len] = NXT(len);
6165 len++;
6166 if (len >= XML_MAX_NAMELEN) {
6167 xmlGenericError(xmlGenericErrorContext,
6168 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6169 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6170 (NXT(len) == '.') || (NXT(len) == '-') ||
6171 (NXT(len) == '_') || (NXT(len) == ':') ||
6172 (IS_COMBINING(NXT(len))) ||
6173 (IS_EXTENDER(NXT(len))))
6174 len++;
6175 break;
6176 }
6177 }
6178 return(xmlStrndup(buf, len));
6179}
6180
6181/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006182 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006183 * @ctxt: the XPath Parser context
6184 *
6185 * [19] PathExpr ::= LocationPath
6186 * | FilterExpr
6187 * | FilterExpr '/' RelativeLocationPath
6188 * | FilterExpr '//' RelativeLocationPath
6189 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006190 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006191 * The / operator and // operators combine an arbitrary expression
6192 * and a relative location path. It is an error if the expression
6193 * does not evaluate to a node-set.
6194 * The / operator does composition in the same way as when / is
6195 * used in a location path. As in location paths, // is short for
6196 * /descendant-or-self::node()/.
6197 */
6198
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006199static void
6200xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006201 int lc = 1; /* Should we branch to LocationPath ? */
6202 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6203
6204 SKIP_BLANKS;
6205 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6206 (CUR == '\'') || (CUR == '"')) {
6207 lc = 0;
6208 } else if (CUR == '*') {
6209 /* relative or absolute location path */
6210 lc = 1;
6211 } else if (CUR == '/') {
6212 /* relative or absolute location path */
6213 lc = 1;
6214 } else if (CUR == '@') {
6215 /* relative abbreviated attribute location path */
6216 lc = 1;
6217 } else if (CUR == '.') {
6218 /* relative abbreviated attribute location path */
6219 lc = 1;
6220 } else {
6221 /*
6222 * Problem is finding if we have a name here whether it's:
6223 * - a nodetype
6224 * - a function call in which case it's followed by '('
6225 * - an axis in which case it's followed by ':'
6226 * - a element name
6227 * We do an a priori analysis here rather than having to
6228 * maintain parsed token content through the recursive function
6229 * calls. This looks uglier but makes the code quite easier to
6230 * read/write/debug.
6231 */
6232 SKIP_BLANKS;
6233 name = xmlXPathScanName(ctxt);
6234 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6235#ifdef DEBUG_STEP
6236 xmlGenericError(xmlGenericErrorContext,
6237 "PathExpr: Axis\n");
6238#endif
6239 lc = 1;
6240 xmlFree(name);
6241 } else if (name != NULL) {
6242 int len =xmlStrlen(name);
6243 int blank = 0;
6244
6245
6246 while (NXT(len) != 0) {
6247 if (NXT(len) == '/') {
6248 /* element name */
6249#ifdef DEBUG_STEP
6250 xmlGenericError(xmlGenericErrorContext,
6251 "PathExpr: AbbrRelLocation\n");
6252#endif
6253 lc = 1;
6254 break;
6255 } else if (IS_BLANK(NXT(len))) {
6256 /* skip to next */
6257 blank = 1;
6258 } else if (NXT(len) == ':') {
6259#ifdef DEBUG_STEP
6260 xmlGenericError(xmlGenericErrorContext,
6261 "PathExpr: AbbrRelLocation\n");
6262#endif
6263 lc = 1;
6264 break;
6265 } else if ((NXT(len) == '(')) {
6266 /* Note Type or Function */
6267 if (xmlXPathIsNodeType(name)) {
6268#ifdef DEBUG_STEP
6269 xmlGenericError(xmlGenericErrorContext,
6270 "PathExpr: Type search\n");
6271#endif
6272 lc = 1;
6273 } else {
6274#ifdef DEBUG_STEP
6275 xmlGenericError(xmlGenericErrorContext,
6276 "PathExpr: function call\n");
6277#endif
6278 lc = 0;
6279 }
6280 break;
6281 } else if ((NXT(len) == '[')) {
6282 /* element name */
6283#ifdef DEBUG_STEP
6284 xmlGenericError(xmlGenericErrorContext,
6285 "PathExpr: AbbrRelLocation\n");
6286#endif
6287 lc = 1;
6288 break;
6289 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6290 (NXT(len) == '=')) {
6291 lc = 1;
6292 break;
6293 } else {
6294 lc = 1;
6295 break;
6296 }
6297 len++;
6298 }
6299 if (NXT(len) == 0) {
6300#ifdef DEBUG_STEP
6301 xmlGenericError(xmlGenericErrorContext,
6302 "PathExpr: AbbrRelLocation\n");
6303#endif
6304 /* element name */
6305 lc = 1;
6306 }
6307 xmlFree(name);
6308 } else {
6309 /* make sure all cases are covered explicitely */
6310 XP_ERROR(XPATH_EXPR_ERROR);
6311 }
6312 }
6313
6314 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006315 if (CUR == '/') {
6316 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6317 } else {
6318 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006319 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006320 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006321 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006322 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006323 CHECK_ERROR;
6324 if ((CUR == '/') && (NXT(1) == '/')) {
6325 SKIP(2);
6326 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006327
6328 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6329 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6330 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6331
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006332 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006333 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006334 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006335 }
6336 }
6337 SKIP_BLANKS;
6338}
6339
6340/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006341 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006342 * @ctxt: the XPath Parser context
6343 *
6344 * [18] UnionExpr ::= PathExpr
6345 * | UnionExpr '|' PathExpr
6346 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006347 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006348 */
6349
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006350static void
6351xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6352 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006353 CHECK_ERROR;
6354 SKIP_BLANKS;
6355 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006356 int op1 = ctxt->comp->last;
6357 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006358
6359 NEXT;
6360 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006361 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006362
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006363 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6364
Owen Taylor3473f882001-02-23 17:55:21 +00006365 SKIP_BLANKS;
6366 }
Owen Taylor3473f882001-02-23 17:55:21 +00006367}
6368
6369/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006370 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006371 * @ctxt: the XPath Parser context
6372 *
6373 * [27] UnaryExpr ::= UnionExpr
6374 * | '-' UnaryExpr
6375 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006376 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006377 */
6378
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006379static void
6380xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006381 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006382 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006383
6384 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006385 while (CUR == '-') {
6386 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006387 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006388 NEXT;
6389 SKIP_BLANKS;
6390 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006391
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006392 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006393 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006394 if (found) {
6395 if (minus)
6396 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6397 else
6398 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006399 }
6400}
6401
6402/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006403 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006404 * @ctxt: the XPath Parser context
6405 *
6406 * [26] MultiplicativeExpr ::= UnaryExpr
6407 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6408 * | MultiplicativeExpr 'div' UnaryExpr
6409 * | MultiplicativeExpr 'mod' UnaryExpr
6410 * [34] MultiplyOperator ::= '*'
6411 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006412 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006413 */
6414
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006415static void
6416xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6417 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006418 CHECK_ERROR;
6419 SKIP_BLANKS;
6420 while ((CUR == '*') ||
6421 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6422 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6423 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006424 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006425
6426 if (CUR == '*') {
6427 op = 0;
6428 NEXT;
6429 } else if (CUR == 'd') {
6430 op = 1;
6431 SKIP(3);
6432 } else if (CUR == 'm') {
6433 op = 2;
6434 SKIP(3);
6435 }
6436 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006437 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006438 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006439 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006440 SKIP_BLANKS;
6441 }
6442}
6443
6444/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006445 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006446 * @ctxt: the XPath Parser context
6447 *
6448 * [25] AdditiveExpr ::= MultiplicativeExpr
6449 * | AdditiveExpr '+' MultiplicativeExpr
6450 * | AdditiveExpr '-' MultiplicativeExpr
6451 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006452 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006453 */
6454
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006455static void
6456xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006457
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006458 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006459 CHECK_ERROR;
6460 SKIP_BLANKS;
6461 while ((CUR == '+') || (CUR == '-')) {
6462 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006463 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006464
6465 if (CUR == '+') plus = 1;
6466 else plus = 0;
6467 NEXT;
6468 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006469 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006470 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006471 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006472 SKIP_BLANKS;
6473 }
6474}
6475
6476/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006477 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006478 * @ctxt: the XPath Parser context
6479 *
6480 * [24] RelationalExpr ::= AdditiveExpr
6481 * | RelationalExpr '<' AdditiveExpr
6482 * | RelationalExpr '>' AdditiveExpr
6483 * | RelationalExpr '<=' AdditiveExpr
6484 * | RelationalExpr '>=' AdditiveExpr
6485 *
6486 * A <= B > C is allowed ? Answer from James, yes with
6487 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6488 * which is basically what got implemented.
6489 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006490 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006491 * on the stack
6492 */
6493
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006494static void
6495xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6496 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006497 CHECK_ERROR;
6498 SKIP_BLANKS;
6499 while ((CUR == '<') ||
6500 (CUR == '>') ||
6501 ((CUR == '<') && (NXT(1) == '=')) ||
6502 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006503 int inf, strict;
6504 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006505
6506 if (CUR == '<') inf = 1;
6507 else inf = 0;
6508 if (NXT(1) == '=') strict = 0;
6509 else strict = 1;
6510 NEXT;
6511 if (!strict) NEXT;
6512 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006513 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006514 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006515 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006516 SKIP_BLANKS;
6517 }
6518}
6519
6520/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006521 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006522 * @ctxt: the XPath Parser context
6523 *
6524 * [23] EqualityExpr ::= RelationalExpr
6525 * | EqualityExpr '=' RelationalExpr
6526 * | EqualityExpr '!=' RelationalExpr
6527 *
6528 * A != B != C is allowed ? Answer from James, yes with
6529 * (RelationalExpr = RelationalExpr) = RelationalExpr
6530 * (RelationalExpr != RelationalExpr) != RelationalExpr
6531 * which is basically what got implemented.
6532 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006533 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006534 *
6535 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006536static void
6537xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6538 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006539 CHECK_ERROR;
6540 SKIP_BLANKS;
6541 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006542 int eq;
6543 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006544
6545 if (CUR == '=') eq = 1;
6546 else eq = 0;
6547 NEXT;
6548 if (!eq) NEXT;
6549 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006550 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006551 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006552 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006553 SKIP_BLANKS;
6554 }
6555}
6556
6557/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006558 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006559 * @ctxt: the XPath Parser context
6560 *
6561 * [22] AndExpr ::= EqualityExpr
6562 * | AndExpr 'and' EqualityExpr
6563 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006564 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006565 *
6566 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006567static void
6568xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6569 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006570 CHECK_ERROR;
6571 SKIP_BLANKS;
6572 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006573 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006574 SKIP(3);
6575 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006576 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006577 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006578 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006579 SKIP_BLANKS;
6580 }
6581}
6582
6583/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006584 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006585 * @ctxt: the XPath Parser context
6586 *
6587 * [14] Expr ::= OrExpr
6588 * [21] OrExpr ::= AndExpr
6589 * | OrExpr 'or' AndExpr
6590 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006591 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006592 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006593static void
6594xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6595 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006596 CHECK_ERROR;
6597 SKIP_BLANKS;
6598 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006599 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006600 SKIP(2);
6601 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006602 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006603 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006604 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6605 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006606 SKIP_BLANKS;
6607 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006608 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6609 /* more ops could be optimized too */
6610 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6611 }
Owen Taylor3473f882001-02-23 17:55:21 +00006612}
6613
6614/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006615 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006616 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006617 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006618 *
6619 * [8] Predicate ::= '[' PredicateExpr ']'
6620 * [9] PredicateExpr ::= Expr
6621 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006622 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006623 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006624static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006625xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006626 int op1 = ctxt->comp->last;
6627
6628 SKIP_BLANKS;
6629 if (CUR != '[') {
6630 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6631 }
6632 NEXT;
6633 SKIP_BLANKS;
6634
6635 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006636 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006637 CHECK_ERROR;
6638
6639 if (CUR != ']') {
6640 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6641 }
6642
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006643 if (filter)
6644 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6645 else
6646 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006647
6648 NEXT;
6649 SKIP_BLANKS;
6650}
6651
6652/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006653 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006654 * @ctxt: the XPath Parser context
6655 * @test: pointer to a xmlXPathTestVal
6656 * @type: pointer to a xmlXPathTypeVal
6657 * @prefix: placeholder for a possible name prefix
6658 *
6659 * [7] NodeTest ::= NameTest
6660 * | NodeType '(' ')'
6661 * | 'processing-instruction' '(' Literal ')'
6662 *
6663 * [37] NameTest ::= '*'
6664 * | NCName ':' '*'
6665 * | QName
6666 * [38] NodeType ::= 'comment'
6667 * | 'text'
6668 * | 'processing-instruction'
6669 * | 'node'
6670 *
6671 * Returns the name found and update @test, @type and @prefix appropriately
6672 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006673static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006674xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6675 xmlXPathTypeVal *type, const xmlChar **prefix,
6676 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006677 int blanks;
6678
6679 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6680 STRANGE;
6681 return(NULL);
6682 }
6683 *type = 0;
6684 *test = 0;
6685 *prefix = NULL;
6686 SKIP_BLANKS;
6687
6688 if ((name == NULL) && (CUR == '*')) {
6689 /*
6690 * All elements
6691 */
6692 NEXT;
6693 *test = NODE_TEST_ALL;
6694 return(NULL);
6695 }
6696
6697 if (name == NULL)
6698 name = xmlXPathParseNCName(ctxt);
6699 if (name == NULL) {
6700 XP_ERROR0(XPATH_EXPR_ERROR);
6701 }
6702
6703 blanks = IS_BLANK(CUR);
6704 SKIP_BLANKS;
6705 if (CUR == '(') {
6706 NEXT;
6707 /*
6708 * NodeType or PI search
6709 */
6710 if (xmlStrEqual(name, BAD_CAST "comment"))
6711 *type = NODE_TYPE_COMMENT;
6712 else if (xmlStrEqual(name, BAD_CAST "node"))
6713 *type = NODE_TYPE_NODE;
6714 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6715 *type = NODE_TYPE_PI;
6716 else if (xmlStrEqual(name, BAD_CAST "text"))
6717 *type = NODE_TYPE_TEXT;
6718 else {
6719 if (name != NULL)
6720 xmlFree(name);
6721 XP_ERROR0(XPATH_EXPR_ERROR);
6722 }
6723
6724 *test = NODE_TEST_TYPE;
6725
6726 SKIP_BLANKS;
6727 if (*type == NODE_TYPE_PI) {
6728 /*
6729 * Specific case: search a PI by name.
6730 */
Owen Taylor3473f882001-02-23 17:55:21 +00006731 if (name != NULL)
6732 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006733 name = NULL;
6734 if (CUR != ')') {
6735 name = xmlXPathParseLiteral(ctxt);
6736 CHECK_ERROR 0;
6737 SKIP_BLANKS;
6738 }
Owen Taylor3473f882001-02-23 17:55:21 +00006739 }
6740 if (CUR != ')') {
6741 if (name != NULL)
6742 xmlFree(name);
6743 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6744 }
6745 NEXT;
6746 return(name);
6747 }
6748 *test = NODE_TEST_NAME;
6749 if ((!blanks) && (CUR == ':')) {
6750 NEXT;
6751
6752 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006753 * Since currently the parser context don't have a
6754 * namespace list associated:
6755 * The namespace name for this prefix can be computed
6756 * only at evaluation time. The compilation is done
6757 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006758 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006759#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006760 *prefix = xmlXPathNsLookup(ctxt->context, name);
6761 if (name != NULL)
6762 xmlFree(name);
6763 if (*prefix == NULL) {
6764 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6765 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006766#else
6767 *prefix = name;
6768#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006769
6770 if (CUR == '*') {
6771 /*
6772 * All elements
6773 */
6774 NEXT;
6775 *test = NODE_TEST_ALL;
6776 return(NULL);
6777 }
6778
6779 name = xmlXPathParseNCName(ctxt);
6780 if (name == NULL) {
6781 XP_ERROR0(XPATH_EXPR_ERROR);
6782 }
6783 }
6784 return(name);
6785}
6786
6787/**
6788 * xmlXPathIsAxisName:
6789 * @name: a preparsed name token
6790 *
6791 * [6] AxisName ::= 'ancestor'
6792 * | 'ancestor-or-self'
6793 * | 'attribute'
6794 * | 'child'
6795 * | 'descendant'
6796 * | 'descendant-or-self'
6797 * | 'following'
6798 * | 'following-sibling'
6799 * | 'namespace'
6800 * | 'parent'
6801 * | 'preceding'
6802 * | 'preceding-sibling'
6803 * | 'self'
6804 *
6805 * Returns the axis or 0
6806 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006807static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006808xmlXPathIsAxisName(const xmlChar *name) {
6809 xmlXPathAxisVal ret = 0;
6810 switch (name[0]) {
6811 case 'a':
6812 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6813 ret = AXIS_ANCESTOR;
6814 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6815 ret = AXIS_ANCESTOR_OR_SELF;
6816 if (xmlStrEqual(name, BAD_CAST "attribute"))
6817 ret = AXIS_ATTRIBUTE;
6818 break;
6819 case 'c':
6820 if (xmlStrEqual(name, BAD_CAST "child"))
6821 ret = AXIS_CHILD;
6822 break;
6823 case 'd':
6824 if (xmlStrEqual(name, BAD_CAST "descendant"))
6825 ret = AXIS_DESCENDANT;
6826 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6827 ret = AXIS_DESCENDANT_OR_SELF;
6828 break;
6829 case 'f':
6830 if (xmlStrEqual(name, BAD_CAST "following"))
6831 ret = AXIS_FOLLOWING;
6832 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6833 ret = AXIS_FOLLOWING_SIBLING;
6834 break;
6835 case 'n':
6836 if (xmlStrEqual(name, BAD_CAST "namespace"))
6837 ret = AXIS_NAMESPACE;
6838 break;
6839 case 'p':
6840 if (xmlStrEqual(name, BAD_CAST "parent"))
6841 ret = AXIS_PARENT;
6842 if (xmlStrEqual(name, BAD_CAST "preceding"))
6843 ret = AXIS_PRECEDING;
6844 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6845 ret = AXIS_PRECEDING_SIBLING;
6846 break;
6847 case 's':
6848 if (xmlStrEqual(name, BAD_CAST "self"))
6849 ret = AXIS_SELF;
6850 break;
6851 }
6852 return(ret);
6853}
6854
6855/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006856 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006857 * @ctxt: the XPath Parser context
6858 *
6859 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6860 * | AbbreviatedStep
6861 *
6862 * [12] AbbreviatedStep ::= '.' | '..'
6863 *
6864 * [5] AxisSpecifier ::= AxisName '::'
6865 * | AbbreviatedAxisSpecifier
6866 *
6867 * [13] AbbreviatedAxisSpecifier ::= '@'?
6868 *
6869 * Modified for XPtr range support as:
6870 *
6871 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6872 * | AbbreviatedStep
6873 * | 'range-to' '(' Expr ')' Predicate*
6874 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006875 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006876 * A location step of . is short for self::node(). This is
6877 * particularly useful in conjunction with //. For example, the
6878 * location path .//para is short for
6879 * self::node()/descendant-or-self::node()/child::para
6880 * and so will select all para descendant elements of the context
6881 * node.
6882 * Similarly, a location step of .. is short for parent::node().
6883 * For example, ../title is short for parent::node()/child::title
6884 * and so will select the title children of the parent of the context
6885 * node.
6886 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006887static void
6888xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006889#ifdef LIBXML_XPTR_ENABLED
6890 int rangeto = 0;
6891 int op2 = -1;
6892#endif
6893
Owen Taylor3473f882001-02-23 17:55:21 +00006894 SKIP_BLANKS;
6895 if ((CUR == '.') && (NXT(1) == '.')) {
6896 SKIP(2);
6897 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006898 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6899 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006900 } else if (CUR == '.') {
6901 NEXT;
6902 SKIP_BLANKS;
6903 } else {
6904 xmlChar *name = NULL;
6905 const xmlChar *prefix = NULL;
6906 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006907 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006908 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006909 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006910
6911 /*
6912 * The modification needed for XPointer change to the production
6913 */
6914#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006915 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006916 name = xmlXPathParseNCName(ctxt);
6917 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006918 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006919 xmlFree(name);
6920 SKIP_BLANKS;
6921 if (CUR != '(') {
6922 XP_ERROR(XPATH_EXPR_ERROR);
6923 }
6924 NEXT;
6925 SKIP_BLANKS;
6926
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006927 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006928 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006929 CHECK_ERROR;
6930
6931 SKIP_BLANKS;
6932 if (CUR != ')') {
6933 XP_ERROR(XPATH_EXPR_ERROR);
6934 }
6935 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006936 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006937 goto eval_predicates;
6938 }
6939 }
6940#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006941 if (CUR == '*') {
6942 axis = AXIS_CHILD;
6943 } else {
6944 if (name == NULL)
6945 name = xmlXPathParseNCName(ctxt);
6946 if (name != NULL) {
6947 axis = xmlXPathIsAxisName(name);
6948 if (axis != 0) {
6949 SKIP_BLANKS;
6950 if ((CUR == ':') && (NXT(1) == ':')) {
6951 SKIP(2);
6952 xmlFree(name);
6953 name = NULL;
6954 } else {
6955 /* an element name can conflict with an axis one :-\ */
6956 axis = AXIS_CHILD;
6957 }
Owen Taylor3473f882001-02-23 17:55:21 +00006958 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00006959 axis = AXIS_CHILD;
6960 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006961 } else if (CUR == '@') {
6962 NEXT;
6963 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00006964 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00006965 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00006966 }
Owen Taylor3473f882001-02-23 17:55:21 +00006967 }
6968
6969 CHECK_ERROR;
6970
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006971 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006972 if (test == 0)
6973 return;
6974
6975#ifdef DEBUG_STEP
6976 xmlGenericError(xmlGenericErrorContext,
6977 "Basis : computing new set\n");
6978#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006979
Owen Taylor3473f882001-02-23 17:55:21 +00006980#ifdef DEBUG_STEP
6981 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006982 if (ctxt->value == NULL)
6983 xmlGenericError(xmlGenericErrorContext, "no value\n");
6984 else if (ctxt->value->nodesetval == NULL)
6985 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6986 else
6987 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006988#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006989
6990eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006991 op1 = ctxt->comp->last;
6992 ctxt->comp->last = -1;
6993
Owen Taylor3473f882001-02-23 17:55:21 +00006994 SKIP_BLANKS;
6995 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006996 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006997 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006998
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006999#ifdef LIBXML_XPTR_ENABLED
7000 if (rangeto) {
7001 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7002 } else
7003#endif
7004 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7005 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007006
Owen Taylor3473f882001-02-23 17:55:21 +00007007 }
7008#ifdef DEBUG_STEP
7009 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007010 if (ctxt->value == NULL)
7011 xmlGenericError(xmlGenericErrorContext, "no value\n");
7012 else if (ctxt->value->nodesetval == NULL)
7013 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7014 else
7015 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7016 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007017#endif
7018}
7019
7020/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007021 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007022 * @ctxt: the XPath Parser context
7023 *
7024 * [3] RelativeLocationPath ::= Step
7025 * | RelativeLocationPath '/' Step
7026 * | AbbreviatedRelativeLocationPath
7027 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7028 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007029 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007030 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007031static void
Owen Taylor3473f882001-02-23 17:55:21 +00007032#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007033xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007034#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007035xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007036#endif
7037(xmlXPathParserContextPtr ctxt) {
7038 SKIP_BLANKS;
7039 if ((CUR == '/') && (NXT(1) == '/')) {
7040 SKIP(2);
7041 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007042 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7043 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007044 } else if (CUR == '/') {
7045 NEXT;
7046 SKIP_BLANKS;
7047 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007048 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007049 SKIP_BLANKS;
7050 while (CUR == '/') {
7051 if ((CUR == '/') && (NXT(1) == '/')) {
7052 SKIP(2);
7053 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007054 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007055 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007056 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007057 } else if (CUR == '/') {
7058 NEXT;
7059 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007060 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007061 }
7062 SKIP_BLANKS;
7063 }
7064}
7065
7066/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007067 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007068 * @ctxt: the XPath Parser context
7069 *
7070 * [1] LocationPath ::= RelativeLocationPath
7071 * | AbsoluteLocationPath
7072 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7073 * | AbbreviatedAbsoluteLocationPath
7074 * [10] AbbreviatedAbsoluteLocationPath ::=
7075 * '//' RelativeLocationPath
7076 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007077 * Compile a location path
7078 *
Owen Taylor3473f882001-02-23 17:55:21 +00007079 * // is short for /descendant-or-self::node()/. For example,
7080 * //para is short for /descendant-or-self::node()/child::para and
7081 * so will select any para element in the document (even a para element
7082 * that is a document element will be selected by //para since the
7083 * document element node is a child of the root node); div//para is
7084 * short for div/descendant-or-self::node()/child::para and so will
7085 * select all para descendants of div children.
7086 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007087static void
7088xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007089 SKIP_BLANKS;
7090 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007091 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007092 } else {
7093 while (CUR == '/') {
7094 if ((CUR == '/') && (NXT(1) == '/')) {
7095 SKIP(2);
7096 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007097 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7098 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007099 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007100 } else if (CUR == '/') {
7101 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007102 SKIP_BLANKS;
7103 if ((CUR != 0 ) &&
7104 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7105 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007106 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007107 }
7108 }
7109 }
7110}
7111
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007112/************************************************************************
7113 * *
7114 * XPath precompiled expression evaluation *
7115 * *
7116 ************************************************************************/
7117
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007118static void
7119xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7120
7121/**
7122 * xmlXPathNodeCollectAndTest:
7123 * @ctxt: the XPath Parser context
7124 * @op: the XPath precompiled step operation
7125 *
7126 * This is the function implementing a step: based on the current list
7127 * of nodes, it builds up a new list, looking at all nodes under that
7128 * axis and selecting them it also do the predicate filtering
7129 *
7130 * Pushes the new NodeSet resulting from the search.
7131 */
7132static void
7133xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
7134 xmlXPathStepOpPtr op) {
7135 xmlXPathAxisVal axis = op->value;
7136 xmlXPathTestVal test = op->value2;
7137 xmlXPathTypeVal type = op->value3;
7138 const xmlChar *prefix = op->value4;
7139 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007140 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007141
7142#ifdef DEBUG_STEP
7143 int n = 0, t = 0;
7144#endif
7145 int i;
7146 xmlNodeSetPtr ret, list;
7147 xmlXPathTraversalFunction next = NULL;
7148 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
7149 xmlNodePtr cur = NULL;
7150 xmlXPathObjectPtr obj;
7151 xmlNodeSetPtr nodelist;
7152 xmlNodePtr tmp;
7153
7154 CHECK_TYPE(XPATH_NODESET);
7155 obj = valuePop(ctxt);
7156 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007157 if (prefix != NULL) {
7158 URI = xmlXPathNsLookup(ctxt->context, prefix);
7159 if (URI == NULL)
7160 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
7161 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007162
7163#ifdef DEBUG_STEP
7164 xmlGenericError(xmlGenericErrorContext,
7165 "new step : ");
7166#endif
7167 switch (axis) {
7168 case AXIS_ANCESTOR:
7169#ifdef DEBUG_STEP
7170 xmlGenericError(xmlGenericErrorContext,
7171 "axis 'ancestors' ");
7172#endif
7173 next = xmlXPathNextAncestor; break;
7174 case AXIS_ANCESTOR_OR_SELF:
7175#ifdef DEBUG_STEP
7176 xmlGenericError(xmlGenericErrorContext,
7177 "axis 'ancestors-or-self' ");
7178#endif
7179 next = xmlXPathNextAncestorOrSelf; break;
7180 case AXIS_ATTRIBUTE:
7181#ifdef DEBUG_STEP
7182 xmlGenericError(xmlGenericErrorContext,
7183 "axis 'attributes' ");
7184#endif
7185 next = xmlXPathNextAttribute; break;
7186 break;
7187 case AXIS_CHILD:
7188#ifdef DEBUG_STEP
7189 xmlGenericError(xmlGenericErrorContext,
7190 "axis 'child' ");
7191#endif
7192 next = xmlXPathNextChild; break;
7193 case AXIS_DESCENDANT:
7194#ifdef DEBUG_STEP
7195 xmlGenericError(xmlGenericErrorContext,
7196 "axis 'descendant' ");
7197#endif
7198 next = xmlXPathNextDescendant; break;
7199 case AXIS_DESCENDANT_OR_SELF:
7200#ifdef DEBUG_STEP
7201 xmlGenericError(xmlGenericErrorContext,
7202 "axis 'descendant-or-self' ");
7203#endif
7204 next = xmlXPathNextDescendantOrSelf; break;
7205 case AXIS_FOLLOWING:
7206#ifdef DEBUG_STEP
7207 xmlGenericError(xmlGenericErrorContext,
7208 "axis 'following' ");
7209#endif
7210 next = xmlXPathNextFollowing; break;
7211 case AXIS_FOLLOWING_SIBLING:
7212#ifdef DEBUG_STEP
7213 xmlGenericError(xmlGenericErrorContext,
7214 "axis 'following-siblings' ");
7215#endif
7216 next = xmlXPathNextFollowingSibling; break;
7217 case AXIS_NAMESPACE:
7218#ifdef DEBUG_STEP
7219 xmlGenericError(xmlGenericErrorContext,
7220 "axis 'namespace' ");
7221#endif
7222 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
7223 break;
7224 case AXIS_PARENT:
7225#ifdef DEBUG_STEP
7226 xmlGenericError(xmlGenericErrorContext,
7227 "axis 'parent' ");
7228#endif
7229 next = xmlXPathNextParent; break;
7230 case AXIS_PRECEDING:
7231#ifdef DEBUG_STEP
7232 xmlGenericError(xmlGenericErrorContext,
7233 "axis 'preceding' ");
7234#endif
7235 next = xmlXPathNextPreceding; break;
7236 case AXIS_PRECEDING_SIBLING:
7237#ifdef DEBUG_STEP
7238 xmlGenericError(xmlGenericErrorContext,
7239 "axis 'preceding-sibling' ");
7240#endif
7241 next = xmlXPathNextPrecedingSibling; break;
7242 case AXIS_SELF:
7243#ifdef DEBUG_STEP
7244 xmlGenericError(xmlGenericErrorContext,
7245 "axis 'self' ");
7246#endif
7247 next = xmlXPathNextSelf; break;
7248 }
7249 if (next == NULL)
7250 return;
7251
7252 nodelist = obj->nodesetval;
7253 if (nodelist == NULL) {
7254 xmlXPathFreeObject(obj);
7255 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7256 return;
7257 }
7258 addNode = xmlXPathNodeSetAddUnique;
7259 ret = NULL;
7260#ifdef DEBUG_STEP
7261 xmlGenericError(xmlGenericErrorContext,
7262 " context contains %d nodes\n",
7263 nodelist->nodeNr);
7264 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007265 case NODE_TEST_NONE:
7266 xmlGenericError(xmlGenericErrorContext,
7267 " searching for none !!!\n");
7268 break;
7269 case NODE_TEST_TYPE:
7270 xmlGenericError(xmlGenericErrorContext,
7271 " searching for type %d\n", type);
7272 break;
7273 case NODE_TEST_PI:
7274 xmlGenericError(xmlGenericErrorContext,
7275 " searching for PI !!!\n");
7276 break;
7277 case NODE_TEST_ALL:
7278 xmlGenericError(xmlGenericErrorContext,
7279 " searching for *\n");
7280 break;
7281 case NODE_TEST_NS:
7282 xmlGenericError(xmlGenericErrorContext,
7283 " searching for namespace %s\n",
7284 prefix);
7285 break;
7286 case NODE_TEST_NAME:
7287 xmlGenericError(xmlGenericErrorContext,
7288 " searching for name %s\n", name);
7289 if (prefix != NULL)
7290 xmlGenericError(xmlGenericErrorContext,
7291 " with namespace %s\n",
7292 prefix);
7293 break;
7294 }
7295 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7296#endif
7297 /*
7298 * 2.3 Node Tests
7299 * - For the attribute axis, the principal node type is attribute.
7300 * - For the namespace axis, the principal node type is namespace.
7301 * - For other axes, the principal node type is element.
7302 *
7303 * A node test * is true for any node of the
7304 * principal node type. For example, child::* willi
7305 * select all element children of the context node
7306 */
7307 tmp = ctxt->context->node;
7308 for (i = 0;i < nodelist->nodeNr; i++) {
7309 ctxt->context->node = nodelist->nodeTab[i];
7310
7311 cur = NULL;
7312 list = xmlXPathNodeSetCreate(NULL);
7313 do {
7314 cur = next(ctxt, cur);
7315 if (cur == NULL) break;
7316#ifdef DEBUG_STEP
7317 t++;
7318 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7319#endif
7320 switch (test) {
7321 case NODE_TEST_NONE:
7322 ctxt->context->node = tmp;
7323 STRANGE
7324 return;
7325 case NODE_TEST_TYPE:
7326 if ((cur->type == type) ||
7327 ((type == NODE_TYPE_NODE) &&
7328 ((cur->type == XML_DOCUMENT_NODE) ||
7329 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7330 (cur->type == XML_ELEMENT_NODE) ||
7331 (cur->type == XML_PI_NODE) ||
7332 (cur->type == XML_COMMENT_NODE) ||
7333 (cur->type == XML_CDATA_SECTION_NODE) ||
7334 (cur->type == XML_TEXT_NODE)))) {
7335#ifdef DEBUG_STEP
7336 n++;
7337#endif
7338 addNode(list, cur);
7339 }
7340 break;
7341 case NODE_TEST_PI:
7342 if (cur->type == XML_PI_NODE) {
7343 if ((name != NULL) &&
7344 (!xmlStrEqual(name, cur->name)))
7345 break;
7346#ifdef DEBUG_STEP
7347 n++;
7348#endif
7349 addNode(list, cur);
7350 }
7351 break;
7352 case NODE_TEST_ALL:
7353 if (axis == AXIS_ATTRIBUTE) {
7354 if (cur->type == XML_ATTRIBUTE_NODE) {
7355#ifdef DEBUG_STEP
7356 n++;
7357#endif
7358 addNode(list, cur);
7359 }
7360 } else if (axis == AXIS_NAMESPACE) {
7361 if (cur->type == XML_NAMESPACE_DECL) {
7362#ifdef DEBUG_STEP
7363 n++;
7364#endif
7365 addNode(list, cur);
7366 }
7367 } else {
Daniel Veillard8cf14d52001-06-23 16:32:46 +00007368 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007369 if (prefix == NULL) {
7370#ifdef DEBUG_STEP
7371 n++;
7372#endif
7373 addNode(list, cur);
7374 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007375 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007376 cur->ns->href))) {
7377#ifdef DEBUG_STEP
7378 n++;
7379#endif
7380 addNode(list, cur);
7381 }
7382 }
7383 }
7384 break;
7385 case NODE_TEST_NS: {
7386 TODO;
7387 break;
7388 }
7389 case NODE_TEST_NAME:
7390 switch (cur->type) {
7391 case XML_ELEMENT_NODE:
7392 if (xmlStrEqual(name, cur->name)) {
7393 if (prefix == NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00007394 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007395#ifdef DEBUG_STEP
7396 n++;
7397#endif
7398 addNode(list, cur);
7399 }
7400 } else {
7401 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007402 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007403 cur->ns->href))) {
7404#ifdef DEBUG_STEP
7405 n++;
7406#endif
7407 addNode(list, cur);
7408 }
7409 }
7410 }
7411 break;
7412 case XML_ATTRIBUTE_NODE: {
7413 xmlAttrPtr attr = (xmlAttrPtr) cur;
7414 if (xmlStrEqual(name, attr->name)) {
7415 if (prefix == NULL) {
7416 if ((attr->ns == NULL) ||
7417 (attr->ns->prefix == NULL)) {
7418#ifdef DEBUG_STEP
7419 n++;
7420#endif
7421 addNode(list, (xmlNodePtr) attr);
7422 }
7423 } else {
7424 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007425 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007426 attr->ns->href))) {
7427#ifdef DEBUG_STEP
7428 n++;
7429#endif
7430 addNode(list, (xmlNodePtr) attr);
7431 }
7432 }
7433 }
7434 break;
7435 }
Daniel Veillard8b8d2252001-06-16 21:24:56 +00007436 case XML_NAMESPACE_DECL:
7437 if (cur->type == XML_NAMESPACE_DECL) {
7438 xmlNsPtr ns = (xmlNsPtr) cur;
7439 if ((ns->prefix != NULL) && (name != NULL) &&
7440 (xmlStrEqual(ns->prefix, name))) {
7441#ifdef DEBUG_STEP
7442 n++;
7443#endif
7444 addNode(list, cur);
7445 }
7446 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007447 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007448 default:
7449 break;
7450 }
7451 break;
7452 }
7453 } while (cur != NULL);
7454
7455 /*
7456 * If there is some predicate filtering do it now
7457 */
7458 if (op->ch2 != -1) {
7459 xmlXPathObjectPtr obj2;
7460
7461 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7462 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7463 CHECK_TYPE(XPATH_NODESET);
7464 obj2 = valuePop(ctxt);
7465 list = obj2->nodesetval;
7466 obj2->nodesetval = NULL;
7467 xmlXPathFreeObject(obj2);
7468 }
7469 if (ret == NULL) {
7470 ret = list;
7471 } else {
7472 ret = xmlXPathNodeSetMerge(ret, list);
7473 xmlXPathFreeNodeSet(list);
7474 }
7475 }
7476 ctxt->context->node = tmp;
7477#ifdef DEBUG_STEP
7478 xmlGenericError(xmlGenericErrorContext,
7479 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7480#endif
7481 xmlXPathFreeObject(obj);
7482 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7483}
7484
Owen Taylor3473f882001-02-23 17:55:21 +00007485/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007486 * xmlXPathCompOpEval:
7487 * @ctxt: the XPath parser context with the compiled expression
7488 * @op: an XPath compiled operation
7489 *
7490 * Evaluate the Precompiled XPath operation
7491 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007492static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007493xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7494 int equal, ret;
7495 xmlXPathCompExprPtr comp;
7496 xmlXPathObjectPtr arg1, arg2;
7497
7498 comp = ctxt->comp;
7499 switch (op->op) {
7500 case XPATH_OP_END:
7501 return;
7502 case XPATH_OP_AND:
7503 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7504 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007505 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007506 return;
7507 arg2 = valuePop(ctxt);
7508 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7509 xmlXPathBooleanFunction(ctxt, 1);
7510 arg1 = valuePop(ctxt);
7511 arg1->boolval &= arg2->boolval;
7512 valuePush(ctxt, arg1);
7513 xmlXPathFreeObject(arg2);
7514 return;
7515 case XPATH_OP_OR:
7516 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7517 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007518 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007519 return;
7520 arg2 = valuePop(ctxt);
7521 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7522 xmlXPathBooleanFunction(ctxt, 1);
7523 arg1 = valuePop(ctxt);
7524 arg1->boolval |= arg2->boolval;
7525 valuePush(ctxt, arg1);
7526 xmlXPathFreeObject(arg2);
7527 return;
7528 case XPATH_OP_EQUAL:
7529 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7530 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7531 equal = xmlXPathEqualValues(ctxt);
7532 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7533 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7534 return;
7535 case XPATH_OP_CMP:
7536 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7537 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7538 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7539 valuePush(ctxt, xmlXPathNewBoolean(ret));
7540 return;
7541 case XPATH_OP_PLUS:
7542 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7543 if (op->ch2 != -1)
7544 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7545 if (op->value == 0) xmlXPathSubValues(ctxt);
7546 else if (op->value == 1) xmlXPathAddValues(ctxt);
7547 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7548 else if (op->value == 3) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007549 CAST_TO_NUMBER;
7550 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007551 }
7552 return;
7553 case XPATH_OP_MULT:
7554 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7555 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7556 if (op->value == 0) xmlXPathMultValues(ctxt);
7557 else if (op->value == 1) xmlXPathDivValues(ctxt);
7558 else if (op->value == 2) xmlXPathModValues(ctxt);
7559 return;
7560 case XPATH_OP_UNION:
7561 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7562 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7563 CHECK_TYPE(XPATH_NODESET);
7564 arg2 = valuePop(ctxt);
7565
7566 CHECK_TYPE(XPATH_NODESET);
7567 arg1 = valuePop(ctxt);
7568
7569 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7570 arg2->nodesetval);
7571 valuePush(ctxt, arg1);
7572 xmlXPathFreeObject(arg2);
7573 return;
7574 case XPATH_OP_ROOT:
7575 xmlXPathRoot(ctxt);
7576 return;
7577 case XPATH_OP_NODE:
7578 if (op->ch1 != -1)
7579 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7580 if (op->ch2 != -1)
7581 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7582 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7583 return;
7584 case XPATH_OP_RESET:
7585 if (op->ch1 != -1)
7586 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7587 if (op->ch2 != -1)
7588 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7589 ctxt->context->node = NULL;
7590 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007591 case XPATH_OP_COLLECT: {
7592 if (op->ch1 == -1)
7593 return;
7594
7595 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7596 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007597 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007598 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007599 case XPATH_OP_VALUE:
7600 valuePush(ctxt,
7601 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7602 return;
7603 case XPATH_OP_VARIABLE: {
7604 if (op->ch1 != -1)
7605 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7606 if (op->value5 == NULL)
7607 valuePush(ctxt,
7608 xmlXPathVariableLookup(ctxt->context, op->value4));
7609 else {
7610 const xmlChar *URI;
7611 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7612 if (URI == NULL) {
7613 xmlGenericError(xmlGenericErrorContext,
7614 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7615 op->value4, op->value5);
7616 return;
7617 }
7618 valuePush(ctxt,
7619 xmlXPathVariableLookupNS(ctxt->context,
7620 op->value4, URI));
7621 }
7622 return;
7623 }
7624 case XPATH_OP_FUNCTION: {
7625 xmlXPathFunction func;
Daniel Veillard42596ad2001-05-22 16:57:14 +00007626 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007627
7628 if (op->ch1 != -1)
7629 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007630 if (op->cache != NULL)
7631 func = (xmlXPathFunction) op->cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007632 else {
Daniel Veillard42596ad2001-05-22 16:57:14 +00007633 const xmlChar *URI = NULL;
7634
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007635 if (op->value5 == NULL)
7636 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7637 else {
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007638 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7639 if (URI == NULL) {
7640 xmlGenericError(xmlGenericErrorContext,
7641 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7642 op->value4, op->value5);
7643 return;
7644 }
7645 func = xmlXPathFunctionLookupNS(ctxt->context,
7646 op->value4, URI);
7647 }
7648 if (func == NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007649 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007650 "xmlXPathRunEval: function %s not found\n",
7651 op->value4);
7652 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007653 return;
7654 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007655 op->cache = (void *) func;
Daniel Veillard42596ad2001-05-22 16:57:14 +00007656 op->cacheURI = (void *) URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007657 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00007658 oldFunc = ctxt->context->function;
7659 oldFuncURI = ctxt->context->functionURI;
7660 ctxt->context->function = op->value4;
7661 ctxt->context->functionURI = op->cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007662 func(ctxt, op->value);
Daniel Veillard42596ad2001-05-22 16:57:14 +00007663 ctxt->context->function = oldFunc;
7664 ctxt->context->functionURI = oldFuncURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007665 return;
7666 }
7667 case XPATH_OP_ARG:
7668 if (op->ch1 != -1)
7669 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7670 if (op->ch2 != -1)
7671 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7672 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007673 case XPATH_OP_PREDICATE:
7674 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007675 xmlXPathObjectPtr res;
7676 xmlXPathObjectPtr obj, tmp;
7677 xmlNodeSetPtr newset = NULL;
7678 xmlNodeSetPtr oldset;
7679 xmlNodePtr oldnode;
7680 int i;
7681
7682 if (op->ch1 != -1)
7683 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7684 if (op->ch2 == -1)
7685 return;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007686 if (ctxt->value == NULL)
7687 return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007688
7689 oldnode = ctxt->context->node;
7690
7691#ifdef LIBXML_XPTR_ENABLED
7692 /*
7693 * Hum are we filtering the result of an XPointer expression
7694 */
7695 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007696 xmlLocationSetPtr newlocset = NULL;
7697 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007698
7699 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007700 * Extract the old locset, and then evaluate the result of the
7701 * expression for all the element in the locset. use it to grow
7702 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007703 */
7704 CHECK_TYPE(XPATH_LOCATIONSET);
7705 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007706 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007707 ctxt->context->node = NULL;
7708
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007709 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007710 ctxt->context->contextSize = 0;
7711 ctxt->context->proximityPosition = 0;
7712 if (op->ch2 != -1)
7713 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7714 res = valuePop(ctxt);
7715 if (res != NULL)
7716 xmlXPathFreeObject(res);
7717 valuePush(ctxt, obj);
7718 CHECK_ERROR;
7719 return;
7720 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007721 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007722
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007723 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007724 /*
7725 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007726 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007727 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007728 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007729 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7730 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007731 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007732 ctxt->context->proximityPosition = i + 1;
7733
7734 if (op->ch2 != -1)
7735 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7736 CHECK_ERROR;
7737
7738 /*
7739 * The result of the evaluation need to be tested to
7740 * decided whether the filter succeeded or not
7741 */
7742 res = valuePop(ctxt);
7743 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007744 xmlXPtrLocationSetAdd(newlocset,
7745 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007746 }
7747
7748 /*
7749 * Cleanup
7750 */
7751 if (res != NULL)
7752 xmlXPathFreeObject(res);
7753 if (ctxt->value == tmp) {
7754 res = valuePop(ctxt);
7755 xmlXPathFreeObject(res);
7756 }
7757
7758 ctxt->context->node = NULL;
7759 }
7760
7761 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007762 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007763 */
7764 xmlXPathFreeObject(obj);
7765 ctxt->context->node = NULL;
7766 ctxt->context->contextSize = -1;
7767 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007768 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007769 ctxt->context->node = oldnode;
7770 return;
7771 }
7772#endif /* LIBXML_XPTR_ENABLED */
7773
7774 /*
7775 * Extract the old set, and then evaluate the result of the
7776 * expression for all the element in the set. use it to grow
7777 * up a new set.
7778 */
7779 CHECK_TYPE(XPATH_NODESET);
7780 obj = valuePop(ctxt);
7781 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007782
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007783 oldnode = ctxt->context->node;
7784 ctxt->context->node = NULL;
7785
7786 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7787 ctxt->context->contextSize = 0;
7788 ctxt->context->proximityPosition = 0;
7789 if (op->ch2 != -1)
7790 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7791 res = valuePop(ctxt);
7792 if (res != NULL)
7793 xmlXPathFreeObject(res);
7794 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007795 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007796 CHECK_ERROR;
7797 } else {
7798 /*
7799 * Initialize the new set.
7800 */
7801 newset = xmlXPathNodeSetCreate(NULL);
7802
7803 for (i = 0; i < oldset->nodeNr; i++) {
7804 /*
7805 * Run the evaluation with a node list made of
7806 * a single item in the nodeset.
7807 */
7808 ctxt->context->node = oldset->nodeTab[i];
7809 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7810 valuePush(ctxt, tmp);
7811 ctxt->context->contextSize = oldset->nodeNr;
7812 ctxt->context->proximityPosition = i + 1;
7813
7814 if (op->ch2 != -1)
7815 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7816 CHECK_ERROR;
7817
7818 /*
7819 * The result of the evaluation need to be tested to
7820 * decided whether the filter succeeded or not
7821 */
7822 res = valuePop(ctxt);
7823 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7824 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7825 }
7826
7827 /*
7828 * Cleanup
7829 */
7830 if (res != NULL)
7831 xmlXPathFreeObject(res);
7832 if (ctxt->value == tmp) {
7833 res = valuePop(ctxt);
7834 xmlXPathFreeObject(res);
7835 }
7836
7837 ctxt->context->node = NULL;
7838 }
7839
7840 /*
7841 * The result is used as the new evaluation set.
7842 */
7843 xmlXPathFreeObject(obj);
7844 ctxt->context->node = NULL;
7845 ctxt->context->contextSize = -1;
7846 ctxt->context->proximityPosition = -1;
7847 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7848 }
7849 ctxt->context->node = oldnode;
7850 return;
7851 }
7852 case XPATH_OP_SORT:
7853 if (op->ch1 != -1)
7854 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7855 if ((ctxt->value != NULL) &&
7856 (ctxt->value->type == XPATH_NODESET) &&
7857 (ctxt->value->nodesetval != NULL))
7858 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7859 return;
7860#ifdef LIBXML_XPTR_ENABLED
7861 case XPATH_OP_RANGETO: {
7862 xmlXPathObjectPtr range;
7863 xmlXPathObjectPtr res, obj;
7864 xmlXPathObjectPtr tmp;
7865 xmlLocationSetPtr newset = NULL;
7866 xmlNodeSetPtr oldset;
7867 int i;
7868
7869 if (op->ch1 != -1)
7870 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7871 if (op->ch2 == -1)
7872 return;
7873
7874 CHECK_TYPE(XPATH_NODESET);
7875 obj = valuePop(ctxt);
7876 oldset = obj->nodesetval;
7877 ctxt->context->node = NULL;
7878
7879 newset = xmlXPtrLocationSetCreate(NULL);
7880
Daniel Veillard911f49a2001-04-07 15:39:35 +00007881 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007882 for (i = 0; i < oldset->nodeNr; i++) {
7883 /*
7884 * Run the evaluation with a node list made of a single item
7885 * in the nodeset.
7886 */
7887 ctxt->context->node = oldset->nodeTab[i];
7888 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7889 valuePush(ctxt, tmp);
7890
7891 if (op->ch2 != -1)
7892 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7893 CHECK_ERROR;
7894
7895 /*
7896 * The result of the evaluation need to be tested to
7897 * decided whether the filter succeeded or not
7898 */
7899 res = valuePop(ctxt);
7900 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7901 if (range != NULL) {
7902 xmlXPtrLocationSetAdd(newset, range);
7903 }
7904
7905 /*
7906 * Cleanup
7907 */
7908 if (res != NULL)
7909 xmlXPathFreeObject(res);
7910 if (ctxt->value == tmp) {
7911 res = valuePop(ctxt);
7912 xmlXPathFreeObject(res);
7913 }
7914
7915 ctxt->context->node = NULL;
7916 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007917 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007918
7919 /*
7920 * The result is used as the new evaluation set.
7921 */
7922 xmlXPathFreeObject(obj);
7923 ctxt->context->node = NULL;
7924 ctxt->context->contextSize = -1;
7925 ctxt->context->proximityPosition = -1;
7926 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7927 return;
7928 }
7929#endif /* LIBXML_XPTR_ENABLED */
7930 }
7931 xmlGenericError(xmlGenericErrorContext,
7932 "XPath: unknown precompiled operation %d\n",
7933 op->op);
7934 return;
7935}
7936
7937/**
7938 * xmlXPathRunEval:
7939 * @ctxt: the XPath parser context with the compiled expression
7940 *
7941 * Evaluate the Precompiled XPath expression in the given context.
7942 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007943static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007944xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7945 xmlXPathCompExprPtr comp;
7946
7947 if ((ctxt == NULL) || (ctxt->comp == NULL))
7948 return;
7949
7950 if (ctxt->valueTab == NULL) {
7951 /* Allocate the value stack */
7952 ctxt->valueTab = (xmlXPathObjectPtr *)
7953 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7954 if (ctxt->valueTab == NULL) {
7955 xmlFree(ctxt);
7956 xmlGenericError(xmlGenericErrorContext,
7957 "xmlXPathRunEval: out of memory\n");
7958 return;
7959 }
7960 ctxt->valueNr = 0;
7961 ctxt->valueMax = 10;
7962 ctxt->value = NULL;
7963 }
7964 comp = ctxt->comp;
7965 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7966}
7967
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007968/************************************************************************
7969 * *
7970 * Public interfaces *
7971 * *
7972 ************************************************************************/
7973
7974/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007975 * xmlXPathEvalPredicate:
7976 * @ctxt: the XPath context
7977 * @res: the Predicate Expression evaluation result
7978 *
7979 * Evaluate a predicate result for the current node.
7980 * A PredicateExpr is evaluated by evaluating the Expr and converting
7981 * the result to a boolean. If the result is a number, the result will
7982 * be converted to true if the number is equal to the position of the
7983 * context node in the context node list (as returned by the position
7984 * function) and will be converted to false otherwise; if the result
7985 * is not a number, then the result will be converted as if by a call
7986 * to the boolean function.
7987 *
7988 * Return 1 if predicate is true, 0 otherwise
7989 */
7990int
7991xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7992 if (res == NULL) return(0);
7993 switch (res->type) {
7994 case XPATH_BOOLEAN:
7995 return(res->boolval);
7996 case XPATH_NUMBER:
7997 return(res->floatval == ctxt->proximityPosition);
7998 case XPATH_NODESET:
7999 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008000 if (res->nodesetval == NULL)
8001 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008002 return(res->nodesetval->nodeNr != 0);
8003 case XPATH_STRING:
8004 return((res->stringval != NULL) &&
8005 (xmlStrlen(res->stringval) != 0));
8006 default:
8007 STRANGE
8008 }
8009 return(0);
8010}
8011
8012/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008013 * xmlXPathEvaluatePredicateResult:
8014 * @ctxt: the XPath Parser context
8015 * @res: the Predicate Expression evaluation result
8016 *
8017 * Evaluate a predicate result for the current node.
8018 * A PredicateExpr is evaluated by evaluating the Expr and converting
8019 * the result to a boolean. If the result is a number, the result will
8020 * be converted to true if the number is equal to the position of the
8021 * context node in the context node list (as returned by the position
8022 * function) and will be converted to false otherwise; if the result
8023 * is not a number, then the result will be converted as if by a call
8024 * to the boolean function.
8025 *
8026 * Return 1 if predicate is true, 0 otherwise
8027 */
8028int
8029xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
8030 xmlXPathObjectPtr res) {
8031 if (res == NULL) return(0);
8032 switch (res->type) {
8033 case XPATH_BOOLEAN:
8034 return(res->boolval);
8035 case XPATH_NUMBER:
8036 return(res->floatval == ctxt->context->proximityPosition);
8037 case XPATH_NODESET:
8038 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00008039 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00008040 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008041 return(res->nodesetval->nodeNr != 0);
8042 case XPATH_STRING:
8043 return((res->stringval != NULL) &&
8044 (xmlStrlen(res->stringval) != 0));
8045 default:
8046 STRANGE
8047 }
8048 return(0);
8049}
8050
8051/**
8052 * xmlXPathCompile:
8053 * @str: the XPath expression
8054 *
8055 * Compile an XPath expression
8056 *
8057 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8058 * the caller has to free the object.
8059 */
8060xmlXPathCompExprPtr
8061xmlXPathCompile(const xmlChar *str) {
8062 xmlXPathParserContextPtr ctxt;
8063 xmlXPathCompExprPtr comp;
8064
8065 xmlXPathInit();
8066
8067 ctxt = xmlXPathNewParserContext(str, NULL);
8068 xmlXPathCompileExpr(ctxt);
8069
Daniel Veillard40af6492001-04-22 08:50:55 +00008070 if (*ctxt->cur != 0) {
8071 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8072 comp = NULL;
8073 } else {
8074 comp = ctxt->comp;
8075 ctxt->comp = NULL;
8076 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008077 xmlXPathFreeParserContext(ctxt);
8078 return(comp);
8079}
8080
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008081/**
8082 * xmlXPathCompiledEval:
8083 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00008084 * @ctx: the XPath context
8085 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008086 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00008087 *
8088 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8089 * the caller has to free the object.
8090 */
8091xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008092xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00008093 xmlXPathParserContextPtr ctxt;
8094 xmlXPathObjectPtr res, tmp, init = NULL;
8095 int stack = 0;
8096
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008097 if ((comp == NULL) || (ctx == NULL))
8098 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008099 xmlXPathInit();
8100
8101 CHECK_CONTEXT(ctx)
8102
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008103 ctxt = xmlXPathCompParserContext(comp, ctx);
8104 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008105
8106 if (ctxt->value == NULL) {
8107 xmlGenericError(xmlGenericErrorContext,
8108 "xmlXPathEval: evaluation failed\n");
8109 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00008110 } else {
8111 res = valuePop(ctxt);
8112 }
8113
8114 do {
8115 tmp = valuePop(ctxt);
8116 if (tmp != NULL) {
8117 if (tmp != init)
8118 stack++;
8119 xmlXPathFreeObject(tmp);
8120 }
8121 } while (tmp != NULL);
8122 if ((stack != 0) && (res != NULL)) {
8123 xmlGenericError(xmlGenericErrorContext,
8124 "xmlXPathEval: %d object left on the stack\n",
8125 stack);
8126 }
8127 if (ctxt->error != XPATH_EXPRESSION_OK) {
8128 xmlXPathFreeObject(res);
8129 res = NULL;
8130 }
8131
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008132
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008133 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008134 xmlXPathFreeParserContext(ctxt);
8135 return(res);
8136}
8137
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008138/**
8139 * xmlXPathEvalExpr:
8140 * @ctxt: the XPath Parser context
8141 *
8142 * Parse and evaluate an XPath expression in the given context,
8143 * then push the result on the context stack
8144 */
8145void
8146xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
8147 xmlXPathCompileExpr(ctxt);
8148 xmlXPathRunEval(ctxt);
8149}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008150
8151/**
8152 * xmlXPathEval:
8153 * @str: the XPath expression
8154 * @ctx: the XPath context
8155 *
8156 * Evaluate the XPath Location Path in the given context.
8157 *
8158 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8159 * the caller has to free the object.
8160 */
8161xmlXPathObjectPtr
8162xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
8163 xmlXPathParserContextPtr ctxt;
8164 xmlXPathObjectPtr res, tmp, init = NULL;
8165 int stack = 0;
8166
8167 xmlXPathInit();
8168
8169 CHECK_CONTEXT(ctx)
8170
8171 ctxt = xmlXPathNewParserContext(str, ctx);
8172 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008173
8174 if (ctxt->value == NULL) {
8175 xmlGenericError(xmlGenericErrorContext,
8176 "xmlXPathEval: evaluation failed\n");
8177 res = NULL;
8178 } else if (*ctxt->cur != 0) {
8179 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8180 res = NULL;
8181 } else {
8182 res = valuePop(ctxt);
8183 }
8184
8185 do {
8186 tmp = valuePop(ctxt);
8187 if (tmp != NULL) {
8188 if (tmp != init)
8189 stack++;
8190 xmlXPathFreeObject(tmp);
8191 }
8192 } while (tmp != NULL);
8193 if ((stack != 0) && (res != NULL)) {
8194 xmlGenericError(xmlGenericErrorContext,
8195 "xmlXPathEval: %d object left on the stack\n",
8196 stack);
8197 }
8198 if (ctxt->error != XPATH_EXPRESSION_OK) {
8199 xmlXPathFreeObject(res);
8200 res = NULL;
8201 }
8202
Owen Taylor3473f882001-02-23 17:55:21 +00008203 xmlXPathFreeParserContext(ctxt);
8204 return(res);
8205}
8206
8207/**
8208 * xmlXPathEvalExpression:
8209 * @str: the XPath expression
8210 * @ctxt: the XPath context
8211 *
8212 * Evaluate the XPath expression in the given context.
8213 *
8214 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
8215 * the caller has to free the object.
8216 */
8217xmlXPathObjectPtr
8218xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
8219 xmlXPathParserContextPtr pctxt;
8220 xmlXPathObjectPtr res, tmp;
8221 int stack = 0;
8222
8223 xmlXPathInit();
8224
8225 CHECK_CONTEXT(ctxt)
8226
8227 pctxt = xmlXPathNewParserContext(str, ctxt);
8228 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008229
8230 if (*pctxt->cur != 0) {
8231 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8232 res = NULL;
8233 } else {
8234 res = valuePop(pctxt);
8235 }
8236 do {
8237 tmp = valuePop(pctxt);
8238 if (tmp != NULL) {
8239 xmlXPathFreeObject(tmp);
8240 stack++;
8241 }
8242 } while (tmp != NULL);
8243 if ((stack != 0) && (res != NULL)) {
8244 xmlGenericError(xmlGenericErrorContext,
8245 "xmlXPathEvalExpression: %d object left on the stack\n",
8246 stack);
8247 }
8248 xmlXPathFreeParserContext(pctxt);
8249 return(res);
8250}
8251
8252/**
8253 * xmlXPathRegisterAllFunctions:
8254 * @ctxt: the XPath context
8255 *
8256 * Registers all default XPath functions in this context
8257 */
8258void
8259xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
8260{
8261 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
8262 xmlXPathBooleanFunction);
8263 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
8264 xmlXPathCeilingFunction);
8265 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
8266 xmlXPathCountFunction);
8267 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
8268 xmlXPathConcatFunction);
8269 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
8270 xmlXPathContainsFunction);
8271 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
8272 xmlXPathIdFunction);
8273 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
8274 xmlXPathFalseFunction);
8275 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
8276 xmlXPathFloorFunction);
8277 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
8278 xmlXPathLastFunction);
8279 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
8280 xmlXPathLangFunction);
8281 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
8282 xmlXPathLocalNameFunction);
8283 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
8284 xmlXPathNotFunction);
8285 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
8286 xmlXPathNameFunction);
8287 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
8288 xmlXPathNamespaceURIFunction);
8289 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
8290 xmlXPathNormalizeFunction);
8291 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
8292 xmlXPathNumberFunction);
8293 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
8294 xmlXPathPositionFunction);
8295 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
8296 xmlXPathRoundFunction);
8297 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
8298 xmlXPathStringFunction);
8299 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
8300 xmlXPathStringLengthFunction);
8301 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
8302 xmlXPathStartsWithFunction);
8303 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
8304 xmlXPathSubstringFunction);
8305 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
8306 xmlXPathSubstringBeforeFunction);
8307 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
8308 xmlXPathSubstringAfterFunction);
8309 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
8310 xmlXPathSumFunction);
8311 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
8312 xmlXPathTrueFunction);
8313 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
8314 xmlXPathTranslateFunction);
8315}
8316
8317#endif /* LIBXML_XPATH_ENABLED */