blob: 90ebe1bab7052cb9e8b41179db43c8102a7622ea [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 *
13 * Author: Daniel.Veillard@w3.org
14 *
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}
558#endif
559
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}
Owen Taylor3473f882001-02-23 17:55:21 +0000866#endif
867
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 */
1017 integer_place = 1 + (int)log10(absolute_value);
1018 fraction_place = (integer_place > 0)
1019 ? DBL_DIG - integer_place
1020 : DBL_DIG;
1021 size = snprintf(work, sizeof(work), "%0.*f",
1022 fraction_place, number);
1023 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001024 }
1025
Bjorn Reese70a9da52001-04-21 16:57:29 +00001026 /* Remove fractional trailing zeroes */
1027 ptr = after_fraction;
1028 while (*(--ptr) == '0')
1029 ;
1030 if (*ptr != '.')
1031 ptr++;
1032 strcpy(ptr, after_fraction);
1033
1034 /* Finally copy result back to caller */
1035 size = strlen(work) + 1;
1036 if (size > buffersize) {
1037 work[buffersize - 1] = 0;
1038 size = buffersize;
1039 }
1040 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001041 }
1042 break;
1043 }
1044}
1045
Owen Taylor3473f882001-02-23 17:55:21 +00001046/************************************************************************
1047 * *
1048 * Error handling routines *
1049 * *
1050 ************************************************************************/
1051
1052
1053const char *xmlXPathErrorMessages[] = {
1054 "Ok",
1055 "Number encoding",
1056 "Unfinished litteral",
1057 "Start of litteral",
1058 "Expected $ for variable reference",
1059 "Undefined variable",
1060 "Invalid predicate",
1061 "Invalid expression",
1062 "Missing closing curly brace",
1063 "Unregistered function",
1064 "Invalid operand",
1065 "Invalid type",
1066 "Invalid number of arguments",
1067 "Invalid context size",
1068 "Invalid context position",
1069 "Memory allocation error",
1070 "Syntax error",
1071 "Resource error",
1072 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001073 "Undefined namespace prefix",
1074 "Encoding error",
1075 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001076};
1077
1078/**
1079 * xmlXPathError:
1080 * @ctxt: the XPath Parser context
1081 * @file: the file name
1082 * @line: the line number
1083 * @no: the error number
1084 *
1085 * Create a new xmlNodeSetPtr of type double and of value @val
1086 *
1087 * Returns the newly created object.
1088 */
1089void
1090xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1091 int line, int no) {
1092 int n;
1093 const xmlChar *cur;
1094 const xmlChar *base;
1095
1096 xmlGenericError(xmlGenericErrorContext,
1097 "Error %s:%d: %s\n", file, line,
1098 xmlXPathErrorMessages[no]);
1099
1100 cur = ctxt->cur;
1101 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001102 if ((cur == NULL) || (base == NULL))
1103 return;
1104
Owen Taylor3473f882001-02-23 17:55:21 +00001105 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1106 cur--;
1107 }
1108 n = 0;
1109 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1110 cur--;
1111 if ((*cur == '\n') || (*cur == '\r')) cur++;
1112 base = cur;
1113 n = 0;
1114 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1115 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1116 n++;
1117 }
1118 xmlGenericError(xmlGenericErrorContext, "\n");
1119 cur = ctxt->cur;
1120 while ((*cur == '\n') || (*cur == '\r'))
1121 cur--;
1122 n = 0;
1123 while ((cur != base) && (n++ < 80)) {
1124 xmlGenericError(xmlGenericErrorContext, " ");
1125 base++;
1126 }
1127 xmlGenericError(xmlGenericErrorContext,"^\n");
1128}
1129
1130
1131/************************************************************************
1132 * *
1133 * Routines to handle NodeSets *
1134 * *
1135 ************************************************************************/
1136
1137/**
1138 * xmlXPathCmpNodes:
1139 * @node1: the first node
1140 * @node2: the second node
1141 *
1142 * Compare two nodes w.r.t document order
1143 *
1144 * Returns -2 in case of error 1 if first point < second point, 0 if
1145 * that's the same node, -1 otherwise
1146 */
1147int
1148xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1149 int depth1, depth2;
1150 xmlNodePtr cur, root;
1151
1152 if ((node1 == NULL) || (node2 == NULL))
1153 return(-2);
1154 /*
1155 * a couple of optimizations which will avoid computations in most cases
1156 */
1157 if (node1 == node2)
1158 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001159 if ((node1->type == XML_NAMESPACE_DECL) ||
1160 (node2->type == XML_NAMESPACE_DECL))
1161 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001162 if (node1 == node2->prev)
1163 return(1);
1164 if (node1 == node2->next)
1165 return(-1);
1166
1167 /*
1168 * compute depth to root
1169 */
1170 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1171 if (cur == node1)
1172 return(1);
1173 depth2++;
1174 }
1175 root = cur;
1176 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1177 if (cur == node2)
1178 return(-1);
1179 depth1++;
1180 }
1181 /*
1182 * Distinct document (or distinct entities :-( ) case.
1183 */
1184 if (root != cur) {
1185 return(-2);
1186 }
1187 /*
1188 * get the nearest common ancestor.
1189 */
1190 while (depth1 > depth2) {
1191 depth1--;
1192 node1 = node1->parent;
1193 }
1194 while (depth2 > depth1) {
1195 depth2--;
1196 node2 = node2->parent;
1197 }
1198 while (node1->parent != node2->parent) {
1199 node1 = node1->parent;
1200 node2 = node2->parent;
1201 /* should not happen but just in case ... */
1202 if ((node1 == NULL) || (node2 == NULL))
1203 return(-2);
1204 }
1205 /*
1206 * Find who's first.
1207 */
1208 if (node1 == node2->next)
1209 return(-1);
1210 for (cur = node1->next;cur != NULL;cur = cur->next)
1211 if (cur == node2)
1212 return(1);
1213 return(-1); /* assume there is no sibling list corruption */
1214}
1215
1216/**
1217 * xmlXPathNodeSetSort:
1218 * @set: the node set
1219 *
1220 * Sort the node set in document order
1221 */
1222void
1223xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001224 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001225 xmlNodePtr tmp;
1226
1227 if (set == NULL)
1228 return;
1229
1230 /* Use Shell's sort to sort the node-set */
1231 len = set->nodeNr;
1232 for (incr = len / 2; incr > 0; incr /= 2) {
1233 for (i = incr; i < len; i++) {
1234 j = i - incr;
1235 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001236 if (xmlXPathCmpNodes(set->nodeTab[j],
1237 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001238 tmp = set->nodeTab[j];
1239 set->nodeTab[j] = set->nodeTab[j + incr];
1240 set->nodeTab[j + incr] = tmp;
1241 j -= incr;
1242 } else
1243 break;
1244 }
1245 }
1246 }
1247}
1248
1249#define XML_NODESET_DEFAULT 10
1250/**
1251 * xmlXPathNodeSetCreate:
1252 * @val: an initial xmlNodePtr, or NULL
1253 *
1254 * Create a new xmlNodeSetPtr of type double and of value @val
1255 *
1256 * Returns the newly created object.
1257 */
1258xmlNodeSetPtr
1259xmlXPathNodeSetCreate(xmlNodePtr val) {
1260 xmlNodeSetPtr ret;
1261
1262 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1263 if (ret == NULL) {
1264 xmlGenericError(xmlGenericErrorContext,
1265 "xmlXPathNewNodeSet: out of memory\n");
1266 return(NULL);
1267 }
1268 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1269 if (val != NULL) {
1270 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1271 sizeof(xmlNodePtr));
1272 if (ret->nodeTab == NULL) {
1273 xmlGenericError(xmlGenericErrorContext,
1274 "xmlXPathNewNodeSet: out of memory\n");
1275 return(NULL);
1276 }
1277 memset(ret->nodeTab, 0 ,
1278 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1279 ret->nodeMax = XML_NODESET_DEFAULT;
1280 ret->nodeTab[ret->nodeNr++] = val;
1281 }
1282 return(ret);
1283}
1284
1285/**
1286 * xmlXPathNodeSetAdd:
1287 * @cur: the initial node set
1288 * @val: a new xmlNodePtr
1289 *
1290 * add a new xmlNodePtr ot an existing NodeSet
1291 */
1292void
1293xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1294 int i;
1295
1296 if (val == NULL) return;
1297
1298 /*
1299 * check against doublons
1300 */
1301 for (i = 0;i < cur->nodeNr;i++)
1302 if (cur->nodeTab[i] == val) return;
1303
1304 /*
1305 * grow the nodeTab if needed
1306 */
1307 if (cur->nodeMax == 0) {
1308 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1309 sizeof(xmlNodePtr));
1310 if (cur->nodeTab == NULL) {
1311 xmlGenericError(xmlGenericErrorContext,
1312 "xmlXPathNodeSetAdd: out of memory\n");
1313 return;
1314 }
1315 memset(cur->nodeTab, 0 ,
1316 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1317 cur->nodeMax = XML_NODESET_DEFAULT;
1318 } else if (cur->nodeNr == cur->nodeMax) {
1319 xmlNodePtr *temp;
1320
1321 cur->nodeMax *= 2;
1322 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1323 sizeof(xmlNodePtr));
1324 if (temp == NULL) {
1325 xmlGenericError(xmlGenericErrorContext,
1326 "xmlXPathNodeSetAdd: out of memory\n");
1327 return;
1328 }
1329 cur->nodeTab = temp;
1330 }
1331 cur->nodeTab[cur->nodeNr++] = val;
1332}
1333
1334/**
1335 * xmlXPathNodeSetAddUnique:
1336 * @cur: the initial node set
1337 * @val: a new xmlNodePtr
1338 *
1339 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1340 * when we are sure the node is not already in the set.
1341 */
1342void
1343xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1344 if (val == NULL) return;
1345
1346 /*
1347 * grow the nodeTab if needed
1348 */
1349 if (cur->nodeMax == 0) {
1350 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1351 sizeof(xmlNodePtr));
1352 if (cur->nodeTab == NULL) {
1353 xmlGenericError(xmlGenericErrorContext,
1354 "xmlXPathNodeSetAddUnique: out of memory\n");
1355 return;
1356 }
1357 memset(cur->nodeTab, 0 ,
1358 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1359 cur->nodeMax = XML_NODESET_DEFAULT;
1360 } else if (cur->nodeNr == cur->nodeMax) {
1361 xmlNodePtr *temp;
1362
1363 cur->nodeMax *= 2;
1364 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1365 sizeof(xmlNodePtr));
1366 if (temp == NULL) {
1367 xmlGenericError(xmlGenericErrorContext,
1368 "xmlXPathNodeSetAddUnique: out of memory\n");
1369 return;
1370 }
1371 cur->nodeTab = temp;
1372 }
1373 cur->nodeTab[cur->nodeNr++] = val;
1374}
1375
1376/**
1377 * xmlXPathNodeSetMerge:
1378 * @val1: the first NodeSet or NULL
1379 * @val2: the second NodeSet
1380 *
1381 * Merges two nodesets, all nodes from @val2 are added to @val1
1382 * if @val1 is NULL, a new set is created and copied from @val2
1383 *
1384 * Returns val1 once extended or NULL in case of error.
1385 */
1386xmlNodeSetPtr
1387xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001388 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001389
1390 if (val2 == NULL) return(val1);
1391 if (val1 == NULL) {
1392 val1 = xmlXPathNodeSetCreate(NULL);
1393 }
1394
1395 initNr = val1->nodeNr;
1396
1397 for (i = 0;i < val2->nodeNr;i++) {
1398 /*
1399 * check against doublons
1400 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001401 skip = 0;
1402 for (j = 0; j < initNr; j++) {
1403 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1404 skip = 1;
1405 break;
1406 }
1407 }
1408 if (skip)
1409 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001410
1411 /*
1412 * grow the nodeTab if needed
1413 */
1414 if (val1->nodeMax == 0) {
1415 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1416 sizeof(xmlNodePtr));
1417 if (val1->nodeTab == NULL) {
1418 xmlGenericError(xmlGenericErrorContext,
1419 "xmlXPathNodeSetMerge: out of memory\n");
1420 return(NULL);
1421 }
1422 memset(val1->nodeTab, 0 ,
1423 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1424 val1->nodeMax = XML_NODESET_DEFAULT;
1425 } else if (val1->nodeNr == val1->nodeMax) {
1426 xmlNodePtr *temp;
1427
1428 val1->nodeMax *= 2;
1429 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1430 sizeof(xmlNodePtr));
1431 if (temp == NULL) {
1432 xmlGenericError(xmlGenericErrorContext,
1433 "xmlXPathNodeSetMerge: out of memory\n");
1434 return(NULL);
1435 }
1436 val1->nodeTab = temp;
1437 }
1438 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1439 }
1440
1441 return(val1);
1442}
1443
1444/**
1445 * xmlXPathNodeSetDel:
1446 * @cur: the initial node set
1447 * @val: an xmlNodePtr
1448 *
1449 * Removes an xmlNodePtr from an existing NodeSet
1450 */
1451void
1452xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1453 int i;
1454
1455 if (cur == NULL) return;
1456 if (val == NULL) return;
1457
1458 /*
1459 * check against doublons
1460 */
1461 for (i = 0;i < cur->nodeNr;i++)
1462 if (cur->nodeTab[i] == val) break;
1463
1464 if (i >= cur->nodeNr) {
1465#ifdef DEBUG
1466 xmlGenericError(xmlGenericErrorContext,
1467 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1468 val->name);
1469#endif
1470 return;
1471 }
1472 cur->nodeNr--;
1473 for (;i < cur->nodeNr;i++)
1474 cur->nodeTab[i] = cur->nodeTab[i + 1];
1475 cur->nodeTab[cur->nodeNr] = NULL;
1476}
1477
1478/**
1479 * xmlXPathNodeSetRemove:
1480 * @cur: the initial node set
1481 * @val: the index to remove
1482 *
1483 * Removes an entry from an existing NodeSet list.
1484 */
1485void
1486xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1487 if (cur == NULL) return;
1488 if (val >= cur->nodeNr) return;
1489 cur->nodeNr--;
1490 for (;val < cur->nodeNr;val++)
1491 cur->nodeTab[val] = cur->nodeTab[val + 1];
1492 cur->nodeTab[cur->nodeNr] = NULL;
1493}
1494
1495/**
1496 * xmlXPathFreeNodeSet:
1497 * @obj: the xmlNodeSetPtr to free
1498 *
1499 * Free the NodeSet compound (not the actual nodes !).
1500 */
1501void
1502xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1503 if (obj == NULL) return;
1504 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001505 xmlFree(obj->nodeTab);
1506 }
Owen Taylor3473f882001-02-23 17:55:21 +00001507 xmlFree(obj);
1508}
1509
1510/**
1511 * xmlXPathFreeValueTree:
1512 * @obj: the xmlNodeSetPtr to free
1513 *
1514 * Free the NodeSet compound and the actual tree, this is different
1515 * from xmlXPathFreeNodeSet()
1516 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001517static void
Owen Taylor3473f882001-02-23 17:55:21 +00001518xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1519 int i;
1520
1521 if (obj == NULL) return;
1522 for (i = 0;i < obj->nodeNr;i++)
1523 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001524 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001525
1526 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001527 xmlFree(obj->nodeTab);
1528 }
Owen Taylor3473f882001-02-23 17:55:21 +00001529 xmlFree(obj);
1530}
1531
1532#if defined(DEBUG) || defined(DEBUG_STEP)
1533/**
1534 * xmlGenericErrorContextNodeSet:
1535 * @output: a FILE * for the output
1536 * @obj: the xmlNodeSetPtr to free
1537 *
1538 * Quick display of a NodeSet
1539 */
1540void
1541xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1542 int i;
1543
1544 if (output == NULL) output = xmlGenericErrorContext;
1545 if (obj == NULL) {
1546 fprintf(output, "NodeSet == NULL !\n");
1547 return;
1548 }
1549 if (obj->nodeNr == 0) {
1550 fprintf(output, "NodeSet is empty\n");
1551 return;
1552 }
1553 if (obj->nodeTab == NULL) {
1554 fprintf(output, " nodeTab == NULL !\n");
1555 return;
1556 }
1557 for (i = 0; i < obj->nodeNr; i++) {
1558 if (obj->nodeTab[i] == NULL) {
1559 fprintf(output, " NULL !\n");
1560 return;
1561 }
1562 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1563 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1564 fprintf(output, " /");
1565 else if (obj->nodeTab[i]->name == NULL)
1566 fprintf(output, " noname!");
1567 else fprintf(output, " %s", obj->nodeTab[i]->name);
1568 }
1569 fprintf(output, "\n");
1570}
1571#endif
1572
1573/**
1574 * xmlXPathNewNodeSet:
1575 * @val: the NodePtr value
1576 *
1577 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1578 * it with the single Node @val
1579 *
1580 * Returns the newly created object.
1581 */
1582xmlXPathObjectPtr
1583xmlXPathNewNodeSet(xmlNodePtr val) {
1584 xmlXPathObjectPtr ret;
1585
1586 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1587 if (ret == NULL) {
1588 xmlGenericError(xmlGenericErrorContext,
1589 "xmlXPathNewNodeSet: out of memory\n");
1590 return(NULL);
1591 }
1592 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1593 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001594 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001595 ret->nodesetval = xmlXPathNodeSetCreate(val);
1596 return(ret);
1597}
1598
1599/**
1600 * xmlXPathNewValueTree:
1601 * @val: the NodePtr value
1602 *
1603 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1604 * it with the tree root @val
1605 *
1606 * Returns the newly created object.
1607 */
1608xmlXPathObjectPtr
1609xmlXPathNewValueTree(xmlNodePtr val) {
1610 xmlXPathObjectPtr ret;
1611
1612 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1613 if (ret == NULL) {
1614 xmlGenericError(xmlGenericErrorContext,
1615 "xmlXPathNewNodeSet: out of memory\n");
1616 return(NULL);
1617 }
1618 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1619 ret->type = XPATH_XSLT_TREE;
1620 ret->nodesetval = xmlXPathNodeSetCreate(val);
1621 return(ret);
1622}
1623
1624/**
1625 * xmlXPathNewNodeSetList:
1626 * @val: an existing NodeSet
1627 *
1628 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1629 * it with the Nodeset @val
1630 *
1631 * Returns the newly created object.
1632 */
1633xmlXPathObjectPtr
1634xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1635 xmlXPathObjectPtr ret;
1636 int i;
1637
1638 if (val == NULL)
1639 ret = NULL;
1640 else if (val->nodeTab == NULL)
1641 ret = xmlXPathNewNodeSet(NULL);
1642 else
1643 {
1644 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1645 for (i = 1; i < val->nodeNr; ++i)
1646 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1647 }
1648
1649 return(ret);
1650}
1651
1652/**
1653 * xmlXPathWrapNodeSet:
1654 * @val: the NodePtr value
1655 *
1656 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1657 *
1658 * Returns the newly created object.
1659 */
1660xmlXPathObjectPtr
1661xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1662 xmlXPathObjectPtr ret;
1663
1664 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1665 if (ret == NULL) {
1666 xmlGenericError(xmlGenericErrorContext,
1667 "xmlXPathWrapNodeSet: out of memory\n");
1668 return(NULL);
1669 }
1670 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1671 ret->type = XPATH_NODESET;
1672 ret->nodesetval = val;
1673 return(ret);
1674}
1675
1676/**
1677 * xmlXPathFreeNodeSetList:
1678 * @obj: an existing NodeSetList object
1679 *
1680 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1681 * the list contrary to xmlXPathFreeObject().
1682 */
1683void
1684xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1685 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001686 xmlFree(obj);
1687}
1688
1689/************************************************************************
1690 * *
1691 * Routines to handle extra functions *
1692 * *
1693 ************************************************************************/
1694
1695/**
1696 * xmlXPathRegisterFunc:
1697 * @ctxt: the XPath context
1698 * @name: the function name
1699 * @f: the function implementation or NULL
1700 *
1701 * Register a new function. If @f is NULL it unregisters the function
1702 *
1703 * Returns 0 in case of success, -1 in case of error
1704 */
1705int
1706xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1707 xmlXPathFunction f) {
1708 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1709}
1710
1711/**
1712 * xmlXPathRegisterFuncNS:
1713 * @ctxt: the XPath context
1714 * @name: the function name
1715 * @ns_uri: the function namespace URI
1716 * @f: the function implementation or NULL
1717 *
1718 * Register a new function. If @f is NULL it unregisters the function
1719 *
1720 * Returns 0 in case of success, -1 in case of error
1721 */
1722int
1723xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1724 const xmlChar *ns_uri, xmlXPathFunction f) {
1725 if (ctxt == NULL)
1726 return(-1);
1727 if (name == NULL)
1728 return(-1);
1729
1730 if (ctxt->funcHash == NULL)
1731 ctxt->funcHash = xmlHashCreate(0);
1732 if (ctxt->funcHash == NULL)
1733 return(-1);
1734 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1735}
1736
1737/**
1738 * xmlXPathFunctionLookup:
1739 * @ctxt: the XPath context
1740 * @name: the function name
1741 *
1742 * Search in the Function array of the context for the given
1743 * function.
1744 *
1745 * Returns the xmlXPathFunction or NULL if not found
1746 */
1747xmlXPathFunction
1748xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1749 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1750}
1751
1752/**
1753 * xmlXPathFunctionLookupNS:
1754 * @ctxt: the XPath context
1755 * @name: the function name
1756 * @ns_uri: the function namespace URI
1757 *
1758 * Search in the Function array of the context for the given
1759 * function.
1760 *
1761 * Returns the xmlXPathFunction or NULL if not found
1762 */
1763xmlXPathFunction
1764xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1765 const xmlChar *ns_uri) {
1766 if (ctxt == NULL)
1767 return(NULL);
1768 if (ctxt->funcHash == NULL)
1769 return(NULL);
1770 if (name == NULL)
1771 return(NULL);
1772
1773 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1774}
1775
1776/**
1777 * xmlXPathRegisteredFuncsCleanup:
1778 * @ctxt: the XPath context
1779 *
1780 * Cleanup the XPath context data associated to registered functions
1781 */
1782void
1783xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1784 if (ctxt == NULL)
1785 return;
1786
1787 xmlHashFree(ctxt->funcHash, NULL);
1788 ctxt->funcHash = NULL;
1789}
1790
1791/************************************************************************
1792 * *
1793 * Routines to handle Variable *
1794 * *
1795 ************************************************************************/
1796
1797/**
1798 * xmlXPathRegisterVariable:
1799 * @ctxt: the XPath context
1800 * @name: the variable name
1801 * @value: the variable value or NULL
1802 *
1803 * Register a new variable value. If @value is NULL it unregisters
1804 * the variable
1805 *
1806 * Returns 0 in case of success, -1 in case of error
1807 */
1808int
1809xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1810 xmlXPathObjectPtr value) {
1811 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1812}
1813
1814/**
1815 * xmlXPathRegisterVariableNS:
1816 * @ctxt: the XPath context
1817 * @name: the variable name
1818 * @ns_uri: the variable namespace URI
1819 * @value: the variable value or NULL
1820 *
1821 * Register a new variable value. If @value is NULL it unregisters
1822 * the variable
1823 *
1824 * Returns 0 in case of success, -1 in case of error
1825 */
1826int
1827xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1828 const xmlChar *ns_uri,
1829 xmlXPathObjectPtr value) {
1830 if (ctxt == NULL)
1831 return(-1);
1832 if (name == NULL)
1833 return(-1);
1834
1835 if (ctxt->varHash == NULL)
1836 ctxt->varHash = xmlHashCreate(0);
1837 if (ctxt->varHash == NULL)
1838 return(-1);
1839 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1840 (void *) value,
1841 (xmlHashDeallocator)xmlXPathFreeObject));
1842}
1843
1844/**
1845 * xmlXPathRegisterVariableLookup:
1846 * @ctxt: the XPath context
1847 * @f: the lookup function
1848 * @data: the lookup data
1849 *
1850 * register an external mechanism to do variable lookup
1851 */
1852void
1853xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1854 xmlXPathVariableLookupFunc f, void *data) {
1855 if (ctxt == NULL)
1856 return;
1857 ctxt->varLookupFunc = (void *) f;
1858 ctxt->varLookupData = data;
1859}
1860
1861/**
1862 * xmlXPathVariableLookup:
1863 * @ctxt: the XPath context
1864 * @name: the variable name
1865 *
1866 * Search in the Variable array of the context for the given
1867 * variable value.
1868 *
1869 * Returns the value or NULL if not found
1870 */
1871xmlXPathObjectPtr
1872xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1873 if (ctxt == NULL)
1874 return(NULL);
1875
1876 if (ctxt->varLookupFunc != NULL) {
1877 xmlXPathObjectPtr ret;
1878
1879 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1880 (ctxt->varLookupData, name, NULL);
1881 if (ret != NULL) return(ret);
1882 }
1883 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1884}
1885
1886/**
1887 * xmlXPathVariableLookupNS:
1888 * @ctxt: the XPath context
1889 * @name: the variable name
1890 * @ns_uri: the variable namespace URI
1891 *
1892 * Search in the Variable array of the context for the given
1893 * variable value.
1894 *
1895 * Returns the value or NULL if not found
1896 */
1897xmlXPathObjectPtr
1898xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1899 const xmlChar *ns_uri) {
1900 if (ctxt == NULL)
1901 return(NULL);
1902
1903 if (ctxt->varLookupFunc != NULL) {
1904 xmlXPathObjectPtr ret;
1905
1906 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1907 (ctxt->varLookupData, name, ns_uri);
1908 if (ret != NULL) return(ret);
1909 }
1910
1911 if (ctxt->varHash == NULL)
1912 return(NULL);
1913 if (name == NULL)
1914 return(NULL);
1915
1916 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1917}
1918
1919/**
1920 * xmlXPathRegisteredVariablesCleanup:
1921 * @ctxt: the XPath context
1922 *
1923 * Cleanup the XPath context data associated to registered variables
1924 */
1925void
1926xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1927 if (ctxt == NULL)
1928 return;
1929
Daniel Veillard76d66f42001-05-16 21:05:17 +00001930 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00001931 ctxt->varHash = NULL;
1932}
1933
1934/**
1935 * xmlXPathRegisterNs:
1936 * @ctxt: the XPath context
1937 * @prefix: the namespace prefix
1938 * @ns_uri: the namespace name
1939 *
1940 * Register a new namespace. If @ns_uri is NULL it unregisters
1941 * the namespace
1942 *
1943 * Returns 0 in case of success, -1 in case of error
1944 */
1945int
1946xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1947 const xmlChar *ns_uri) {
1948 if (ctxt == NULL)
1949 return(-1);
1950 if (prefix == NULL)
1951 return(-1);
1952
1953 if (ctxt->nsHash == NULL)
1954 ctxt->nsHash = xmlHashCreate(10);
1955 if (ctxt->nsHash == NULL)
1956 return(-1);
1957 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1958 (xmlHashDeallocator)xmlFree));
1959}
1960
1961/**
1962 * xmlXPathNsLookup:
1963 * @ctxt: the XPath context
1964 * @prefix: the namespace prefix value
1965 *
1966 * Search in the namespace declaration array of the context for the given
1967 * namespace name associated to the given prefix
1968 *
1969 * Returns the value or NULL if not found
1970 */
1971const xmlChar *
1972xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1973 if (ctxt == NULL)
1974 return(NULL);
1975 if (prefix == NULL)
1976 return(NULL);
1977
1978#ifdef XML_XML_NAMESPACE
1979 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1980 return(XML_XML_NAMESPACE);
1981#endif
1982
Daniel Veillardc8f620b2001-04-30 20:31:33 +00001983 if (ctxt->namespaces != NULL) {
1984 int i;
1985
1986 for (i = 0;i < ctxt->nsNr;i++) {
1987 if ((ctxt->namespaces[i] != NULL) &&
1988 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
1989 return(ctxt->namespaces[i]->href);
1990 }
1991 }
Owen Taylor3473f882001-02-23 17:55:21 +00001992
1993 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1994}
1995
1996/**
1997 * xmlXPathRegisteredVariablesCleanup:
1998 * @ctxt: the XPath context
1999 *
2000 * Cleanup the XPath context data associated to registered variables
2001 */
2002void
2003xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2004 if (ctxt == NULL)
2005 return;
2006
2007 xmlHashFree(ctxt->nsHash, NULL);
2008 ctxt->nsHash = NULL;
2009}
2010
2011/************************************************************************
2012 * *
2013 * Routines to handle Values *
2014 * *
2015 ************************************************************************/
2016
2017/* Allocations are terrible, one need to optimize all this !!! */
2018
2019/**
2020 * xmlXPathNewFloat:
2021 * @val: the double value
2022 *
2023 * Create a new xmlXPathObjectPtr of type double and of value @val
2024 *
2025 * Returns the newly created object.
2026 */
2027xmlXPathObjectPtr
2028xmlXPathNewFloat(double val) {
2029 xmlXPathObjectPtr ret;
2030
2031 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2032 if (ret == NULL) {
2033 xmlGenericError(xmlGenericErrorContext,
2034 "xmlXPathNewFloat: out of memory\n");
2035 return(NULL);
2036 }
2037 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2038 ret->type = XPATH_NUMBER;
2039 ret->floatval = val;
2040 return(ret);
2041}
2042
2043/**
2044 * xmlXPathNewBoolean:
2045 * @val: the boolean value
2046 *
2047 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2048 *
2049 * Returns the newly created object.
2050 */
2051xmlXPathObjectPtr
2052xmlXPathNewBoolean(int val) {
2053 xmlXPathObjectPtr ret;
2054
2055 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2056 if (ret == NULL) {
2057 xmlGenericError(xmlGenericErrorContext,
2058 "xmlXPathNewBoolean: out of memory\n");
2059 return(NULL);
2060 }
2061 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2062 ret->type = XPATH_BOOLEAN;
2063 ret->boolval = (val != 0);
2064 return(ret);
2065}
2066
2067/**
2068 * xmlXPathNewString:
2069 * @val: the xmlChar * value
2070 *
2071 * Create a new xmlXPathObjectPtr of type string and of value @val
2072 *
2073 * Returns the newly created object.
2074 */
2075xmlXPathObjectPtr
2076xmlXPathNewString(const xmlChar *val) {
2077 xmlXPathObjectPtr ret;
2078
2079 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2080 if (ret == NULL) {
2081 xmlGenericError(xmlGenericErrorContext,
2082 "xmlXPathNewString: out of memory\n");
2083 return(NULL);
2084 }
2085 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2086 ret->type = XPATH_STRING;
2087 if (val != NULL)
2088 ret->stringval = xmlStrdup(val);
2089 else
2090 ret->stringval = xmlStrdup((const xmlChar *)"");
2091 return(ret);
2092}
2093
2094/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002095 * xmlXPathWrapString:
2096 * @val: the xmlChar * value
2097 *
2098 * Wraps the @val string into an XPath object.
2099 *
2100 * Returns the newly created object.
2101 */
2102xmlXPathObjectPtr
2103xmlXPathWrapString (xmlChar *val) {
2104 xmlXPathObjectPtr ret;
2105
2106 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2107 if (ret == NULL) {
2108 xmlGenericError(xmlGenericErrorContext,
2109 "xmlXPathWrapString: out of memory\n");
2110 return(NULL);
2111 }
2112 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2113 ret->type = XPATH_STRING;
2114 ret->stringval = val;
2115 return(ret);
2116}
2117
2118/**
Owen Taylor3473f882001-02-23 17:55:21 +00002119 * xmlXPathNewCString:
2120 * @val: the char * value
2121 *
2122 * Create a new xmlXPathObjectPtr of type string and of value @val
2123 *
2124 * Returns the newly created object.
2125 */
2126xmlXPathObjectPtr
2127xmlXPathNewCString(const char *val) {
2128 xmlXPathObjectPtr ret;
2129
2130 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2131 if (ret == NULL) {
2132 xmlGenericError(xmlGenericErrorContext,
2133 "xmlXPathNewCString: out of memory\n");
2134 return(NULL);
2135 }
2136 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2137 ret->type = XPATH_STRING;
2138 ret->stringval = xmlStrdup(BAD_CAST val);
2139 return(ret);
2140}
2141
2142/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002143 * xmlXPathWrapCString:
2144 * @val: the char * value
2145 *
2146 * Wraps a string into an XPath object.
2147 *
2148 * Returns the newly created object.
2149 */
2150xmlXPathObjectPtr
2151xmlXPathWrapCString (char * val) {
2152 return(xmlXPathWrapString((xmlChar *)(val)));
2153}
2154
2155/**
Owen Taylor3473f882001-02-23 17:55:21 +00002156 * xmlXPathObjectCopy:
2157 * @val: the original object
2158 *
2159 * allocate a new copy of a given object
2160 *
2161 * Returns the newly created object.
2162 */
2163xmlXPathObjectPtr
2164xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2165 xmlXPathObjectPtr ret;
2166
2167 if (val == NULL)
2168 return(NULL);
2169
2170 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2171 if (ret == NULL) {
2172 xmlGenericError(xmlGenericErrorContext,
2173 "xmlXPathObjectCopy: out of memory\n");
2174 return(NULL);
2175 }
2176 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2177 switch (val->type) {
2178 case XPATH_BOOLEAN:
2179 case XPATH_NUMBER:
2180 case XPATH_POINT:
2181 case XPATH_RANGE:
2182 break;
2183 case XPATH_STRING:
2184 ret->stringval = xmlStrdup(val->stringval);
2185 break;
2186 case XPATH_XSLT_TREE:
2187 if ((val->nodesetval != NULL) &&
2188 (val->nodesetval->nodeTab != NULL))
2189 ret->nodesetval = xmlXPathNodeSetCreate(
2190 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2191 else
2192 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2193 break;
2194 case XPATH_NODESET:
2195 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2196 break;
2197 case XPATH_LOCATIONSET:
2198#ifdef LIBXML_XPTR_ENABLED
2199 {
2200 xmlLocationSetPtr loc = val->user;
2201 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2202 break;
2203 }
2204#endif
2205 case XPATH_UNDEFINED:
2206 case XPATH_USERS:
2207 xmlGenericError(xmlGenericErrorContext,
2208 "xmlXPathObjectCopy: unsupported type %d\n",
2209 val->type);
2210 break;
2211 }
2212 return(ret);
2213}
2214
2215/**
2216 * xmlXPathFreeObject:
2217 * @obj: the object to free
2218 *
2219 * Free up an xmlXPathObjectPtr object.
2220 */
2221void
2222xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2223 if (obj == NULL) return;
2224 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002225 if (obj->boolval) {
2226 obj->type = XPATH_XSLT_TREE;
2227 if (obj->nodesetval != NULL)
2228 xmlXPathFreeValueTree(obj->nodesetval);
2229 } else {
2230 if (obj->nodesetval != NULL)
2231 xmlXPathFreeNodeSet(obj->nodesetval);
2232 }
Owen Taylor3473f882001-02-23 17:55:21 +00002233#ifdef LIBXML_XPTR_ENABLED
2234 } else if (obj->type == XPATH_LOCATIONSET) {
2235 if (obj->user != NULL)
2236 xmlXPtrFreeLocationSet(obj->user);
2237#endif
2238 } else if (obj->type == XPATH_STRING) {
2239 if (obj->stringval != NULL)
2240 xmlFree(obj->stringval);
2241 } else if (obj->type == XPATH_XSLT_TREE) {
2242 if (obj->nodesetval != NULL)
2243 xmlXPathFreeValueTree(obj->nodesetval);
2244 }
2245
Owen Taylor3473f882001-02-23 17:55:21 +00002246 xmlFree(obj);
2247}
2248
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002249
2250/************************************************************************
2251 * *
2252 * Type Casting Routines *
2253 * *
2254 ************************************************************************/
2255
2256/**
2257 * xmlXPathCastBooleanToString:
2258 * @val: a boolean
2259 *
2260 * Converts a boolean to its string value.
2261 *
2262 * Returns a newly allocated string.
2263 */
2264xmlChar *
2265xmlXPathCastBooleanToString (int val) {
2266 xmlChar *ret;
2267 if (val)
2268 ret = xmlStrdup((const xmlChar *) "true");
2269 else
2270 ret = xmlStrdup((const xmlChar *) "false");
2271 return(ret);
2272}
2273
2274/**
2275 * xmlXPathCastNumberToString:
2276 * @val: a number
2277 *
2278 * Converts a number to its string value.
2279 *
2280 * Returns a newly allocated string.
2281 */
2282xmlChar *
2283xmlXPathCastNumberToString (double val) {
2284 xmlChar *ret;
2285 switch (isinf(val)) {
2286 case 1:
2287 ret = xmlStrdup((const xmlChar *) "+Infinity");
2288 break;
2289 case -1:
2290 ret = xmlStrdup((const xmlChar *) "-Infinity");
2291 break;
2292 default:
2293 if (isnan(val)) {
2294 ret = xmlStrdup((const xmlChar *) "NaN");
2295 } else {
2296 /* could be improved */
2297 char buf[100];
2298 xmlXPathFormatNumber(val, buf, 100);
2299 ret = xmlStrdup((const xmlChar *) buf);
2300 }
2301 }
2302 return(ret);
2303}
2304
2305/**
2306 * xmlXPathCastNodeToString:
2307 * @node: a node
2308 *
2309 * Converts a node to its string value.
2310 *
2311 * Returns a newly allocated string.
2312 */
2313xmlChar *
2314xmlXPathCastNodeToString (xmlNodePtr node) {
2315 return(xmlNodeGetContent(node));
2316}
2317
2318/**
2319 * xmlXPathCastNodeSetToString:
2320 * @ns: a node-set
2321 *
2322 * Converts a node-set to its string value.
2323 *
2324 * Returns a newly allocated string.
2325 */
2326xmlChar *
2327xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2328 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2329 return(xmlStrdup((const xmlChar *) ""));
2330
2331 xmlXPathNodeSetSort(ns);
2332 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2333}
2334
2335/**
2336 * xmlXPathCastToString:
2337 * @val: an XPath object
2338 *
2339 * Converts an existing object to its string() equivalent
2340 *
2341 * Returns the string value of the object, NULL in case of error.
2342 * A new string is allocated only if needed (val isn't a
2343 * string object).
2344 */
2345xmlChar *
2346xmlXPathCastToString(xmlXPathObjectPtr val) {
2347 xmlChar *ret = NULL;
2348
2349 if (val == NULL)
2350 return(xmlStrdup((const xmlChar *) ""));
2351 switch (val->type) {
2352 case XPATH_UNDEFINED:
2353#ifdef DEBUG_EXPR
2354 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2355#endif
2356 ret = xmlStrdup((const xmlChar *) "");
2357 break;
2358 case XPATH_XSLT_TREE:
2359 case XPATH_NODESET:
2360 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2361 break;
2362 case XPATH_STRING:
2363 return(val->stringval);
2364 case XPATH_BOOLEAN:
2365 ret = xmlXPathCastBooleanToString(val->boolval);
2366 break;
2367 case XPATH_NUMBER: {
2368 ret = xmlXPathCastNumberToString(val->floatval);
2369 break;
2370 }
2371 case XPATH_USERS:
2372 case XPATH_POINT:
2373 case XPATH_RANGE:
2374 case XPATH_LOCATIONSET:
2375 TODO
2376 ret = xmlStrdup((const xmlChar *) "");
2377 break;
2378 }
2379 return(ret);
2380}
2381
2382/**
2383 * xmlXPathConvertString:
2384 * @val: an XPath object
2385 *
2386 * Converts an existing object to its string() equivalent
2387 *
2388 * Returns the new object, the old one is freed (or the operation
2389 * is done directly on @val)
2390 */
2391xmlXPathObjectPtr
2392xmlXPathConvertString(xmlXPathObjectPtr val) {
2393 xmlChar *res = NULL;
2394
2395 if (val == NULL)
2396 return(xmlXPathNewCString(""));
2397
2398 switch (val->type) {
2399 case XPATH_UNDEFINED:
2400#ifdef DEBUG_EXPR
2401 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2402#endif
2403 break;
2404 case XPATH_XSLT_TREE:
2405 case XPATH_NODESET:
2406 res = xmlXPathCastNodeSetToString(val->nodesetval);
2407 break;
2408 case XPATH_STRING:
2409 return(val);
2410 case XPATH_BOOLEAN:
2411 res = xmlXPathCastBooleanToString(val->boolval);
2412 break;
2413 case XPATH_NUMBER:
2414 res = xmlXPathCastNumberToString(val->floatval);
2415 break;
2416 case XPATH_USERS:
2417 case XPATH_POINT:
2418 case XPATH_RANGE:
2419 case XPATH_LOCATIONSET:
2420 TODO;
2421 break;
2422 }
2423 xmlXPathFreeObject(val);
2424 if (res == NULL)
2425 return(xmlXPathNewCString(""));
2426 return(xmlXPathWrapString(res));
2427}
2428
2429/**
2430 * xmlXPathCastBooleanToNumber:
2431 * @val: a boolean
2432 *
2433 * Converts a boolean to its number value
2434 *
2435 * Returns the number value
2436 */
2437double
2438xmlXPathCastBooleanToNumber(int val) {
2439 if (val)
2440 return(1.0);
2441 return(0.0);
2442}
2443
2444/**
2445 * xmlXPathCastStringToNumber:
2446 * @val: a string
2447 *
2448 * Converts a string to its number value
2449 *
2450 * Returns the number value
2451 */
2452double
2453xmlXPathCastStringToNumber(const xmlChar * val) {
2454 return(xmlXPathStringEvalNumber(val));
2455}
2456
2457/**
2458 * xmlXPathCastNodeToNumber:
2459 * @node: a node
2460 *
2461 * Converts a node to its number value
2462 *
2463 * Returns the number value
2464 */
2465double
2466xmlXPathCastNodeToNumber (xmlNodePtr node) {
2467 xmlChar *strval;
2468 double ret;
2469
2470 if (node == NULL)
2471 return(xmlXPathNAN);
2472 strval = xmlXPathCastNodeToString(node);
2473 if (strval == NULL)
2474 return(xmlXPathNAN);
2475 ret = xmlXPathCastStringToNumber(strval);
2476 xmlFree(strval);
2477
2478 return(ret);
2479}
2480
2481/**
2482 * xmlXPathCastNodeSetToNumber:
2483 * @ns: a node-set
2484 *
2485 * Converts a node-set to its number value
2486 *
2487 * Returns the number value
2488 */
2489double
2490xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
2491 xmlChar *str;
2492 double ret;
2493
2494 if (ns == NULL)
2495 return(xmlXPathNAN);
2496 str = xmlXPathCastNodeSetToString(ns);
2497 ret = xmlXPathCastStringToNumber(str);
2498 xmlFree(str);
2499 return(ret);
2500}
2501
2502/**
2503 * xmlXPathCastToNumber:
2504 * @val: an XPath object
2505 *
2506 * Converts an XPath object to its number value
2507 *
2508 * Returns the number value
2509 */
2510double
2511xmlXPathCastToNumber(xmlXPathObjectPtr val) {
2512 double ret = 0.0;
2513
2514 if (val == NULL)
2515 return(xmlXPathNAN);
2516 switch (val->type) {
2517 case XPATH_UNDEFINED:
2518#ifdef DEGUB_EXPR
2519 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
2520#endif
2521 ret = xmlXPathNAN;
2522 break;
2523 case XPATH_XSLT_TREE:
2524 case XPATH_NODESET:
2525 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
2526 break;
2527 case XPATH_STRING:
2528 ret = xmlXPathCastStringToNumber(val->stringval);
2529 break;
2530 case XPATH_NUMBER:
2531 ret = val->floatval;
2532 break;
2533 case XPATH_BOOLEAN:
2534 ret = xmlXPathCastBooleanToNumber(val->boolval);
2535 break;
2536 case XPATH_USERS:
2537 case XPATH_POINT:
2538 case XPATH_RANGE:
2539 case XPATH_LOCATIONSET:
2540 TODO;
2541 ret = xmlXPathNAN;
2542 break;
2543 }
2544 return(ret);
2545}
2546
2547/**
2548 * xmlXPathConvertNumber:
2549 * @val: an XPath object
2550 *
2551 * Converts an existing object to its number() equivalent
2552 *
2553 * Returns the new object, the old one is freed (or the operation
2554 * is done directly on @val)
2555 */
2556xmlXPathObjectPtr
2557xmlXPathConvertNumber(xmlXPathObjectPtr val) {
2558 xmlXPathObjectPtr ret;
2559
2560 if (val == NULL)
2561 return(xmlXPathNewFloat(0.0));
2562 if (val->type == XPATH_NUMBER)
2563 return(val);
2564 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
2565 xmlXPathFreeObject(val);
2566 return(ret);
2567}
2568
2569/**
2570 * xmlXPathCastNumberToBoolean:
2571 * @val: a number
2572 *
2573 * Converts a number to its boolean value
2574 *
2575 * Returns the boolean value
2576 */
2577int
2578xmlXPathCastNumberToBoolean (double val) {
2579 if (isnan(val) || (val == 0.0))
2580 return(0);
2581 return(1);
2582}
2583
2584/**
2585 * xmlXPathCastStringToBoolean:
2586 * @val: a string
2587 *
2588 * Converts a string to its boolean value
2589 *
2590 * Returns the boolean value
2591 */
2592int
2593xmlXPathCastStringToBoolean (const xmlChar *val) {
2594 if ((val == NULL) || (xmlStrlen(val) == 0))
2595 return(0);
2596 return(1);
2597}
2598
2599/**
2600 * xmlXPathCastNodeSetToBoolean:
2601 * @ns: a node-set
2602 *
2603 * Converts a node-set to its boolean value
2604 *
2605 * Returns the boolean value
2606 */
2607int
2608xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
2609 if ((ns == NULL) || (ns->nodeNr == 0))
2610 return(0);
2611 return(1);
2612}
2613
2614/**
2615 * xmlXpathCastToBoolean:
2616 * @val: an XPath object
2617 *
2618 * Converts an XPath object to its boolean value
2619 *
2620 * Returns the boolean value
2621 */
2622int
2623xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
2624 int ret = 0;
2625
2626 if (val == NULL)
2627 return(0);
2628 switch (val->type) {
2629 case XPATH_UNDEFINED:
2630#ifdef DEBUG_EXPR
2631 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
2632#endif
2633 ret = 0;
2634 break;
2635 case XPATH_XSLT_TREE:
2636 case XPATH_NODESET:
2637 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
2638 break;
2639 case XPATH_STRING:
2640 ret = xmlXPathCastStringToBoolean(val->stringval);
2641 break;
2642 case XPATH_NUMBER:
2643 ret = xmlXPathCastNumberToBoolean(val->floatval);
2644 break;
2645 case XPATH_BOOLEAN:
2646 ret = val->boolval;
2647 break;
2648 case XPATH_USERS:
2649 case XPATH_POINT:
2650 case XPATH_RANGE:
2651 case XPATH_LOCATIONSET:
2652 TODO;
2653 ret = 0;
2654 break;
2655 }
2656 return(ret);
2657}
2658
2659
2660/**
2661 * xmlXPathConvertBoolean:
2662 * @val: an XPath object
2663 *
2664 * Converts an existing object to its boolean() equivalent
2665 *
2666 * Returns the new object, the old one is freed (or the operation
2667 * is done directly on @val)
2668 */
2669xmlXPathObjectPtr
2670xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
2671 xmlXPathObjectPtr ret;
2672
2673 if (val == NULL)
2674 return(xmlXPathNewBoolean(0));
2675 if (val->type == XPATH_BOOLEAN)
2676 return(val);
2677 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
2678 xmlXPathFreeObject(val);
2679 return(ret);
2680}
2681
Owen Taylor3473f882001-02-23 17:55:21 +00002682/************************************************************************
2683 * *
2684 * Routines to handle XPath contexts *
2685 * *
2686 ************************************************************************/
2687
2688/**
2689 * xmlXPathNewContext:
2690 * @doc: the XML document
2691 *
2692 * Create a new xmlXPathContext
2693 *
2694 * Returns the xmlXPathContext just allocated.
2695 */
2696xmlXPathContextPtr
2697xmlXPathNewContext(xmlDocPtr doc) {
2698 xmlXPathContextPtr ret;
2699
2700 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2701 if (ret == NULL) {
2702 xmlGenericError(xmlGenericErrorContext,
2703 "xmlXPathNewContext: out of memory\n");
2704 return(NULL);
2705 }
2706 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2707 ret->doc = doc;
2708 ret->node = NULL;
2709
2710 ret->varHash = NULL;
2711
2712 ret->nb_types = 0;
2713 ret->max_types = 0;
2714 ret->types = NULL;
2715
2716 ret->funcHash = xmlHashCreate(0);
2717
2718 ret->nb_axis = 0;
2719 ret->max_axis = 0;
2720 ret->axis = NULL;
2721
2722 ret->nsHash = NULL;
2723 ret->user = NULL;
2724
2725 ret->contextSize = -1;
2726 ret->proximityPosition = -1;
2727
2728 xmlXPathRegisterAllFunctions(ret);
2729
2730 return(ret);
2731}
2732
2733/**
2734 * xmlXPathFreeContext:
2735 * @ctxt: the context to free
2736 *
2737 * Free up an xmlXPathContext
2738 */
2739void
2740xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2741 xmlXPathRegisteredNsCleanup(ctxt);
2742 xmlXPathRegisteredFuncsCleanup(ctxt);
2743 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002744 xmlFree(ctxt);
2745}
2746
2747/************************************************************************
2748 * *
2749 * Routines to handle XPath parser contexts *
2750 * *
2751 ************************************************************************/
2752
2753#define CHECK_CTXT(ctxt) \
2754 if (ctxt == NULL) { \
2755 xmlGenericError(xmlGenericErrorContext, \
2756 "%s:%d Internal error: ctxt == NULL\n", \
2757 __FILE__, __LINE__); \
2758 } \
2759
2760
2761#define CHECK_CONTEXT(ctxt) \
2762 if (ctxt == NULL) { \
2763 xmlGenericError(xmlGenericErrorContext, \
2764 "%s:%d Internal error: no context\n", \
2765 __FILE__, __LINE__); \
2766 } \
2767 else if (ctxt->doc == NULL) { \
2768 xmlGenericError(xmlGenericErrorContext, \
2769 "%s:%d Internal error: no document\n", \
2770 __FILE__, __LINE__); \
2771 } \
2772 else if (ctxt->doc->children == NULL) { \
2773 xmlGenericError(xmlGenericErrorContext, \
2774 "%s:%d Internal error: document without root\n", \
2775 __FILE__, __LINE__); \
2776 } \
2777
2778
2779/**
2780 * xmlXPathNewParserContext:
2781 * @str: the XPath expression
2782 * @ctxt: the XPath context
2783 *
2784 * Create a new xmlXPathParserContext
2785 *
2786 * Returns the xmlXPathParserContext just allocated.
2787 */
2788xmlXPathParserContextPtr
2789xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2790 xmlXPathParserContextPtr ret;
2791
2792 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2793 if (ret == NULL) {
2794 xmlGenericError(xmlGenericErrorContext,
2795 "xmlXPathNewParserContext: out of memory\n");
2796 return(NULL);
2797 }
2798 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2799 ret->cur = ret->base = str;
2800 ret->context = ctxt;
2801
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002802 ret->comp = xmlXPathNewCompExpr();
2803 if (ret->comp == NULL) {
2804 xmlFree(ret->valueTab);
2805 xmlFree(ret);
2806 return(NULL);
2807 }
2808
2809 return(ret);
2810}
2811
2812/**
2813 * xmlXPathCompParserContext:
2814 * @comp: the XPath compiled expression
2815 * @ctxt: the XPath context
2816 *
2817 * Create a new xmlXPathParserContext when processing a compiled expression
2818 *
2819 * Returns the xmlXPathParserContext just allocated.
2820 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002821static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002822xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2823 xmlXPathParserContextPtr ret;
2824
2825 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2826 if (ret == NULL) {
2827 xmlGenericError(xmlGenericErrorContext,
2828 "xmlXPathNewParserContext: out of memory\n");
2829 return(NULL);
2830 }
2831 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2832
Owen Taylor3473f882001-02-23 17:55:21 +00002833 /* Allocate the value stack */
2834 ret->valueTab = (xmlXPathObjectPtr *)
2835 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002836 if (ret->valueTab == NULL) {
2837 xmlFree(ret);
2838 xmlGenericError(xmlGenericErrorContext,
2839 "xmlXPathNewParserContext: out of memory\n");
2840 return(NULL);
2841 }
Owen Taylor3473f882001-02-23 17:55:21 +00002842 ret->valueNr = 0;
2843 ret->valueMax = 10;
2844 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002845
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002846 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002847 ret->comp = comp;
2848
Owen Taylor3473f882001-02-23 17:55:21 +00002849 return(ret);
2850}
2851
2852/**
2853 * xmlXPathFreeParserContext:
2854 * @ctxt: the context to free
2855 *
2856 * Free up an xmlXPathParserContext
2857 */
2858void
2859xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2860 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002861 xmlFree(ctxt->valueTab);
2862 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002863 if (ctxt->comp)
2864 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002865 xmlFree(ctxt);
2866}
2867
2868/************************************************************************
2869 * *
2870 * The implicit core function library *
2871 * *
2872 ************************************************************************/
2873
Owen Taylor3473f882001-02-23 17:55:21 +00002874/**
2875 * xmlXPathCompareNodeSetFloat:
2876 * @ctxt: the XPath Parser context
2877 * @inf: less than (1) or greater than (0)
2878 * @strict: is the comparison strict
2879 * @arg: the node set
2880 * @f: the value
2881 *
2882 * Implement the compare operation between a nodeset and a number
2883 * @ns < @val (1, 1, ...
2884 * @ns <= @val (1, 0, ...
2885 * @ns > @val (0, 1, ...
2886 * @ns >= @val (0, 0, ...
2887 *
2888 * If one object to be compared is a node-set and the other is a number,
2889 * then the comparison will be true if and only if there is a node in the
2890 * node-set such that the result of performing the comparison on the number
2891 * to be compared and on the result of converting the string-value of that
2892 * node to a number using the number function is true.
2893 *
2894 * Returns 0 or 1 depending on the results of the test.
2895 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002896static int
Owen Taylor3473f882001-02-23 17:55:21 +00002897xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2898 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2899 int i, ret = 0;
2900 xmlNodeSetPtr ns;
2901 xmlChar *str2;
2902
2903 if ((f == NULL) || (arg == NULL) ||
2904 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2905 xmlXPathFreeObject(arg);
2906 xmlXPathFreeObject(f);
2907 return(0);
2908 }
2909 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002910 if (ns != NULL) {
2911 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002912 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002913 if (str2 != NULL) {
2914 valuePush(ctxt,
2915 xmlXPathNewString(str2));
2916 xmlFree(str2);
2917 xmlXPathNumberFunction(ctxt, 1);
2918 valuePush(ctxt, xmlXPathObjectCopy(f));
2919 ret = xmlXPathCompareValues(ctxt, inf, strict);
2920 if (ret)
2921 break;
2922 }
2923 }
Owen Taylor3473f882001-02-23 17:55:21 +00002924 }
2925 xmlXPathFreeObject(arg);
2926 xmlXPathFreeObject(f);
2927 return(ret);
2928}
2929
2930/**
2931 * xmlXPathCompareNodeSetString:
2932 * @ctxt: the XPath Parser context
2933 * @inf: less than (1) or greater than (0)
2934 * @strict: is the comparison strict
2935 * @arg: the node set
2936 * @s: the value
2937 *
2938 * Implement the compare operation between a nodeset and a string
2939 * @ns < @val (1, 1, ...
2940 * @ns <= @val (1, 0, ...
2941 * @ns > @val (0, 1, ...
2942 * @ns >= @val (0, 0, ...
2943 *
2944 * If one object to be compared is a node-set and the other is a string,
2945 * then the comparison will be true if and only if there is a node in
2946 * the node-set such that the result of performing the comparison on the
2947 * string-value of the node and the other string is true.
2948 *
2949 * Returns 0 or 1 depending on the results of the test.
2950 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002951static int
Owen Taylor3473f882001-02-23 17:55:21 +00002952xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2953 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2954 int i, ret = 0;
2955 xmlNodeSetPtr ns;
2956 xmlChar *str2;
2957
2958 if ((s == NULL) || (arg == NULL) ||
2959 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2960 xmlXPathFreeObject(arg);
2961 xmlXPathFreeObject(s);
2962 return(0);
2963 }
2964 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002965 if (ns != NULL) {
2966 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002967 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002968 if (str2 != NULL) {
2969 valuePush(ctxt,
2970 xmlXPathNewString(str2));
2971 xmlFree(str2);
2972 valuePush(ctxt, xmlXPathObjectCopy(s));
2973 ret = xmlXPathCompareValues(ctxt, inf, strict);
2974 if (ret)
2975 break;
2976 }
2977 }
Owen Taylor3473f882001-02-23 17:55:21 +00002978 }
2979 xmlXPathFreeObject(arg);
2980 xmlXPathFreeObject(s);
2981 return(ret);
2982}
2983
2984/**
2985 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002986 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00002987 * @strict: is the comparison strict
2988 * @arg1: the fist node set object
2989 * @arg2: the second node set object
2990 *
2991 * Implement the compare operation on nodesets:
2992 *
2993 * If both objects to be compared are node-sets, then the comparison
2994 * will be true if and only if there is a node in the first node-set
2995 * and a node in the second node-set such that the result of performing
2996 * the comparison on the string-values of the two nodes is true.
2997 * ....
2998 * When neither object to be compared is a node-set and the operator
2999 * is <=, <, >= or >, then the objects are compared by converting both
3000 * objects to numbers and comparing the numbers according to IEEE 754.
3001 * ....
3002 * The number function converts its argument to a number as follows:
3003 * - a string that consists of optional whitespace followed by an
3004 * optional minus sign followed by a Number followed by whitespace
3005 * is converted to the IEEE 754 number that is nearest (according
3006 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3007 * represented by the string; any other string is converted to NaN
3008 *
3009 * Conclusion all nodes need to be converted first to their string value
3010 * and then the comparison must be done when possible
3011 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003012static int
3013xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003014 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3015 int i, j, init = 0;
3016 double val1;
3017 double *values2;
3018 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003019 xmlNodeSetPtr ns1;
3020 xmlNodeSetPtr ns2;
3021
3022 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003023 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3024 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003025 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003026 }
Owen Taylor3473f882001-02-23 17:55:21 +00003027 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003028 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3029 xmlXPathFreeObject(arg1);
3030 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003031 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003032 }
Owen Taylor3473f882001-02-23 17:55:21 +00003033
3034 ns1 = arg1->nodesetval;
3035 ns2 = arg2->nodesetval;
3036
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003037 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003038 xmlXPathFreeObject(arg1);
3039 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003040 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003041 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003042 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003043 xmlXPathFreeObject(arg1);
3044 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003045 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003046 }
Owen Taylor3473f882001-02-23 17:55:21 +00003047
3048 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3049 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003050 xmlXPathFreeObject(arg1);
3051 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003052 return(0);
3053 }
3054 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003055 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003056 if (isnan(val1))
3057 continue;
3058 for (j = 0;j < ns2->nodeNr;j++) {
3059 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003060 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003061 }
3062 if (isnan(values2[j]))
3063 continue;
3064 if (inf && strict)
3065 ret = (val1 < values2[j]);
3066 else if (inf && !strict)
3067 ret = (val1 <= values2[j]);
3068 else if (!inf && strict)
3069 ret = (val1 > values2[j]);
3070 else if (!inf && !strict)
3071 ret = (val1 >= values2[j]);
3072 if (ret)
3073 break;
3074 }
3075 if (ret)
3076 break;
3077 init = 1;
3078 }
3079 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003080 xmlXPathFreeObject(arg1);
3081 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003082 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003083}
3084
3085/**
3086 * xmlXPathCompareNodeSetValue:
3087 * @ctxt: the XPath Parser context
3088 * @inf: less than (1) or greater than (0)
3089 * @strict: is the comparison strict
3090 * @arg: the node set
3091 * @val: the value
3092 *
3093 * Implement the compare operation between a nodeset and a value
3094 * @ns < @val (1, 1, ...
3095 * @ns <= @val (1, 0, ...
3096 * @ns > @val (0, 1, ...
3097 * @ns >= @val (0, 0, ...
3098 *
3099 * If one object to be compared is a node-set and the other is a boolean,
3100 * then the comparison will be true if and only if the result of performing
3101 * the comparison on the boolean and on the result of converting
3102 * the node-set to a boolean using the boolean function is true.
3103 *
3104 * Returns 0 or 1 depending on the results of the test.
3105 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003106static int
Owen Taylor3473f882001-02-23 17:55:21 +00003107xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3108 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3109 if ((val == NULL) || (arg == NULL) ||
3110 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3111 return(0);
3112
3113 switch(val->type) {
3114 case XPATH_NUMBER:
3115 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3116 case XPATH_NODESET:
3117 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003118 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003119 case XPATH_STRING:
3120 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3121 case XPATH_BOOLEAN:
3122 valuePush(ctxt, arg);
3123 xmlXPathBooleanFunction(ctxt, 1);
3124 valuePush(ctxt, val);
3125 return(xmlXPathCompareValues(ctxt, inf, strict));
3126 default:
3127 TODO
3128 return(0);
3129 }
3130 return(0);
3131}
3132
3133/**
3134 * xmlXPathEqualNodeSetString
3135 * @arg: the nodeset object argument
3136 * @str: the string to compare to.
3137 *
3138 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3139 * If one object to be compared is a node-set and the other is a string,
3140 * then the comparison will be true if and only if there is a node in
3141 * the node-set such that the result of performing the comparison on the
3142 * string-value of the node and the other string is true.
3143 *
3144 * Returns 0 or 1 depending on the results of the test.
3145 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003146static int
Owen Taylor3473f882001-02-23 17:55:21 +00003147xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
3148 int i;
3149 xmlNodeSetPtr ns;
3150 xmlChar *str2;
3151
3152 if ((str == NULL) || (arg == NULL) ||
3153 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3154 return(0);
3155 ns = arg->nodesetval;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003156 if (ns == NULL)
3157 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003158 if (ns->nodeNr <= 0)
3159 return(0);
3160 for (i = 0;i < ns->nodeNr;i++) {
3161 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3162 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3163 xmlFree(str2);
3164 return(1);
3165 }
3166 if (str2 != NULL)
3167 xmlFree(str2);
3168 }
3169 return(0);
3170}
3171
3172/**
3173 * xmlXPathEqualNodeSetFloat
3174 * @arg: the nodeset object argument
3175 * @f: the float to compare to
3176 *
3177 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3178 * If one object to be compared is a node-set and the other is a number,
3179 * then the comparison will be true if and only if there is a node in
3180 * the node-set such that the result of performing the comparison on the
3181 * number to be compared and on the result of converting the string-value
3182 * of that node to a number using the number function is true.
3183 *
3184 * Returns 0 or 1 depending on the results of the test.
3185 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003186static int
Owen Taylor3473f882001-02-23 17:55:21 +00003187xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3188 char buf[100] = "";
3189
3190 if ((arg == NULL) ||
3191 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3192 return(0);
3193
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003194 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003195 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3196}
3197
3198
3199/**
3200 * xmlXPathEqualNodeSets
3201 * @arg1: first nodeset object argument
3202 * @arg2: second nodeset object argument
3203 *
3204 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3205 * If both objects to be compared are node-sets, then the comparison
3206 * will be true if and only if there is a node in the first node-set and
3207 * a node in the second node-set such that the result of performing the
3208 * comparison on the string-values of the two nodes is true.
3209 *
3210 * (needless to say, this is a costly operation)
3211 *
3212 * Returns 0 or 1 depending on the results of the test.
3213 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003214static int
Owen Taylor3473f882001-02-23 17:55:21 +00003215xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3216 int i, j;
3217 xmlChar **values1;
3218 xmlChar **values2;
3219 int ret = 0;
3220 xmlNodeSetPtr ns1;
3221 xmlNodeSetPtr ns2;
3222
3223 if ((arg1 == NULL) ||
3224 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3225 return(0);
3226 if ((arg2 == NULL) ||
3227 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3228 return(0);
3229
3230 ns1 = arg1->nodesetval;
3231 ns2 = arg2->nodesetval;
3232
Daniel Veillard911f49a2001-04-07 15:39:35 +00003233 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003234 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003235 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003236 return(0);
3237
3238 /*
3239 * check if there is a node pertaining to both sets
3240 */
3241 for (i = 0;i < ns1->nodeNr;i++)
3242 for (j = 0;j < ns2->nodeNr;j++)
3243 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3244 return(1);
3245
3246 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3247 if (values1 == NULL)
3248 return(0);
3249 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3250 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3251 if (values2 == NULL) {
3252 xmlFree(values1);
3253 return(0);
3254 }
3255 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3256 for (i = 0;i < ns1->nodeNr;i++) {
3257 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3258 for (j = 0;j < ns2->nodeNr;j++) {
3259 if (i == 0)
3260 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3261 ret = xmlStrEqual(values1[i], values2[j]);
3262 if (ret)
3263 break;
3264 }
3265 if (ret)
3266 break;
3267 }
3268 for (i = 0;i < ns1->nodeNr;i++)
3269 if (values1[i] != NULL)
3270 xmlFree(values1[i]);
3271 for (j = 0;j < ns2->nodeNr;j++)
3272 if (values2[j] != NULL)
3273 xmlFree(values2[j]);
3274 xmlFree(values1);
3275 xmlFree(values2);
3276 return(ret);
3277}
3278
3279/**
3280 * xmlXPathEqualValues:
3281 * @ctxt: the XPath Parser context
3282 *
3283 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3284 *
3285 * Returns 0 or 1 depending on the results of the test.
3286 */
3287int
3288xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
3289 xmlXPathObjectPtr arg1, arg2;
3290 int ret = 0;
3291
3292 arg1 = valuePop(ctxt);
3293 if (arg1 == NULL)
3294 XP_ERROR0(XPATH_INVALID_OPERAND);
3295
3296 arg2 = valuePop(ctxt);
3297 if (arg2 == NULL) {
3298 xmlXPathFreeObject(arg1);
3299 XP_ERROR0(XPATH_INVALID_OPERAND);
3300 }
3301
3302 if (arg1 == arg2) {
3303#ifdef DEBUG_EXPR
3304 xmlGenericError(xmlGenericErrorContext,
3305 "Equal: by pointer\n");
3306#endif
3307 return(1);
3308 }
3309
3310 switch (arg1->type) {
3311 case XPATH_UNDEFINED:
3312#ifdef DEBUG_EXPR
3313 xmlGenericError(xmlGenericErrorContext,
3314 "Equal: undefined\n");
3315#endif
3316 break;
3317 case XPATH_XSLT_TREE:
3318 case XPATH_NODESET:
3319 switch (arg2->type) {
3320 case XPATH_UNDEFINED:
3321#ifdef DEBUG_EXPR
3322 xmlGenericError(xmlGenericErrorContext,
3323 "Equal: undefined\n");
3324#endif
3325 break;
3326 case XPATH_XSLT_TREE:
3327 case XPATH_NODESET:
3328 ret = xmlXPathEqualNodeSets(arg1, arg2);
3329 break;
3330 case XPATH_BOOLEAN:
3331 if ((arg1->nodesetval == NULL) ||
3332 (arg1->nodesetval->nodeNr == 0)) ret = 0;
3333 else
3334 ret = 1;
3335 ret = (ret == arg2->boolval);
3336 break;
3337 case XPATH_NUMBER:
3338 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
3339 break;
3340 case XPATH_STRING:
3341 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
3342 break;
3343 case XPATH_USERS:
3344 case XPATH_POINT:
3345 case XPATH_RANGE:
3346 case XPATH_LOCATIONSET:
3347 TODO
3348 break;
3349 }
3350 break;
3351 case XPATH_BOOLEAN:
3352 switch (arg2->type) {
3353 case XPATH_UNDEFINED:
3354#ifdef DEBUG_EXPR
3355 xmlGenericError(xmlGenericErrorContext,
3356 "Equal: undefined\n");
3357#endif
3358 break;
3359 case XPATH_NODESET:
3360 case XPATH_XSLT_TREE:
3361 if ((arg2->nodesetval == NULL) ||
3362 (arg2->nodesetval->nodeNr == 0)) ret = 0;
3363 else
3364 ret = 1;
3365 break;
3366 case XPATH_BOOLEAN:
3367#ifdef DEBUG_EXPR
3368 xmlGenericError(xmlGenericErrorContext,
3369 "Equal: %d boolean %d \n",
3370 arg1->boolval, arg2->boolval);
3371#endif
3372 ret = (arg1->boolval == arg2->boolval);
3373 break;
3374 case XPATH_NUMBER:
3375 if (arg2->floatval) ret = 1;
3376 else ret = 0;
3377 ret = (arg1->boolval == ret);
3378 break;
3379 case XPATH_STRING:
3380 if ((arg2->stringval == NULL) ||
3381 (arg2->stringval[0] == 0)) ret = 0;
3382 else
3383 ret = 1;
3384 ret = (arg1->boolval == ret);
3385 break;
3386 case XPATH_USERS:
3387 case XPATH_POINT:
3388 case XPATH_RANGE:
3389 case XPATH_LOCATIONSET:
3390 TODO
3391 break;
3392 }
3393 break;
3394 case XPATH_NUMBER:
3395 switch (arg2->type) {
3396 case XPATH_UNDEFINED:
3397#ifdef DEBUG_EXPR
3398 xmlGenericError(xmlGenericErrorContext,
3399 "Equal: undefined\n");
3400#endif
3401 break;
3402 case XPATH_NODESET:
3403 case XPATH_XSLT_TREE:
3404 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
3405 break;
3406 case XPATH_BOOLEAN:
3407 if (arg1->floatval) ret = 1;
3408 else ret = 0;
3409 ret = (arg2->boolval == ret);
3410 break;
3411 case XPATH_STRING:
3412 valuePush(ctxt, arg2);
3413 xmlXPathNumberFunction(ctxt, 1);
3414 arg2 = valuePop(ctxt);
3415 /* no break on purpose */
3416 case XPATH_NUMBER:
3417 ret = (arg1->floatval == arg2->floatval);
3418 break;
3419 case XPATH_USERS:
3420 case XPATH_POINT:
3421 case XPATH_RANGE:
3422 case XPATH_LOCATIONSET:
3423 TODO
3424 break;
3425 }
3426 break;
3427 case XPATH_STRING:
3428 switch (arg2->type) {
3429 case XPATH_UNDEFINED:
3430#ifdef DEBUG_EXPR
3431 xmlGenericError(xmlGenericErrorContext,
3432 "Equal: undefined\n");
3433#endif
3434 break;
3435 case XPATH_NODESET:
3436 case XPATH_XSLT_TREE:
3437 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
3438 break;
3439 case XPATH_BOOLEAN:
3440 if ((arg1->stringval == NULL) ||
3441 (arg1->stringval[0] == 0)) ret = 0;
3442 else
3443 ret = 1;
3444 ret = (arg2->boolval == ret);
3445 break;
3446 case XPATH_STRING:
3447 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
3448 break;
3449 case XPATH_NUMBER:
3450 valuePush(ctxt, arg1);
3451 xmlXPathNumberFunction(ctxt, 1);
3452 arg1 = valuePop(ctxt);
3453 ret = (arg1->floatval == arg2->floatval);
3454 break;
3455 case XPATH_USERS:
3456 case XPATH_POINT:
3457 case XPATH_RANGE:
3458 case XPATH_LOCATIONSET:
3459 TODO
3460 break;
3461 }
3462 break;
3463 case XPATH_USERS:
3464 case XPATH_POINT:
3465 case XPATH_RANGE:
3466 case XPATH_LOCATIONSET:
3467 TODO
3468 break;
3469 }
3470 xmlXPathFreeObject(arg1);
3471 xmlXPathFreeObject(arg2);
3472 return(ret);
3473}
3474
3475
3476/**
3477 * xmlXPathCompareValues:
3478 * @ctxt: the XPath Parser context
3479 * @inf: less than (1) or greater than (0)
3480 * @strict: is the comparison strict
3481 *
3482 * Implement the compare operation on XPath objects:
3483 * @arg1 < @arg2 (1, 1, ...
3484 * @arg1 <= @arg2 (1, 0, ...
3485 * @arg1 > @arg2 (0, 1, ...
3486 * @arg1 >= @arg2 (0, 0, ...
3487 *
3488 * When neither object to be compared is a node-set and the operator is
3489 * <=, <, >=, >, then the objects are compared by converted both objects
3490 * to numbers and comparing the numbers according to IEEE 754. The <
3491 * comparison will be true if and only if the first number is less than the
3492 * second number. The <= comparison will be true if and only if the first
3493 * number is less than or equal to the second number. The > comparison
3494 * will be true if and only if the first number is greater than the second
3495 * number. The >= comparison will be true if and only if the first number
3496 * is greater than or equal to the second number.
3497 *
3498 * Returns 1 if the comparaison succeeded, 0 if it failed
3499 */
3500int
3501xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3502 int ret = 0;
3503 xmlXPathObjectPtr arg1, arg2;
3504
3505 arg2 = valuePop(ctxt);
3506 if (arg2 == NULL) {
3507 XP_ERROR0(XPATH_INVALID_OPERAND);
3508 }
3509
3510 arg1 = valuePop(ctxt);
3511 if (arg1 == NULL) {
3512 xmlXPathFreeObject(arg2);
3513 XP_ERROR0(XPATH_INVALID_OPERAND);
3514 }
3515
3516 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3517 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003518 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003519 } else {
3520 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003521 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3522 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003523 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003524 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3525 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003526 }
3527 }
3528 return(ret);
3529 }
3530
3531 if (arg1->type != XPATH_NUMBER) {
3532 valuePush(ctxt, arg1);
3533 xmlXPathNumberFunction(ctxt, 1);
3534 arg1 = valuePop(ctxt);
3535 }
3536 if (arg1->type != XPATH_NUMBER) {
3537 xmlXPathFreeObject(arg1);
3538 xmlXPathFreeObject(arg2);
3539 XP_ERROR0(XPATH_INVALID_OPERAND);
3540 }
3541 if (arg2->type != XPATH_NUMBER) {
3542 valuePush(ctxt, arg2);
3543 xmlXPathNumberFunction(ctxt, 1);
3544 arg2 = valuePop(ctxt);
3545 }
3546 if (arg2->type != XPATH_NUMBER) {
3547 xmlXPathFreeObject(arg1);
3548 xmlXPathFreeObject(arg2);
3549 XP_ERROR0(XPATH_INVALID_OPERAND);
3550 }
3551 /*
3552 * Add tests for infinity and nan
3553 * => feedback on 3.4 for Inf and NaN
3554 */
3555 if (inf && strict)
3556 ret = (arg1->floatval < arg2->floatval);
3557 else if (inf && !strict)
3558 ret = (arg1->floatval <= arg2->floatval);
3559 else if (!inf && strict)
3560 ret = (arg1->floatval > arg2->floatval);
3561 else if (!inf && !strict)
3562 ret = (arg1->floatval >= arg2->floatval);
3563 xmlXPathFreeObject(arg1);
3564 xmlXPathFreeObject(arg2);
3565 return(ret);
3566}
3567
3568/**
3569 * xmlXPathValueFlipSign:
3570 * @ctxt: the XPath Parser context
3571 *
3572 * Implement the unary - operation on an XPath object
3573 * The numeric operators convert their operands to numbers as if
3574 * by calling the number function.
3575 */
3576void
3577xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003578 CAST_TO_NUMBER;
3579 CHECK_TYPE(XPATH_NUMBER);
3580 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00003581}
3582
3583/**
3584 * xmlXPathAddValues:
3585 * @ctxt: the XPath Parser context
3586 *
3587 * Implement the add operation on XPath objects:
3588 * The numeric operators convert their operands to numbers as if
3589 * by calling the number function.
3590 */
3591void
3592xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3593 xmlXPathObjectPtr arg;
3594 double val;
3595
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003596 arg = valuePop(ctxt);
3597 if (arg == NULL)
3598 XP_ERROR(XPATH_INVALID_OPERAND);
3599 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003600 xmlXPathFreeObject(arg);
3601
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003602 CAST_TO_NUMBER;
3603 CHECK_TYPE(XPATH_NUMBER);
3604 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00003605}
3606
3607/**
3608 * xmlXPathSubValues:
3609 * @ctxt: the XPath Parser context
3610 *
3611 * Implement the substraction operation on XPath objects:
3612 * The numeric operators convert their operands to numbers as if
3613 * by calling the number function.
3614 */
3615void
3616xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3617 xmlXPathObjectPtr arg;
3618 double val;
3619
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003620 arg = valuePop(ctxt);
3621 if (arg == NULL)
3622 XP_ERROR(XPATH_INVALID_OPERAND);
3623 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003624 xmlXPathFreeObject(arg);
3625
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003626 CAST_TO_NUMBER;
3627 CHECK_TYPE(XPATH_NUMBER);
3628 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003629}
3630
3631/**
3632 * xmlXPathMultValues:
3633 * @ctxt: the XPath Parser context
3634 *
3635 * Implement the multiply operation on XPath objects:
3636 * The numeric operators convert their operands to numbers as if
3637 * by calling the number function.
3638 */
3639void
3640xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3641 xmlXPathObjectPtr arg;
3642 double val;
3643
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003644 arg = valuePop(ctxt);
3645 if (arg == NULL)
3646 XP_ERROR(XPATH_INVALID_OPERAND);
3647 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003648 xmlXPathFreeObject(arg);
3649
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003650 CAST_TO_NUMBER;
3651 CHECK_TYPE(XPATH_NUMBER);
3652 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003653}
3654
3655/**
3656 * xmlXPathDivValues:
3657 * @ctxt: the XPath Parser context
3658 *
3659 * Implement the div operation on XPath objects @arg1 / @arg2:
3660 * The numeric operators convert their operands to numbers as if
3661 * by calling the number function.
3662 */
3663void
3664xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3665 xmlXPathObjectPtr arg;
3666 double val;
3667
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003668 arg = valuePop(ctxt);
3669 if (arg == NULL)
3670 XP_ERROR(XPATH_INVALID_OPERAND);
3671 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003672 xmlXPathFreeObject(arg);
3673
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003674 CAST_TO_NUMBER;
3675 CHECK_TYPE(XPATH_NUMBER);
3676 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003677}
3678
3679/**
3680 * xmlXPathModValues:
3681 * @ctxt: the XPath Parser context
3682 *
3683 * Implement the mod operation on XPath objects: @arg1 / @arg2
3684 * The numeric operators convert their operands to numbers as if
3685 * by calling the number function.
3686 */
3687void
3688xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3689 xmlXPathObjectPtr arg;
3690 int arg1, arg2;
3691
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003692 arg = valuePop(ctxt);
3693 if (arg == NULL)
3694 XP_ERROR(XPATH_INVALID_OPERAND);
3695 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003696 xmlXPathFreeObject(arg);
3697
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003698 CAST_TO_NUMBER;
3699 CHECK_TYPE(XPATH_NUMBER);
3700 arg1 = (int) ctxt->value->floatval;
3701 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00003702}
3703
3704/************************************************************************
3705 * *
3706 * The traversal functions *
3707 * *
3708 ************************************************************************/
3709
Owen Taylor3473f882001-02-23 17:55:21 +00003710/*
3711 * A traversal function enumerates nodes along an axis.
3712 * Initially it must be called with NULL, and it indicates
3713 * termination on the axis by returning NULL.
3714 */
3715typedef xmlNodePtr (*xmlXPathTraversalFunction)
3716 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3717
3718/**
3719 * xmlXPathNextSelf:
3720 * @ctxt: the XPath Parser context
3721 * @cur: the current node in the traversal
3722 *
3723 * Traversal function for the "self" direction
3724 * The self axis contains just the context node itself
3725 *
3726 * Returns the next element following that axis
3727 */
3728xmlNodePtr
3729xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3730 if (cur == NULL)
3731 return(ctxt->context->node);
3732 return(NULL);
3733}
3734
3735/**
3736 * xmlXPathNextChild:
3737 * @ctxt: the XPath Parser context
3738 * @cur: the current node in the traversal
3739 *
3740 * Traversal function for the "child" direction
3741 * The child axis contains the children of the context node in document order.
3742 *
3743 * Returns the next element following that axis
3744 */
3745xmlNodePtr
3746xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3747 if (cur == NULL) {
3748 if (ctxt->context->node == NULL) return(NULL);
3749 switch (ctxt->context->node->type) {
3750 case XML_ELEMENT_NODE:
3751 case XML_TEXT_NODE:
3752 case XML_CDATA_SECTION_NODE:
3753 case XML_ENTITY_REF_NODE:
3754 case XML_ENTITY_NODE:
3755 case XML_PI_NODE:
3756 case XML_COMMENT_NODE:
3757 case XML_NOTATION_NODE:
3758 case XML_DTD_NODE:
3759 return(ctxt->context->node->children);
3760 case XML_DOCUMENT_NODE:
3761 case XML_DOCUMENT_TYPE_NODE:
3762 case XML_DOCUMENT_FRAG_NODE:
3763 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003764#ifdef LIBXML_DOCB_ENABLED
3765 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003766#endif
3767 return(((xmlDocPtr) ctxt->context->node)->children);
3768 case XML_ELEMENT_DECL:
3769 case XML_ATTRIBUTE_DECL:
3770 case XML_ENTITY_DECL:
3771 case XML_ATTRIBUTE_NODE:
3772 case XML_NAMESPACE_DECL:
3773 case XML_XINCLUDE_START:
3774 case XML_XINCLUDE_END:
3775 return(NULL);
3776 }
3777 return(NULL);
3778 }
3779 if ((cur->type == XML_DOCUMENT_NODE) ||
3780 (cur->type == XML_HTML_DOCUMENT_NODE))
3781 return(NULL);
3782 return(cur->next);
3783}
3784
3785/**
3786 * xmlXPathNextDescendant:
3787 * @ctxt: the XPath Parser context
3788 * @cur: the current node in the traversal
3789 *
3790 * Traversal function for the "descendant" direction
3791 * the descendant axis contains the descendants of the context node in document
3792 * order; a descendant is a child or a child of a child and so on.
3793 *
3794 * Returns the next element following that axis
3795 */
3796xmlNodePtr
3797xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3798 if (cur == NULL) {
3799 if (ctxt->context->node == NULL)
3800 return(NULL);
3801 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3802 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3803 return(NULL);
3804
3805 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3806 return(ctxt->context->doc->children);
3807 return(ctxt->context->node->children);
3808 }
3809
3810 if (cur->children != NULL)
3811 {
3812 if (cur->children->type != XML_ENTITY_DECL)
3813 return(cur->children);
3814 }
3815 if (cur->next != NULL) return(cur->next);
3816
3817 do {
3818 cur = cur->parent;
3819 if (cur == NULL) return(NULL);
3820 if (cur == ctxt->context->node) return(NULL);
3821 if (cur->next != NULL) {
3822 cur = cur->next;
3823 return(cur);
3824 }
3825 } while (cur != NULL);
3826 return(cur);
3827}
3828
3829/**
3830 * xmlXPathNextDescendantOrSelf:
3831 * @ctxt: the XPath Parser context
3832 * @cur: the current node in the traversal
3833 *
3834 * Traversal function for the "descendant-or-self" direction
3835 * the descendant-or-self axis contains the context node and the descendants
3836 * of the context node in document order; thus the context node is the first
3837 * node on the axis, and the first child of the context node is the second node
3838 * on the axis
3839 *
3840 * Returns the next element following that axis
3841 */
3842xmlNodePtr
3843xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3844 if (cur == NULL) {
3845 if (ctxt->context->node == NULL)
3846 return(NULL);
3847 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3848 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3849 return(NULL);
3850 return(ctxt->context->node);
3851 }
3852
3853 return(xmlXPathNextDescendant(ctxt, cur));
3854}
3855
3856/**
3857 * xmlXPathNextParent:
3858 * @ctxt: the XPath Parser context
3859 * @cur: the current node in the traversal
3860 *
3861 * Traversal function for the "parent" direction
3862 * The parent axis contains the parent of the context node, if there is one.
3863 *
3864 * Returns the next element following that axis
3865 */
3866xmlNodePtr
3867xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3868 /*
3869 * the parent of an attribute or namespace node is the element
3870 * to which the attribute or namespace node is attached
3871 * Namespace handling !!!
3872 */
3873 if (cur == NULL) {
3874 if (ctxt->context->node == NULL) return(NULL);
3875 switch (ctxt->context->node->type) {
3876 case XML_ELEMENT_NODE:
3877 case XML_TEXT_NODE:
3878 case XML_CDATA_SECTION_NODE:
3879 case XML_ENTITY_REF_NODE:
3880 case XML_ENTITY_NODE:
3881 case XML_PI_NODE:
3882 case XML_COMMENT_NODE:
3883 case XML_NOTATION_NODE:
3884 case XML_DTD_NODE:
3885 case XML_ELEMENT_DECL:
3886 case XML_ATTRIBUTE_DECL:
3887 case XML_XINCLUDE_START:
3888 case XML_XINCLUDE_END:
3889 case XML_ENTITY_DECL:
3890 if (ctxt->context->node->parent == NULL)
3891 return((xmlNodePtr) ctxt->context->doc);
3892 return(ctxt->context->node->parent);
3893 case XML_ATTRIBUTE_NODE: {
3894 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3895
3896 return(att->parent);
3897 }
3898 case XML_DOCUMENT_NODE:
3899 case XML_DOCUMENT_TYPE_NODE:
3900 case XML_DOCUMENT_FRAG_NODE:
3901 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003902#ifdef LIBXML_DOCB_ENABLED
3903 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003904#endif
3905 return(NULL);
3906 case XML_NAMESPACE_DECL:
3907 /*
3908 * TODO !!! may require extending struct _xmlNs with
3909 * parent field
3910 * C.f. Infoset case...
3911 */
3912 return(NULL);
3913 }
3914 }
3915 return(NULL);
3916}
3917
3918/**
3919 * xmlXPathNextAncestor:
3920 * @ctxt: the XPath Parser context
3921 * @cur: the current node in the traversal
3922 *
3923 * Traversal function for the "ancestor" direction
3924 * the ancestor axis contains the ancestors of the context node; the ancestors
3925 * of the context node consist of the parent of context node and the parent's
3926 * parent and so on; the nodes are ordered in reverse document order; thus the
3927 * parent is the first node on the axis, and the parent's parent is the second
3928 * node on the axis
3929 *
3930 * Returns the next element following that axis
3931 */
3932xmlNodePtr
3933xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3934 /*
3935 * the parent of an attribute or namespace node is the element
3936 * to which the attribute or namespace node is attached
3937 * !!!!!!!!!!!!!
3938 */
3939 if (cur == NULL) {
3940 if (ctxt->context->node == NULL) return(NULL);
3941 switch (ctxt->context->node->type) {
3942 case XML_ELEMENT_NODE:
3943 case XML_TEXT_NODE:
3944 case XML_CDATA_SECTION_NODE:
3945 case XML_ENTITY_REF_NODE:
3946 case XML_ENTITY_NODE:
3947 case XML_PI_NODE:
3948 case XML_COMMENT_NODE:
3949 case XML_DTD_NODE:
3950 case XML_ELEMENT_DECL:
3951 case XML_ATTRIBUTE_DECL:
3952 case XML_ENTITY_DECL:
3953 case XML_NOTATION_NODE:
3954 case XML_XINCLUDE_START:
3955 case XML_XINCLUDE_END:
3956 if (ctxt->context->node->parent == NULL)
3957 return((xmlNodePtr) ctxt->context->doc);
3958 return(ctxt->context->node->parent);
3959 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003960 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00003961
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003962 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003963 }
3964 case XML_DOCUMENT_NODE:
3965 case XML_DOCUMENT_TYPE_NODE:
3966 case XML_DOCUMENT_FRAG_NODE:
3967 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003968#ifdef LIBXML_DOCB_ENABLED
3969 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003970#endif
3971 return(NULL);
3972 case XML_NAMESPACE_DECL:
3973 /*
3974 * TODO !!! may require extending struct _xmlNs with
3975 * parent field
3976 * C.f. Infoset case...
3977 */
3978 return(NULL);
3979 }
3980 return(NULL);
3981 }
3982 if (cur == ctxt->context->doc->children)
3983 return((xmlNodePtr) ctxt->context->doc);
3984 if (cur == (xmlNodePtr) ctxt->context->doc)
3985 return(NULL);
3986 switch (cur->type) {
3987 case XML_ELEMENT_NODE:
3988 case XML_TEXT_NODE:
3989 case XML_CDATA_SECTION_NODE:
3990 case XML_ENTITY_REF_NODE:
3991 case XML_ENTITY_NODE:
3992 case XML_PI_NODE:
3993 case XML_COMMENT_NODE:
3994 case XML_NOTATION_NODE:
3995 case XML_DTD_NODE:
3996 case XML_ELEMENT_DECL:
3997 case XML_ATTRIBUTE_DECL:
3998 case XML_ENTITY_DECL:
3999 case XML_XINCLUDE_START:
4000 case XML_XINCLUDE_END:
4001 return(cur->parent);
4002 case XML_ATTRIBUTE_NODE: {
4003 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4004
4005 return(att->parent);
4006 }
4007 case XML_DOCUMENT_NODE:
4008 case XML_DOCUMENT_TYPE_NODE:
4009 case XML_DOCUMENT_FRAG_NODE:
4010 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004011#ifdef LIBXML_DOCB_ENABLED
4012 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004013#endif
4014 return(NULL);
4015 case XML_NAMESPACE_DECL:
4016 /*
4017 * TODO !!! may require extending struct _xmlNs with
4018 * parent field
4019 * C.f. Infoset case...
4020 */
4021 return(NULL);
4022 }
4023 return(NULL);
4024}
4025
4026/**
4027 * xmlXPathNextAncestorOrSelf:
4028 * @ctxt: the XPath Parser context
4029 * @cur: the current node in the traversal
4030 *
4031 * Traversal function for the "ancestor-or-self" direction
4032 * he ancestor-or-self axis contains the context node and ancestors of
4033 * the context node in reverse document order; thus the context node is
4034 * the first node on the axis, and the context node's parent the second;
4035 * parent here is defined the same as with the parent axis.
4036 *
4037 * Returns the next element following that axis
4038 */
4039xmlNodePtr
4040xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4041 if (cur == NULL)
4042 return(ctxt->context->node);
4043 return(xmlXPathNextAncestor(ctxt, cur));
4044}
4045
4046/**
4047 * xmlXPathNextFollowingSibling:
4048 * @ctxt: the XPath Parser context
4049 * @cur: the current node in the traversal
4050 *
4051 * Traversal function for the "following-sibling" direction
4052 * The following-sibling axis contains the following siblings of the context
4053 * node in document order.
4054 *
4055 * Returns the next element following that axis
4056 */
4057xmlNodePtr
4058xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4059 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4060 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4061 return(NULL);
4062 if (cur == (xmlNodePtr) ctxt->context->doc)
4063 return(NULL);
4064 if (cur == NULL)
4065 return(ctxt->context->node->next);
4066 return(cur->next);
4067}
4068
4069/**
4070 * xmlXPathNextPrecedingSibling:
4071 * @ctxt: the XPath Parser context
4072 * @cur: the current node in the traversal
4073 *
4074 * Traversal function for the "preceding-sibling" direction
4075 * The preceding-sibling axis contains the preceding siblings of the context
4076 * node in reverse document order; the first preceding sibling is first on the
4077 * axis; the sibling preceding that node is the second on the axis and so on.
4078 *
4079 * Returns the next element following that axis
4080 */
4081xmlNodePtr
4082xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4083 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4084 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4085 return(NULL);
4086 if (cur == (xmlNodePtr) ctxt->context->doc)
4087 return(NULL);
4088 if (cur == NULL)
4089 return(ctxt->context->node->prev);
4090 return(cur->prev);
4091}
4092
4093/**
4094 * xmlXPathNextFollowing:
4095 * @ctxt: the XPath Parser context
4096 * @cur: the current node in the traversal
4097 *
4098 * Traversal function for the "following" direction
4099 * The following axis contains all nodes in the same document as the context
4100 * node that are after the context node in document order, excluding any
4101 * descendants and excluding attribute nodes and namespace nodes; the nodes
4102 * are ordered in document order
4103 *
4104 * Returns the next element following that axis
4105 */
4106xmlNodePtr
4107xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4108 if (cur != NULL && cur->children != NULL)
4109 return cur->children ;
4110 if (cur == NULL) cur = ctxt->context->node;
4111 if (cur == NULL) return(NULL) ; /* ERROR */
4112 if (cur->next != NULL) return(cur->next) ;
4113 do {
4114 cur = cur->parent;
4115 if (cur == NULL) return(NULL);
4116 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4117 if (cur->next != NULL) return(cur->next);
4118 } while (cur != NULL);
4119 return(cur);
4120}
4121
4122/*
4123 * xmlXPathIsAncestor:
4124 * @ancestor: the ancestor node
4125 * @node: the current node
4126 *
4127 * Check that @ancestor is a @node's ancestor
4128 *
4129 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4130 */
4131static int
4132xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4133 if ((ancestor == NULL) || (node == NULL)) return(0);
4134 /* nodes need to be in the same document */
4135 if (ancestor->doc != node->doc) return(0);
4136 /* avoid searching if ancestor or node is the root node */
4137 if (ancestor == (xmlNodePtr) node->doc) return(1);
4138 if (node == (xmlNodePtr) ancestor->doc) return(0);
4139 while (node->parent != NULL) {
4140 if (node->parent == ancestor)
4141 return(1);
4142 node = node->parent;
4143 }
4144 return(0);
4145}
4146
4147/**
4148 * xmlXPathNextPreceding:
4149 * @ctxt: the XPath Parser context
4150 * @cur: the current node in the traversal
4151 *
4152 * Traversal function for the "preceding" direction
4153 * the preceding axis contains all nodes in the same document as the context
4154 * node that are before the context node in document order, excluding any
4155 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4156 * ordered in reverse document order
4157 *
4158 * Returns the next element following that axis
4159 */
4160xmlNodePtr
4161xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4162 if (cur == NULL)
4163 cur = ctxt->context->node ;
4164 do {
4165 if (cur->prev != NULL) {
4166 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
4167 ;
4168 return(cur) ;
4169 }
4170
4171 cur = cur->parent;
4172 if (cur == NULL) return(NULL);
4173 if (cur == ctxt->context->doc->children) return(NULL);
4174 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
4175 return(cur);
4176}
4177
4178/**
4179 * xmlXPathNextNamespace:
4180 * @ctxt: the XPath Parser context
4181 * @cur: the current attribute in the traversal
4182 *
4183 * Traversal function for the "namespace" direction
4184 * the namespace axis contains the namespace nodes of the context node;
4185 * the order of nodes on this axis is implementation-defined; the axis will
4186 * be empty unless the context node is an element
4187 *
4188 * Returns the next element following that axis
4189 */
4190xmlNodePtr
4191xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4192 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
4193 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
4194 if (ctxt->context->namespaces != NULL)
4195 xmlFree(ctxt->context->namespaces);
4196 ctxt->context->namespaces =
4197 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
4198 if (ctxt->context->namespaces == NULL) return(NULL);
4199 ctxt->context->nsNr = 0;
4200 }
4201 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
4202}
4203
4204/**
4205 * xmlXPathNextAttribute:
4206 * @ctxt: the XPath Parser context
4207 * @cur: the current attribute in the traversal
4208 *
4209 * Traversal function for the "attribute" direction
4210 * TODO: support DTD inherited default attributes
4211 *
4212 * Returns the next element following that axis
4213 */
4214xmlNodePtr
4215xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00004216 if (ctxt->context->node == NULL)
4217 return(NULL);
4218 if (ctxt->context->node->type != XML_ELEMENT_NODE)
4219 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004220 if (cur == NULL) {
4221 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4222 return(NULL);
4223 return((xmlNodePtr)ctxt->context->node->properties);
4224 }
4225 return((xmlNodePtr)cur->next);
4226}
4227
4228/************************************************************************
4229 * *
4230 * NodeTest Functions *
4231 * *
4232 ************************************************************************/
4233
Owen Taylor3473f882001-02-23 17:55:21 +00004234#define IS_FUNCTION 200
4235
Owen Taylor3473f882001-02-23 17:55:21 +00004236
4237/************************************************************************
4238 * *
4239 * Implicit tree core function library *
4240 * *
4241 ************************************************************************/
4242
4243/**
4244 * xmlXPathRoot:
4245 * @ctxt: the XPath Parser context
4246 *
4247 * Initialize the context to the root of the document
4248 */
4249void
4250xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
4251 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
4252 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4253}
4254
4255/************************************************************************
4256 * *
4257 * The explicit core function library *
4258 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
4259 * *
4260 ************************************************************************/
4261
4262
4263/**
4264 * xmlXPathLastFunction:
4265 * @ctxt: the XPath Parser context
4266 * @nargs: the number of arguments
4267 *
4268 * Implement the last() XPath function
4269 * number last()
4270 * The last function returns the number of nodes in the context node list.
4271 */
4272void
4273xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4274 CHECK_ARITY(0);
4275 if (ctxt->context->contextSize >= 0) {
4276 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
4277#ifdef DEBUG_EXPR
4278 xmlGenericError(xmlGenericErrorContext,
4279 "last() : %d\n", ctxt->context->contextSize);
4280#endif
4281 } else {
4282 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
4283 }
4284}
4285
4286/**
4287 * xmlXPathPositionFunction:
4288 * @ctxt: the XPath Parser context
4289 * @nargs: the number of arguments
4290 *
4291 * Implement the position() XPath function
4292 * number position()
4293 * The position function returns the position of the context node in the
4294 * context node list. The first position is 1, and so the last positionr
4295 * will be equal to last().
4296 */
4297void
4298xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4299 CHECK_ARITY(0);
4300 if (ctxt->context->proximityPosition >= 0) {
4301 valuePush(ctxt,
4302 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
4303#ifdef DEBUG_EXPR
4304 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
4305 ctxt->context->proximityPosition);
4306#endif
4307 } else {
4308 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
4309 }
4310}
4311
4312/**
4313 * xmlXPathCountFunction:
4314 * @ctxt: the XPath Parser context
4315 * @nargs: the number of arguments
4316 *
4317 * Implement the count() XPath function
4318 * number count(node-set)
4319 */
4320void
4321xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4322 xmlXPathObjectPtr cur;
4323
4324 CHECK_ARITY(1);
4325 if ((ctxt->value == NULL) ||
4326 ((ctxt->value->type != XPATH_NODESET) &&
4327 (ctxt->value->type != XPATH_XSLT_TREE)))
4328 XP_ERROR(XPATH_INVALID_TYPE);
4329 cur = valuePop(ctxt);
4330
Daniel Veillard911f49a2001-04-07 15:39:35 +00004331 if ((cur == NULL) || (cur->nodesetval == NULL))
4332 valuePush(ctxt, xmlXPathNewFloat((double) 0));
4333 else
4334 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00004335 xmlXPathFreeObject(cur);
4336}
4337
4338/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004339 * xmlXPathGetElementsByIds:
4340 * @doc: the document
4341 * @ids: a whitespace separated list of IDs
4342 *
4343 * Selects elements by their unique ID.
4344 *
4345 * Returns a node-set of selected elements.
4346 */
4347static xmlNodeSetPtr
4348xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
4349 xmlNodeSetPtr ret;
4350 const xmlChar *cur = ids;
4351 xmlChar *ID;
4352 xmlAttrPtr attr;
4353 xmlNodePtr elem = NULL;
4354
4355 ret = xmlXPathNodeSetCreate(NULL);
4356
4357 while (IS_BLANK(*cur)) cur++;
4358 while (*cur != 0) {
4359 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
4360 (*cur == '.') || (*cur == '-') ||
4361 (*cur == '_') || (*cur == ':') ||
4362 (IS_COMBINING(*cur)) ||
4363 (IS_EXTENDER(*cur)))
4364 cur++;
4365
4366 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
4367
4368 ID = xmlStrndup(ids, cur - ids);
4369 attr = xmlGetID(doc, ID);
4370 if (attr != NULL) {
4371 elem = attr->parent;
4372 xmlXPathNodeSetAdd(ret, elem);
4373 }
4374 if (ID != NULL)
4375 xmlFree(ID);
4376
4377 while (IS_BLANK(*cur)) cur++;
4378 ids = cur;
4379 }
4380 return(ret);
4381}
4382
4383/**
Owen Taylor3473f882001-02-23 17:55:21 +00004384 * xmlXPathIdFunction:
4385 * @ctxt: the XPath Parser context
4386 * @nargs: the number of arguments
4387 *
4388 * Implement the id() XPath function
4389 * node-set id(object)
4390 * The id function selects elements by their unique ID
4391 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
4392 * then the result is the union of the result of applying id to the
4393 * string value of each of the nodes in the argument node-set. When the
4394 * argument to id is of any other type, the argument is converted to a
4395 * string as if by a call to the string function; the string is split
4396 * into a whitespace-separated list of tokens (whitespace is any sequence
4397 * of characters matching the production S); the result is a node-set
4398 * containing the elements in the same document as the context node that
4399 * have a unique ID equal to any of the tokens in the list.
4400 */
4401void
4402xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004403 xmlChar *tokens;
4404 xmlNodeSetPtr ret;
4405 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00004406
4407 CHECK_ARITY(1);
4408 obj = valuePop(ctxt);
4409 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
4410 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004411 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00004412 int i;
4413
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004414 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004415
Daniel Veillard911f49a2001-04-07 15:39:35 +00004416 if (obj->nodesetval != NULL) {
4417 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004418 tokens =
4419 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
4420 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
4421 ret = xmlXPathNodeSetMerge(ret, ns);
4422 xmlXPathFreeNodeSet(ns);
4423 if (tokens != NULL)
4424 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004425 }
Owen Taylor3473f882001-02-23 17:55:21 +00004426 }
4427
4428 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004429 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004430 return;
4431 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004432 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00004433
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004434 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
4435 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004436
Owen Taylor3473f882001-02-23 17:55:21 +00004437 xmlXPathFreeObject(obj);
4438 return;
4439}
4440
4441/**
4442 * xmlXPathLocalNameFunction:
4443 * @ctxt: the XPath Parser context
4444 * @nargs: the number of arguments
4445 *
4446 * Implement the local-name() XPath function
4447 * string local-name(node-set?)
4448 * The local-name function returns a string containing the local part
4449 * of the name of the node in the argument node-set that is first in
4450 * document order. If the node-set is empty or the first node has no
4451 * name, an empty string is returned. If the argument is omitted it
4452 * defaults to the context node.
4453 */
4454void
4455xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4456 xmlXPathObjectPtr cur;
4457
4458 if (nargs == 0) {
4459 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4460 nargs = 1;
4461 }
4462
4463 CHECK_ARITY(1);
4464 if ((ctxt->value == NULL) ||
4465 ((ctxt->value->type != XPATH_NODESET) &&
4466 (ctxt->value->type != XPATH_XSLT_TREE)))
4467 XP_ERROR(XPATH_INVALID_TYPE);
4468 cur = valuePop(ctxt);
4469
Daniel Veillard911f49a2001-04-07 15:39:35 +00004470 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004471 valuePush(ctxt, xmlXPathNewCString(""));
4472 } else {
4473 int i = 0; /* Should be first in document order !!!!! */
4474 switch (cur->nodesetval->nodeTab[i]->type) {
4475 case XML_ELEMENT_NODE:
4476 case XML_ATTRIBUTE_NODE:
4477 case XML_PI_NODE:
4478 valuePush(ctxt,
4479 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4480 break;
4481 case XML_NAMESPACE_DECL:
4482 valuePush(ctxt, xmlXPathNewString(
4483 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4484 break;
4485 default:
4486 valuePush(ctxt, xmlXPathNewCString(""));
4487 }
4488 }
4489 xmlXPathFreeObject(cur);
4490}
4491
4492/**
4493 * xmlXPathNamespaceURIFunction:
4494 * @ctxt: the XPath Parser context
4495 * @nargs: the number of arguments
4496 *
4497 * Implement the namespace-uri() XPath function
4498 * string namespace-uri(node-set?)
4499 * The namespace-uri function returns a string containing the
4500 * namespace URI of the expanded name of the node in the argument
4501 * node-set that is first in document order. If the node-set is empty,
4502 * the first node has no name, or the expanded name has no namespace
4503 * URI, an empty string is returned. If the argument is omitted it
4504 * defaults to the context node.
4505 */
4506void
4507xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4508 xmlXPathObjectPtr cur;
4509
4510 if (nargs == 0) {
4511 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4512 nargs = 1;
4513 }
4514 CHECK_ARITY(1);
4515 if ((ctxt->value == NULL) ||
4516 ((ctxt->value->type != XPATH_NODESET) &&
4517 (ctxt->value->type != XPATH_XSLT_TREE)))
4518 XP_ERROR(XPATH_INVALID_TYPE);
4519 cur = valuePop(ctxt);
4520
Daniel Veillard911f49a2001-04-07 15:39:35 +00004521 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004522 valuePush(ctxt, xmlXPathNewCString(""));
4523 } else {
4524 int i = 0; /* Should be first in document order !!!!! */
4525 switch (cur->nodesetval->nodeTab[i]->type) {
4526 case XML_ELEMENT_NODE:
4527 case XML_ATTRIBUTE_NODE:
4528 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4529 valuePush(ctxt, xmlXPathNewCString(""));
4530 else
4531 valuePush(ctxt, xmlXPathNewString(
4532 cur->nodesetval->nodeTab[i]->ns->href));
4533 break;
4534 default:
4535 valuePush(ctxt, xmlXPathNewCString(""));
4536 }
4537 }
4538 xmlXPathFreeObject(cur);
4539}
4540
4541/**
4542 * xmlXPathNameFunction:
4543 * @ctxt: the XPath Parser context
4544 * @nargs: the number of arguments
4545 *
4546 * Implement the name() XPath function
4547 * string name(node-set?)
4548 * The name function returns a string containing a QName representing
4549 * the name of the node in the argument node-set that is first in documenti
4550 * order. The QName must represent the name with respect to the namespace
4551 * declarations in effect on the node whose name is being represented.
4552 * Typically, this will be the form in which the name occurred in the XML
4553 * source. This need not be the case if there are namespace declarations
4554 * in effect on the node that associate multiple prefixes with the same
4555 * namespace. However, an implementation may include information about
4556 * the original prefix in its representation of nodes; in this case, an
4557 * implementation can ensure that the returned string is always the same
4558 * as the QName used in the XML source. If the argument it omitted it
4559 * defaults to the context node.
4560 * Libxml keep the original prefix so the "real qualified name" used is
4561 * returned.
4562 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004563static void
Owen Taylor3473f882001-02-23 17:55:21 +00004564xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4565 xmlXPathObjectPtr cur;
4566
4567 if (nargs == 0) {
4568 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4569 nargs = 1;
4570 }
4571
4572 CHECK_ARITY(1);
4573 if ((ctxt->value == NULL) ||
4574 ((ctxt->value->type != XPATH_NODESET) &&
4575 (ctxt->value->type != XPATH_XSLT_TREE)))
4576 XP_ERROR(XPATH_INVALID_TYPE);
4577 cur = valuePop(ctxt);
4578
Daniel Veillard911f49a2001-04-07 15:39:35 +00004579 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004580 valuePush(ctxt, xmlXPathNewCString(""));
4581 } else {
4582 int i = 0; /* Should be first in document order !!!!! */
4583
4584 switch (cur->nodesetval->nodeTab[i]->type) {
4585 case XML_ELEMENT_NODE:
4586 case XML_ATTRIBUTE_NODE:
4587 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4588 valuePush(ctxt, xmlXPathNewString(
4589 cur->nodesetval->nodeTab[i]->name));
4590
4591 else {
4592 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004593 snprintf(name, sizeof(name), "%s:%s",
4594 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4595 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004596 name[sizeof(name) - 1] = 0;
4597 valuePush(ctxt, xmlXPathNewCString(name));
4598 }
4599 break;
4600 default:
4601 valuePush(ctxt,
4602 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4603 xmlXPathLocalNameFunction(ctxt, 1);
4604 }
4605 }
4606 xmlXPathFreeObject(cur);
4607}
4608
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004609
4610/**
Owen Taylor3473f882001-02-23 17:55:21 +00004611 * xmlXPathStringFunction:
4612 * @ctxt: the XPath Parser context
4613 * @nargs: the number of arguments
4614 *
4615 * Implement the string() XPath function
4616 * string string(object?)
4617 * he string function converts an object to a string as follows:
4618 * - A node-set is converted to a string by returning the value of
4619 * the node in the node-set that is first in document order.
4620 * If the node-set is empty, an empty string is returned.
4621 * - A number is converted to a string as follows
4622 * + NaN is converted to the string NaN
4623 * + positive zero is converted to the string 0
4624 * + negative zero is converted to the string 0
4625 * + positive infinity is converted to the string Infinity
4626 * + negative infinity is converted to the string -Infinity
4627 * + if the number is an integer, the number is represented in
4628 * decimal form as a Number with no decimal point and no leading
4629 * zeros, preceded by a minus sign (-) if the number is negative
4630 * + otherwise, the number is represented in decimal form as a
4631 * Number including a decimal point with at least one digit
4632 * before the decimal point and at least one digit after the
4633 * decimal point, preceded by a minus sign (-) if the number
4634 * is negative; there must be no leading zeros before the decimal
4635 * point apart possibly from the one required digit immediatelyi
4636 * before the decimal point; beyond the one required digit
4637 * after the decimal point there must be as many, but only as
4638 * many, more digits as are needed to uniquely distinguish the
4639 * number from all other IEEE 754 numeric values.
4640 * - The boolean false value is converted to the string false.
4641 * The boolean true value is converted to the string true.
4642 *
4643 * If the argument is omitted, it defaults to a node-set with the
4644 * context node as its only member.
4645 */
4646void
4647xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4648 xmlXPathObjectPtr cur;
4649
4650 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004651 valuePush(ctxt,
4652 xmlXPathWrapString(
4653 xmlXPathCastNodeToString(ctxt->context->node)));
4654 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004655 }
4656
4657 CHECK_ARITY(1);
4658 cur = valuePop(ctxt);
4659 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004660 cur = xmlXPathConvertString(cur);
4661 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004662}
4663
4664/**
4665 * xmlXPathStringLengthFunction:
4666 * @ctxt: the XPath Parser context
4667 * @nargs: the number of arguments
4668 *
4669 * Implement the string-length() XPath function
4670 * number string-length(string?)
4671 * The string-length returns the number of characters in the string
4672 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4673 * the context node converted to a string, in other words the value
4674 * of the context node.
4675 */
4676void
4677xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4678 xmlXPathObjectPtr cur;
4679
4680 if (nargs == 0) {
4681 if (ctxt->context->node == NULL) {
4682 valuePush(ctxt, xmlXPathNewFloat(0));
4683 } else {
4684 xmlChar *content;
4685
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004686 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004687 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004688 xmlFree(content);
4689 }
4690 return;
4691 }
4692 CHECK_ARITY(1);
4693 CAST_TO_STRING;
4694 CHECK_TYPE(XPATH_STRING);
4695 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004696 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004697 xmlXPathFreeObject(cur);
4698}
4699
4700/**
4701 * xmlXPathConcatFunction:
4702 * @ctxt: the XPath Parser context
4703 * @nargs: the number of arguments
4704 *
4705 * Implement the concat() XPath function
4706 * string concat(string, string, string*)
4707 * The concat function returns the concatenation of its arguments.
4708 */
4709void
4710xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4711 xmlXPathObjectPtr cur, newobj;
4712 xmlChar *tmp;
4713
4714 if (nargs < 2) {
4715 CHECK_ARITY(2);
4716 }
4717
4718 CAST_TO_STRING;
4719 cur = valuePop(ctxt);
4720 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4721 xmlXPathFreeObject(cur);
4722 return;
4723 }
4724 nargs--;
4725
4726 while (nargs > 0) {
4727 CAST_TO_STRING;
4728 newobj = valuePop(ctxt);
4729 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4730 xmlXPathFreeObject(newobj);
4731 xmlXPathFreeObject(cur);
4732 XP_ERROR(XPATH_INVALID_TYPE);
4733 }
4734 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4735 newobj->stringval = cur->stringval;
4736 cur->stringval = tmp;
4737
4738 xmlXPathFreeObject(newobj);
4739 nargs--;
4740 }
4741 valuePush(ctxt, cur);
4742}
4743
4744/**
4745 * xmlXPathContainsFunction:
4746 * @ctxt: the XPath Parser context
4747 * @nargs: the number of arguments
4748 *
4749 * Implement the contains() XPath function
4750 * boolean contains(string, string)
4751 * The contains function returns true if the first argument string
4752 * contains the second argument string, and otherwise returns false.
4753 */
4754void
4755xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4756 xmlXPathObjectPtr hay, needle;
4757
4758 CHECK_ARITY(2);
4759 CAST_TO_STRING;
4760 CHECK_TYPE(XPATH_STRING);
4761 needle = valuePop(ctxt);
4762 CAST_TO_STRING;
4763 hay = valuePop(ctxt);
4764 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4765 xmlXPathFreeObject(hay);
4766 xmlXPathFreeObject(needle);
4767 XP_ERROR(XPATH_INVALID_TYPE);
4768 }
4769 if (xmlStrstr(hay->stringval, needle->stringval))
4770 valuePush(ctxt, xmlXPathNewBoolean(1));
4771 else
4772 valuePush(ctxt, xmlXPathNewBoolean(0));
4773 xmlXPathFreeObject(hay);
4774 xmlXPathFreeObject(needle);
4775}
4776
4777/**
4778 * xmlXPathStartsWithFunction:
4779 * @ctxt: the XPath Parser context
4780 * @nargs: the number of arguments
4781 *
4782 * Implement the starts-with() XPath function
4783 * boolean starts-with(string, string)
4784 * The starts-with function returns true if the first argument string
4785 * starts with the second argument string, and otherwise returns false.
4786 */
4787void
4788xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4789 xmlXPathObjectPtr hay, needle;
4790 int n;
4791
4792 CHECK_ARITY(2);
4793 CAST_TO_STRING;
4794 CHECK_TYPE(XPATH_STRING);
4795 needle = valuePop(ctxt);
4796 CAST_TO_STRING;
4797 hay = valuePop(ctxt);
4798 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4799 xmlXPathFreeObject(hay);
4800 xmlXPathFreeObject(needle);
4801 XP_ERROR(XPATH_INVALID_TYPE);
4802 }
4803 n = xmlStrlen(needle->stringval);
4804 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4805 valuePush(ctxt, xmlXPathNewBoolean(0));
4806 else
4807 valuePush(ctxt, xmlXPathNewBoolean(1));
4808 xmlXPathFreeObject(hay);
4809 xmlXPathFreeObject(needle);
4810}
4811
4812/**
4813 * xmlXPathSubstringFunction:
4814 * @ctxt: the XPath Parser context
4815 * @nargs: the number of arguments
4816 *
4817 * Implement the substring() XPath function
4818 * string substring(string, number, number?)
4819 * The substring function returns the substring of the first argument
4820 * starting at the position specified in the second argument with
4821 * length specified in the third argument. For example,
4822 * substring("12345",2,3) returns "234". If the third argument is not
4823 * specified, it returns the substring starting at the position specified
4824 * in the second argument and continuing to the end of the string. For
4825 * example, substring("12345",2) returns "2345". More precisely, each
4826 * character in the string (see [3.6 Strings]) is considered to have a
4827 * numeric position: the position of the first character is 1, the position
4828 * of the second character is 2 and so on. The returned substring contains
4829 * those characters for which the position of the character is greater than
4830 * or equal to the second argument and, if the third argument is specified,
4831 * less than the sum of the second and third arguments; the comparisons
4832 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4833 * - substring("12345", 1.5, 2.6) returns "234"
4834 * - substring("12345", 0, 3) returns "12"
4835 * - substring("12345", 0 div 0, 3) returns ""
4836 * - substring("12345", 1, 0 div 0) returns ""
4837 * - substring("12345", -42, 1 div 0) returns "12345"
4838 * - substring("12345", -1 div 0, 1 div 0) returns ""
4839 */
4840void
4841xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4842 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00004843 double le=0, in;
4844 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00004845 xmlChar *ret;
4846
Owen Taylor3473f882001-02-23 17:55:21 +00004847 if (nargs < 2) {
4848 CHECK_ARITY(2);
4849 }
4850 if (nargs > 3) {
4851 CHECK_ARITY(3);
4852 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00004853 /*
4854 * take care of possible last (position) argument
4855 */
Owen Taylor3473f882001-02-23 17:55:21 +00004856 if (nargs == 3) {
4857 CAST_TO_NUMBER;
4858 CHECK_TYPE(XPATH_NUMBER);
4859 len = valuePop(ctxt);
4860 le = len->floatval;
4861 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00004862 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00004863
Owen Taylor3473f882001-02-23 17:55:21 +00004864 CAST_TO_NUMBER;
4865 CHECK_TYPE(XPATH_NUMBER);
4866 start = valuePop(ctxt);
4867 in = start->floatval;
4868 xmlXPathFreeObject(start);
4869 CAST_TO_STRING;
4870 CHECK_TYPE(XPATH_STRING);
4871 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00004872 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00004873
Daniel Veillard97ac1312001-05-30 19:14:17 +00004874 /*
4875 * If last pos not present, calculate last position
4876 */
4877 if (nargs != 3)
4878 le = m;
4879
4880 /*
4881 * To meet our requirements, initial index calculations
4882 * must be done before we convert to integer format
4883 *
4884 * First we normalize indices
4885 */
4886 in -= 1.0;
4887 le += in;
4888 if (in < 0.0)
4889 in = 0.0;
4890 if (le > (double)m)
4891 le = (double)m;
4892
4893 /*
4894 * Now we go to integer form, rounding up
4895 */
Owen Taylor3473f882001-02-23 17:55:21 +00004896 i = (int) in;
4897 if (((double)i) != in) i++;
4898
Owen Taylor3473f882001-02-23 17:55:21 +00004899 l = (int) le;
4900 if (((double)l) != le) l++;
4901
Daniel Veillard97ac1312001-05-30 19:14:17 +00004902 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00004903
4904 /* number of chars to copy */
4905 l -= i;
4906
Daniel Veillard97ac1312001-05-30 19:14:17 +00004907 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00004908 if (ret == NULL)
4909 valuePush(ctxt, xmlXPathNewCString(""));
4910 else {
4911 valuePush(ctxt, xmlXPathNewString(ret));
4912 xmlFree(ret);
4913 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00004914
Owen Taylor3473f882001-02-23 17:55:21 +00004915 xmlXPathFreeObject(str);
4916}
4917
4918/**
4919 * xmlXPathSubstringBeforeFunction:
4920 * @ctxt: the XPath Parser context
4921 * @nargs: the number of arguments
4922 *
4923 * Implement the substring-before() XPath function
4924 * string substring-before(string, string)
4925 * The substring-before function returns the substring of the first
4926 * argument string that precedes the first occurrence of the second
4927 * argument string in the first argument string, or the empty string
4928 * if the first argument string does not contain the second argument
4929 * string. For example, substring-before("1999/04/01","/") returns 1999.
4930 */
4931void
4932xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4933 xmlXPathObjectPtr str;
4934 xmlXPathObjectPtr find;
4935 xmlBufferPtr target;
4936 const xmlChar *point;
4937 int offset;
4938
4939 CHECK_ARITY(2);
4940 CAST_TO_STRING;
4941 find = valuePop(ctxt);
4942 CAST_TO_STRING;
4943 str = valuePop(ctxt);
4944
4945 target = xmlBufferCreate();
4946 if (target) {
4947 point = xmlStrstr(str->stringval, find->stringval);
4948 if (point) {
4949 offset = (int)(point - str->stringval);
4950 xmlBufferAdd(target, str->stringval, offset);
4951 }
4952 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4953 xmlBufferFree(target);
4954 }
4955
4956 xmlXPathFreeObject(str);
4957 xmlXPathFreeObject(find);
4958}
4959
4960/**
4961 * xmlXPathSubstringAfterFunction:
4962 * @ctxt: the XPath Parser context
4963 * @nargs: the number of arguments
4964 *
4965 * Implement the substring-after() XPath function
4966 * string substring-after(string, string)
4967 * The substring-after function returns the substring of the first
4968 * argument string that follows the first occurrence of the second
4969 * argument string in the first argument string, or the empty stringi
4970 * if the first argument string does not contain the second argument
4971 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4972 * and substring-after("1999/04/01","19") returns 99/04/01.
4973 */
4974void
4975xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4976 xmlXPathObjectPtr str;
4977 xmlXPathObjectPtr find;
4978 xmlBufferPtr target;
4979 const xmlChar *point;
4980 int offset;
4981
4982 CHECK_ARITY(2);
4983 CAST_TO_STRING;
4984 find = valuePop(ctxt);
4985 CAST_TO_STRING;
4986 str = valuePop(ctxt);
4987
4988 target = xmlBufferCreate();
4989 if (target) {
4990 point = xmlStrstr(str->stringval, find->stringval);
4991 if (point) {
4992 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4993 xmlBufferAdd(target, &str->stringval[offset],
4994 xmlStrlen(str->stringval) - offset);
4995 }
4996 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4997 xmlBufferFree(target);
4998 }
4999
5000 xmlXPathFreeObject(str);
5001 xmlXPathFreeObject(find);
5002}
5003
5004/**
5005 * xmlXPathNormalizeFunction:
5006 * @ctxt: the XPath Parser context
5007 * @nargs: the number of arguments
5008 *
5009 * Implement the normalize-space() XPath function
5010 * string normalize-space(string?)
5011 * The normalize-space function returns the argument string with white
5012 * space normalized by stripping leading and trailing whitespace
5013 * and replacing sequences of whitespace characters by a single
5014 * space. Whitespace characters are the same allowed by the S production
5015 * in XML. If the argument is omitted, it defaults to the context
5016 * node converted to a string, in other words the value of the context node.
5017 */
5018void
5019xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5020 xmlXPathObjectPtr obj = NULL;
5021 xmlChar *source = NULL;
5022 xmlBufferPtr target;
5023 xmlChar blank;
5024
5025 if (nargs == 0) {
5026 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005027 valuePush(ctxt,
5028 xmlXPathWrapString(
5029 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005030 nargs = 1;
5031 }
5032
5033 CHECK_ARITY(1);
5034 CAST_TO_STRING;
5035 CHECK_TYPE(XPATH_STRING);
5036 obj = valuePop(ctxt);
5037 source = obj->stringval;
5038
5039 target = xmlBufferCreate();
5040 if (target && source) {
5041
5042 /* Skip leading whitespaces */
5043 while (IS_BLANK(*source))
5044 source++;
5045
5046 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5047 blank = 0;
5048 while (*source) {
5049 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005050 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005051 } else {
5052 if (blank) {
5053 xmlBufferAdd(target, &blank, 1);
5054 blank = 0;
5055 }
5056 xmlBufferAdd(target, source, 1);
5057 }
5058 source++;
5059 }
5060
5061 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5062 xmlBufferFree(target);
5063 }
5064 xmlXPathFreeObject(obj);
5065}
5066
5067/**
5068 * xmlXPathTranslateFunction:
5069 * @ctxt: the XPath Parser context
5070 * @nargs: the number of arguments
5071 *
5072 * Implement the translate() XPath function
5073 * string translate(string, string, string)
5074 * The translate function returns the first argument string with
5075 * occurrences of characters in the second argument string replaced
5076 * by the character at the corresponding position in the third argument
5077 * string. For example, translate("bar","abc","ABC") returns the string
5078 * BAr. If there is a character in the second argument string with no
5079 * character at a corresponding position in the third argument string
5080 * (because the second argument string is longer than the third argument
5081 * string), then occurrences of that character in the first argument
5082 * string are removed. For example, translate("--aaa--","abc-","ABC")
5083 * returns "AAA". If a character occurs more than once in second
5084 * argument string, then the first occurrence determines the replacement
5085 * character. If the third argument string is longer than the second
5086 * argument string, then excess characters are ignored.
5087 */
5088void
5089xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005090 xmlXPathObjectPtr str;
5091 xmlXPathObjectPtr from;
5092 xmlXPathObjectPtr to;
5093 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005094 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005095 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005096 xmlChar *point;
5097 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005098
Daniel Veillarde043ee12001-04-16 14:08:07 +00005099 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005100
Daniel Veillarde043ee12001-04-16 14:08:07 +00005101 CAST_TO_STRING;
5102 to = valuePop(ctxt);
5103 CAST_TO_STRING;
5104 from = valuePop(ctxt);
5105 CAST_TO_STRING;
5106 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005107
Daniel Veillarde043ee12001-04-16 14:08:07 +00005108 target = xmlBufferCreate();
5109 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005110 max = xmlUTF8Strlen(to->stringval);
5111 for (cptr = str->stringval; (ch=*cptr); ) {
5112 offset = xmlUTF8Strloc(from->stringval, cptr);
5113 if (offset >= 0) {
5114 if (offset < max) {
5115 point = xmlUTF8Strpos(to->stringval, offset);
5116 if (point)
5117 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5118 }
5119 } else
5120 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5121
5122 /* Step to next character in input */
5123 cptr++;
5124 if ( ch & 0x80 ) {
5125 /* if not simple ascii, verify proper format */
5126 if ( (ch & 0xc0) != 0xc0 ) {
5127 xmlGenericError(xmlGenericErrorContext,
5128 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5129 break;
5130 }
5131 /* then skip over remaining bytes for this char */
5132 while ( (ch <<= 1) & 0x80 )
5133 if ( (*cptr++ & 0xc0) != 0x80 ) {
5134 xmlGenericError(xmlGenericErrorContext,
5135 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5136 break;
5137 }
5138 if (ch & 0x80) /* must have had error encountered */
5139 break;
5140 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005141 }
Owen Taylor3473f882001-02-23 17:55:21 +00005142 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005143 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5144 xmlBufferFree(target);
5145 xmlXPathFreeObject(str);
5146 xmlXPathFreeObject(from);
5147 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005148}
5149
5150/**
5151 * xmlXPathBooleanFunction:
5152 * @ctxt: the XPath Parser context
5153 * @nargs: the number of arguments
5154 *
5155 * Implement the boolean() XPath function
5156 * boolean boolean(object)
5157 * he boolean function converts its argument to a boolean as follows:
5158 * - a number is true if and only if it is neither positive or
5159 * negative zero nor NaN
5160 * - a node-set is true if and only if it is non-empty
5161 * - a string is true if and only if its length is non-zero
5162 */
5163void
5164xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5165 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005166
5167 CHECK_ARITY(1);
5168 cur = valuePop(ctxt);
5169 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005170 cur = xmlXPathConvertBoolean(cur);
5171 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005172}
5173
5174/**
5175 * xmlXPathNotFunction:
5176 * @ctxt: the XPath Parser context
5177 * @nargs: the number of arguments
5178 *
5179 * Implement the not() XPath function
5180 * boolean not(boolean)
5181 * The not function returns true if its argument is false,
5182 * and false otherwise.
5183 */
5184void
5185xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5186 CHECK_ARITY(1);
5187 CAST_TO_BOOLEAN;
5188 CHECK_TYPE(XPATH_BOOLEAN);
5189 ctxt->value->boolval = ! ctxt->value->boolval;
5190}
5191
5192/**
5193 * xmlXPathTrueFunction:
5194 * @ctxt: the XPath Parser context
5195 * @nargs: the number of arguments
5196 *
5197 * Implement the true() XPath function
5198 * boolean true()
5199 */
5200void
5201xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5202 CHECK_ARITY(0);
5203 valuePush(ctxt, xmlXPathNewBoolean(1));
5204}
5205
5206/**
5207 * xmlXPathFalseFunction:
5208 * @ctxt: the XPath Parser context
5209 * @nargs: the number of arguments
5210 *
5211 * Implement the false() XPath function
5212 * boolean false()
5213 */
5214void
5215xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5216 CHECK_ARITY(0);
5217 valuePush(ctxt, xmlXPathNewBoolean(0));
5218}
5219
5220/**
5221 * xmlXPathLangFunction:
5222 * @ctxt: the XPath Parser context
5223 * @nargs: the number of arguments
5224 *
5225 * Implement the lang() XPath function
5226 * boolean lang(string)
5227 * The lang function returns true or false depending on whether the
5228 * language of the context node as specified by xml:lang attributes
5229 * is the same as or is a sublanguage of the language specified by
5230 * the argument string. The language of the context node is determined
5231 * by the value of the xml:lang attribute on the context node, or, if
5232 * the context node has no xml:lang attribute, by the value of the
5233 * xml:lang attribute on the nearest ancestor of the context node that
5234 * has an xml:lang attribute. If there is no such attribute, then lang
5235 * returns false. If there is such an attribute, then lang returns
5236 * true if the attribute value is equal to the argument ignoring case,
5237 * or if there is some suffix starting with - such that the attribute
5238 * value is equal to the argument ignoring that suffix of the attribute
5239 * value and ignoring case.
5240 */
5241void
5242xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5243 xmlXPathObjectPtr val;
5244 const xmlChar *theLang;
5245 const xmlChar *lang;
5246 int ret = 0;
5247 int i;
5248
5249 CHECK_ARITY(1);
5250 CAST_TO_STRING;
5251 CHECK_TYPE(XPATH_STRING);
5252 val = valuePop(ctxt);
5253 lang = val->stringval;
5254 theLang = xmlNodeGetLang(ctxt->context->node);
5255 if ((theLang != NULL) && (lang != NULL)) {
5256 for (i = 0;lang[i] != 0;i++)
5257 if (toupper(lang[i]) != toupper(theLang[i]))
5258 goto not_equal;
5259 ret = 1;
5260 }
5261not_equal:
5262 xmlXPathFreeObject(val);
5263 valuePush(ctxt, xmlXPathNewBoolean(ret));
5264}
5265
5266/**
5267 * xmlXPathNumberFunction:
5268 * @ctxt: the XPath Parser context
5269 * @nargs: the number of arguments
5270 *
5271 * Implement the number() XPath function
5272 * number number(object?)
5273 */
5274void
5275xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5276 xmlXPathObjectPtr cur;
5277 double res;
5278
5279 if (nargs == 0) {
5280 if (ctxt->context->node == NULL) {
5281 valuePush(ctxt, xmlXPathNewFloat(0.0));
5282 } else {
5283 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
5284
5285 res = xmlXPathStringEvalNumber(content);
5286 valuePush(ctxt, xmlXPathNewFloat(res));
5287 xmlFree(content);
5288 }
5289 return;
5290 }
5291
5292 CHECK_ARITY(1);
5293 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005294 cur = xmlXPathConvertNumber(cur);
5295 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005296}
5297
5298/**
5299 * xmlXPathSumFunction:
5300 * @ctxt: the XPath Parser context
5301 * @nargs: the number of arguments
5302 *
5303 * Implement the sum() XPath function
5304 * number sum(node-set)
5305 * The sum function returns the sum of the values of the nodes in
5306 * the argument node-set.
5307 */
5308void
5309xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5310 xmlXPathObjectPtr cur;
5311 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005312 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00005313
5314 CHECK_ARITY(1);
5315 if ((ctxt->value == NULL) ||
5316 ((ctxt->value->type != XPATH_NODESET) &&
5317 (ctxt->value->type != XPATH_XSLT_TREE)))
5318 XP_ERROR(XPATH_INVALID_TYPE);
5319 cur = valuePop(ctxt);
5320
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005321 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005322 valuePush(ctxt, xmlXPathNewFloat(0.0));
5323 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005324 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
5325 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00005326 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005327 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00005328 }
5329 xmlXPathFreeObject(cur);
5330}
5331
5332/**
5333 * xmlXPathFloorFunction:
5334 * @ctxt: the XPath Parser context
5335 * @nargs: the number of arguments
5336 *
5337 * Implement the floor() XPath function
5338 * number floor(number)
5339 * The floor function returns the largest (closest to positive infinity)
5340 * number that is not greater than the argument and that is an integer.
5341 */
5342void
5343xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5344 CHECK_ARITY(1);
5345 CAST_TO_NUMBER;
5346 CHECK_TYPE(XPATH_NUMBER);
5347#if 0
5348 ctxt->value->floatval = floor(ctxt->value->floatval);
5349#else
5350 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5351 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5352#endif
5353}
5354
5355/**
5356 * xmlXPathCeilingFunction:
5357 * @ctxt: the XPath Parser context
5358 * @nargs: the number of arguments
5359 *
5360 * Implement the ceiling() XPath function
5361 * number ceiling(number)
5362 * The ceiling function returns the smallest (closest to negative infinity)
5363 * number that is not less than the argument and that is an integer.
5364 */
5365void
5366xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5367 double f;
5368
5369 CHECK_ARITY(1);
5370 CAST_TO_NUMBER;
5371 CHECK_TYPE(XPATH_NUMBER);
5372
5373#if 0
5374 ctxt->value->floatval = ceil(ctxt->value->floatval);
5375#else
5376 f = (double)((int) ctxt->value->floatval);
5377 if (f != ctxt->value->floatval)
5378 ctxt->value->floatval = f + 1;
5379#endif
5380}
5381
5382/**
5383 * xmlXPathRoundFunction:
5384 * @ctxt: the XPath Parser context
5385 * @nargs: the number of arguments
5386 *
5387 * Implement the round() XPath function
5388 * number round(number)
5389 * The round function returns the number that is closest to the
5390 * argument and that is an integer. If there are two such numbers,
5391 * then the one that is even is returned.
5392 */
5393void
5394xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5395 double f;
5396
5397 CHECK_ARITY(1);
5398 CAST_TO_NUMBER;
5399 CHECK_TYPE(XPATH_NUMBER);
5400
5401 if ((ctxt->value->floatval == xmlXPathNAN) ||
5402 (ctxt->value->floatval == xmlXPathPINF) ||
5403 (ctxt->value->floatval == xmlXPathNINF) ||
5404 (ctxt->value->floatval == 0.0))
5405 return;
5406
5407#if 0
5408 f = floor(ctxt->value->floatval);
5409#else
5410 f = (double)((int) ctxt->value->floatval);
5411#endif
5412 if (ctxt->value->floatval < f + 0.5)
5413 ctxt->value->floatval = f;
5414 else
5415 ctxt->value->floatval = f + 1;
5416}
5417
5418/************************************************************************
5419 * *
5420 * The Parser *
5421 * *
5422 ************************************************************************/
5423
5424/*
5425 * a couple of forward declarations since we use a recursive call based
5426 * implementation.
5427 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005428static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005429static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005430static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005431#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005432static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5433#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005434#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005435static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005436#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005437static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5438 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005439
5440/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005441 * xmlXPathCurrentChar:
5442 * @ctxt: the XPath parser context
5443 * @cur: pointer to the beginning of the char
5444 * @len: pointer to the length of the char read
5445 *
5446 * The current char value, if using UTF-8 this may actaully span multiple
5447 * bytes in the input buffer.
5448 *
5449 * Returns the current char value and its lenght
5450 */
5451
5452static int
5453xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5454 unsigned char c;
5455 unsigned int val;
5456 const xmlChar *cur;
5457
5458 if (ctxt == NULL)
5459 return(0);
5460 cur = ctxt->cur;
5461
5462 /*
5463 * We are supposed to handle UTF8, check it's valid
5464 * From rfc2044: encoding of the Unicode values on UTF-8:
5465 *
5466 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5467 * 0000 0000-0000 007F 0xxxxxxx
5468 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5469 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5470 *
5471 * Check for the 0x110000 limit too
5472 */
5473 c = *cur;
5474 if (c & 0x80) {
5475 if ((cur[1] & 0xc0) != 0x80)
5476 goto encoding_error;
5477 if ((c & 0xe0) == 0xe0) {
5478
5479 if ((cur[2] & 0xc0) != 0x80)
5480 goto encoding_error;
5481 if ((c & 0xf0) == 0xf0) {
5482 if (((c & 0xf8) != 0xf0) ||
5483 ((cur[3] & 0xc0) != 0x80))
5484 goto encoding_error;
5485 /* 4-byte code */
5486 *len = 4;
5487 val = (cur[0] & 0x7) << 18;
5488 val |= (cur[1] & 0x3f) << 12;
5489 val |= (cur[2] & 0x3f) << 6;
5490 val |= cur[3] & 0x3f;
5491 } else {
5492 /* 3-byte code */
5493 *len = 3;
5494 val = (cur[0] & 0xf) << 12;
5495 val |= (cur[1] & 0x3f) << 6;
5496 val |= cur[2] & 0x3f;
5497 }
5498 } else {
5499 /* 2-byte code */
5500 *len = 2;
5501 val = (cur[0] & 0x1f) << 6;
5502 val |= cur[1] & 0x3f;
5503 }
5504 if (!IS_CHAR(val)) {
5505 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5506 }
5507 return(val);
5508 } else {
5509 /* 1-byte code */
5510 *len = 1;
5511 return((int) *cur);
5512 }
5513encoding_error:
5514 /*
5515 * If we detect an UTF8 error that probably mean that the
5516 * input encoding didn't get properly advertized in the
5517 * declaration header. Report the error and switch the encoding
5518 * to ISO-Latin-1 (if you don't like this policy, just declare the
5519 * encoding !)
5520 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00005521 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00005522 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005523}
5524
5525/**
Owen Taylor3473f882001-02-23 17:55:21 +00005526 * xmlXPathParseNCName:
5527 * @ctxt: the XPath Parser context
5528 *
5529 * parse an XML namespace non qualified name.
5530 *
5531 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5532 *
5533 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5534 * CombiningChar | Extender
5535 *
5536 * Returns the namespace name or NULL
5537 */
5538
5539xmlChar *
5540xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005541 const xmlChar *in;
5542 xmlChar *ret;
5543 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005544
Daniel Veillard2156a562001-04-28 12:24:34 +00005545 /*
5546 * Accelerator for simple ASCII names
5547 */
5548 in = ctxt->cur;
5549 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5550 ((*in >= 0x41) && (*in <= 0x5A)) ||
5551 (*in == '_')) {
5552 in++;
5553 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5554 ((*in >= 0x41) && (*in <= 0x5A)) ||
5555 ((*in >= 0x30) && (*in <= 0x39)) ||
5556 (*in == '_'))
5557 in++;
5558 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5559 (*in == '[') || (*in == ']') || (*in == ':') ||
5560 (*in == '@') || (*in == '*')) {
5561 count = in - ctxt->cur;
5562 if (count == 0)
5563 return(NULL);
5564 ret = xmlStrndup(ctxt->cur, count);
5565 ctxt->cur = in;
5566 return(ret);
5567 }
5568 }
5569 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005570}
5571
Daniel Veillard2156a562001-04-28 12:24:34 +00005572
Owen Taylor3473f882001-02-23 17:55:21 +00005573/**
5574 * xmlXPathParseQName:
5575 * @ctxt: the XPath Parser context
5576 * @prefix: a xmlChar **
5577 *
5578 * parse an XML qualified name
5579 *
5580 * [NS 5] QName ::= (Prefix ':')? LocalPart
5581 *
5582 * [NS 6] Prefix ::= NCName
5583 *
5584 * [NS 7] LocalPart ::= NCName
5585 *
5586 * Returns the function returns the local part, and prefix is updated
5587 * to get the Prefix if any.
5588 */
5589
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005590static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005591xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5592 xmlChar *ret = NULL;
5593
5594 *prefix = NULL;
5595 ret = xmlXPathParseNCName(ctxt);
5596 if (CUR == ':') {
5597 *prefix = ret;
5598 NEXT;
5599 ret = xmlXPathParseNCName(ctxt);
5600 }
5601 return(ret);
5602}
5603
5604/**
5605 * xmlXPathParseName:
5606 * @ctxt: the XPath Parser context
5607 *
5608 * parse an XML name
5609 *
5610 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5611 * CombiningChar | Extender
5612 *
5613 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5614 *
5615 * Returns the namespace name or NULL
5616 */
5617
5618xmlChar *
5619xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005620 const xmlChar *in;
5621 xmlChar *ret;
5622 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005623
Daniel Veillard61d80a22001-04-27 17:13:01 +00005624 /*
5625 * Accelerator for simple ASCII names
5626 */
5627 in = ctxt->cur;
5628 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5629 ((*in >= 0x41) && (*in <= 0x5A)) ||
5630 (*in == '_') || (*in == ':')) {
5631 in++;
5632 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5633 ((*in >= 0x41) && (*in <= 0x5A)) ||
5634 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00005635 (*in == '_') || (*in == '-') ||
5636 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00005637 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00005638 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005639 count = in - ctxt->cur;
5640 ret = xmlStrndup(ctxt->cur, count);
5641 ctxt->cur = in;
5642 return(ret);
5643 }
5644 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005645 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005646}
5647
Daniel Veillard61d80a22001-04-27 17:13:01 +00005648static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005649xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005650 xmlChar buf[XML_MAX_NAMELEN + 5];
5651 int len = 0, l;
5652 int c;
5653
5654 /*
5655 * Handler for more complex cases
5656 */
5657 c = CUR_CHAR(l);
5658 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005659 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5660 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005661 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005662 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005663 return(NULL);
5664 }
5665
5666 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5667 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5668 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005669 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005670 (IS_COMBINING(c)) ||
5671 (IS_EXTENDER(c)))) {
5672 COPY_BUF(l,buf,len,c);
5673 NEXTL(l);
5674 c = CUR_CHAR(l);
5675 if (len >= XML_MAX_NAMELEN) {
5676 /*
5677 * Okay someone managed to make a huge name, so he's ready to pay
5678 * for the processing speed.
5679 */
5680 xmlChar *buffer;
5681 int max = len * 2;
5682
5683 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5684 if (buffer == NULL) {
5685 XP_ERROR0(XPATH_MEMORY_ERROR);
5686 }
5687 memcpy(buffer, buf, len);
5688 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5689 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005690 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005691 (IS_COMBINING(c)) ||
5692 (IS_EXTENDER(c))) {
5693 if (len + 10 > max) {
5694 max *= 2;
5695 buffer = (xmlChar *) xmlRealloc(buffer,
5696 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00005697 if (buffer == NULL) {
5698 XP_ERROR0(XPATH_MEMORY_ERROR);
5699 }
5700 }
5701 COPY_BUF(l,buffer,len,c);
5702 NEXTL(l);
5703 c = CUR_CHAR(l);
5704 }
5705 buffer[len] = 0;
5706 return(buffer);
5707 }
5708 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005709 if (len == 0)
5710 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005711 return(xmlStrndup(buf, len));
5712}
Owen Taylor3473f882001-02-23 17:55:21 +00005713/**
5714 * xmlXPathStringEvalNumber:
5715 * @str: A string to scan
5716 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005717 * [30a] Float ::= Number ('e' Digits?)?
5718 *
Owen Taylor3473f882001-02-23 17:55:21 +00005719 * [30] Number ::= Digits ('.' Digits?)?
5720 * | '.' Digits
5721 * [31] Digits ::= [0-9]+
5722 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005723 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005724 * In complement of the Number expression, this function also handles
5725 * negative values : '-' Number.
5726 *
5727 * Returns the double value.
5728 */
5729double
5730xmlXPathStringEvalNumber(const xmlChar *str) {
5731 const xmlChar *cur = str;
5732 double ret = 0.0;
5733 double mult = 1;
5734 int ok = 0;
5735 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005736 int exponent = 0;
5737 int is_exponent_negative = 0;
5738
Owen Taylor3473f882001-02-23 17:55:21 +00005739 while (IS_BLANK(*cur)) cur++;
5740 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5741 return(xmlXPathNAN);
5742 }
5743 if (*cur == '-') {
5744 isneg = 1;
5745 cur++;
5746 }
5747 while ((*cur >= '0') && (*cur <= '9')) {
5748 ret = ret * 10 + (*cur - '0');
5749 ok = 1;
5750 cur++;
5751 }
5752 if (*cur == '.') {
5753 cur++;
5754 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5755 return(xmlXPathNAN);
5756 }
5757 while ((*cur >= '0') && (*cur <= '9')) {
5758 mult /= 10;
5759 ret = ret + (*cur - '0') * mult;
5760 cur++;
5761 }
5762 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005763 if ((*cur == 'e') || (*cur == 'E')) {
5764 cur++;
5765 if (*cur == '-') {
5766 is_exponent_negative = 1;
5767 cur++;
5768 }
5769 while ((*cur >= '0') && (*cur <= '9')) {
5770 exponent = exponent * 10 + (*cur - '0');
5771 cur++;
5772 }
5773 }
Owen Taylor3473f882001-02-23 17:55:21 +00005774 while (IS_BLANK(*cur)) cur++;
5775 if (*cur != 0) return(xmlXPathNAN);
5776 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005777 if (is_exponent_negative) exponent = -exponent;
5778 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005779 return(ret);
5780}
5781
5782/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005783 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005784 * @ctxt: the XPath Parser context
5785 *
5786 * [30] Number ::= Digits ('.' Digits?)?
5787 * | '.' Digits
5788 * [31] Digits ::= [0-9]+
5789 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005790 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005791 *
5792 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005793static void
5794xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005795 double ret = 0.0;
5796 double mult = 1;
5797 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005798 int exponent = 0;
5799 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005800
5801 CHECK_ERROR;
5802 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5803 XP_ERROR(XPATH_NUMBER_ERROR);
5804 }
5805 while ((CUR >= '0') && (CUR <= '9')) {
5806 ret = ret * 10 + (CUR - '0');
5807 ok = 1;
5808 NEXT;
5809 }
5810 if (CUR == '.') {
5811 NEXT;
5812 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5813 XP_ERROR(XPATH_NUMBER_ERROR);
5814 }
5815 while ((CUR >= '0') && (CUR <= '9')) {
5816 mult /= 10;
5817 ret = ret + (CUR - '0') * mult;
5818 NEXT;
5819 }
5820 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005821 if ((CUR == 'e') || (CUR == 'E')) {
5822 NEXT;
5823 if (CUR == '-') {
5824 is_exponent_negative = 1;
5825 NEXT;
5826 }
5827 while ((CUR >= '0') && (CUR <= '9')) {
5828 exponent = exponent * 10 + (CUR - '0');
5829 NEXT;
5830 }
5831 }
5832 if (is_exponent_negative)
5833 exponent = -exponent;
5834 ret *= pow(10.0, (double)exponent);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005835 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5836 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005837}
5838
5839/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005840 * xmlXPathParseLiteral:
5841 * @ctxt: the XPath Parser context
5842 *
5843 * Parse a Literal
5844 *
5845 * [29] Literal ::= '"' [^"]* '"'
5846 * | "'" [^']* "'"
5847 *
5848 * Returns the value found or NULL in case of error
5849 */
5850static xmlChar *
5851xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5852 const xmlChar *q;
5853 xmlChar *ret = NULL;
5854
5855 if (CUR == '"') {
5856 NEXT;
5857 q = CUR_PTR;
5858 while ((IS_CHAR(CUR)) && (CUR != '"'))
5859 NEXT;
5860 if (!IS_CHAR(CUR)) {
5861 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5862 } else {
5863 ret = xmlStrndup(q, CUR_PTR - q);
5864 NEXT;
5865 }
5866 } else if (CUR == '\'') {
5867 NEXT;
5868 q = CUR_PTR;
5869 while ((IS_CHAR(CUR)) && (CUR != '\''))
5870 NEXT;
5871 if (!IS_CHAR(CUR)) {
5872 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5873 } else {
5874 ret = xmlStrndup(q, CUR_PTR - q);
5875 NEXT;
5876 }
5877 } else {
5878 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5879 }
5880 return(ret);
5881}
5882
5883/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005884 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005885 * @ctxt: the XPath Parser context
5886 *
5887 * Parse a Literal and push it on the stack.
5888 *
5889 * [29] Literal ::= '"' [^"]* '"'
5890 * | "'" [^']* "'"
5891 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005892 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005893 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005894static void
5895xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005896 const xmlChar *q;
5897 xmlChar *ret = NULL;
5898
5899 if (CUR == '"') {
5900 NEXT;
5901 q = CUR_PTR;
5902 while ((IS_CHAR(CUR)) && (CUR != '"'))
5903 NEXT;
5904 if (!IS_CHAR(CUR)) {
5905 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5906 } else {
5907 ret = xmlStrndup(q, CUR_PTR - q);
5908 NEXT;
5909 }
5910 } else if (CUR == '\'') {
5911 NEXT;
5912 q = CUR_PTR;
5913 while ((IS_CHAR(CUR)) && (CUR != '\''))
5914 NEXT;
5915 if (!IS_CHAR(CUR)) {
5916 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5917 } else {
5918 ret = xmlStrndup(q, CUR_PTR - q);
5919 NEXT;
5920 }
5921 } else {
5922 XP_ERROR(XPATH_START_LITERAL_ERROR);
5923 }
5924 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005925 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5926 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005927 xmlFree(ret);
5928}
5929
5930/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005931 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005932 * @ctxt: the XPath Parser context
5933 *
5934 * Parse a VariableReference, evaluate it and push it on the stack.
5935 *
5936 * The variable bindings consist of a mapping from variable names
5937 * to variable values. The value of a variable is an object, which
5938 * of any of the types that are possible for the value of an expression,
5939 * and may also be of additional types not specified here.
5940 *
5941 * Early evaluation is possible since:
5942 * The variable bindings [...] used to evaluate a subexpression are
5943 * always the same as those used to evaluate the containing expression.
5944 *
5945 * [36] VariableReference ::= '$' QName
5946 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005947static void
5948xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005949 xmlChar *name;
5950 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005951
5952 SKIP_BLANKS;
5953 if (CUR != '$') {
5954 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5955 }
5956 NEXT;
5957 name = xmlXPathParseQName(ctxt, &prefix);
5958 if (name == NULL) {
5959 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5960 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005961 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005962 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5963 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005964 SKIP_BLANKS;
5965}
5966
5967/**
5968 * xmlXPathIsNodeType:
5969 * @ctxt: the XPath Parser context
5970 * @name: a name string
5971 *
5972 * Is the name given a NodeType one.
5973 *
5974 * [38] NodeType ::= 'comment'
5975 * | 'text'
5976 * | 'processing-instruction'
5977 * | 'node'
5978 *
5979 * Returns 1 if true 0 otherwise
5980 */
5981int
5982xmlXPathIsNodeType(const xmlChar *name) {
5983 if (name == NULL)
5984 return(0);
5985
5986 if (xmlStrEqual(name, BAD_CAST "comment"))
5987 return(1);
5988 if (xmlStrEqual(name, BAD_CAST "text"))
5989 return(1);
5990 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5991 return(1);
5992 if (xmlStrEqual(name, BAD_CAST "node"))
5993 return(1);
5994 return(0);
5995}
5996
5997/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005998 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005999 * @ctxt: the XPath Parser context
6000 *
6001 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6002 * [17] Argument ::= Expr
6003 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006004 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006005 * pushed on the stack
6006 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006007static void
6008xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006009 xmlChar *name;
6010 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006011 int nbargs = 0;
6012
6013 name = xmlXPathParseQName(ctxt, &prefix);
6014 if (name == NULL) {
6015 XP_ERROR(XPATH_EXPR_ERROR);
6016 }
6017 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006018#ifdef DEBUG_EXPR
6019 if (prefix == NULL)
6020 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6021 name);
6022 else
6023 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6024 prefix, name);
6025#endif
6026
Owen Taylor3473f882001-02-23 17:55:21 +00006027 if (CUR != '(') {
6028 XP_ERROR(XPATH_EXPR_ERROR);
6029 }
6030 NEXT;
6031 SKIP_BLANKS;
6032
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006033 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006034 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006035 int op1 = ctxt->comp->last;
6036 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006037 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006038 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006039 nbargs++;
6040 if (CUR == ')') break;
6041 if (CUR != ',') {
6042 XP_ERROR(XPATH_EXPR_ERROR);
6043 }
6044 NEXT;
6045 SKIP_BLANKS;
6046 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006047 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6048 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006049 NEXT;
6050 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006051}
6052
6053/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006054 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006055 * @ctxt: the XPath Parser context
6056 *
6057 * [15] PrimaryExpr ::= VariableReference
6058 * | '(' Expr ')'
6059 * | Literal
6060 * | Number
6061 * | FunctionCall
6062 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006063 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006064 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006065static void
6066xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006067 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006068 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006069 else if (CUR == '(') {
6070 NEXT;
6071 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006072 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006073 if (CUR != ')') {
6074 XP_ERROR(XPATH_EXPR_ERROR);
6075 }
6076 NEXT;
6077 SKIP_BLANKS;
6078 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006079 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006080 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006081 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006082 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006083 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006084 }
6085 SKIP_BLANKS;
6086}
6087
6088/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006089 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006090 * @ctxt: the XPath Parser context
6091 *
6092 * [20] FilterExpr ::= PrimaryExpr
6093 * | FilterExpr Predicate
6094 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006095 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006096 * Square brackets are used to filter expressions in the same way that
6097 * they are used in location paths. It is an error if the expression to
6098 * be filtered does not evaluate to a node-set. The context node list
6099 * used for evaluating the expression in square brackets is the node-set
6100 * to be filtered listed in document order.
6101 */
6102
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006103static void
6104xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6105 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006106 CHECK_ERROR;
6107 SKIP_BLANKS;
6108
6109 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006110 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006111 SKIP_BLANKS;
6112 }
6113
6114
6115}
6116
6117/**
6118 * xmlXPathScanName:
6119 * @ctxt: the XPath Parser context
6120 *
6121 * Trickery: parse an XML name but without consuming the input flow
6122 * Needed to avoid insanity in the parser state.
6123 *
6124 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6125 * CombiningChar | Extender
6126 *
6127 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6128 *
6129 * [6] Names ::= Name (S Name)*
6130 *
6131 * Returns the Name parsed or NULL
6132 */
6133
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006134static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006135xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6136 xmlChar buf[XML_MAX_NAMELEN];
6137 int len = 0;
6138
6139 SKIP_BLANKS;
6140 if (!IS_LETTER(CUR) && (CUR != '_') &&
6141 (CUR != ':')) {
6142 return(NULL);
6143 }
6144
6145 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6146 (NXT(len) == '.') || (NXT(len) == '-') ||
6147 (NXT(len) == '_') || (NXT(len) == ':') ||
6148 (IS_COMBINING(NXT(len))) ||
6149 (IS_EXTENDER(NXT(len)))) {
6150 buf[len] = NXT(len);
6151 len++;
6152 if (len >= XML_MAX_NAMELEN) {
6153 xmlGenericError(xmlGenericErrorContext,
6154 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6155 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6156 (NXT(len) == '.') || (NXT(len) == '-') ||
6157 (NXT(len) == '_') || (NXT(len) == ':') ||
6158 (IS_COMBINING(NXT(len))) ||
6159 (IS_EXTENDER(NXT(len))))
6160 len++;
6161 break;
6162 }
6163 }
6164 return(xmlStrndup(buf, len));
6165}
6166
6167/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006168 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006169 * @ctxt: the XPath Parser context
6170 *
6171 * [19] PathExpr ::= LocationPath
6172 * | FilterExpr
6173 * | FilterExpr '/' RelativeLocationPath
6174 * | FilterExpr '//' RelativeLocationPath
6175 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006176 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006177 * The / operator and // operators combine an arbitrary expression
6178 * and a relative location path. It is an error if the expression
6179 * does not evaluate to a node-set.
6180 * The / operator does composition in the same way as when / is
6181 * used in a location path. As in location paths, // is short for
6182 * /descendant-or-self::node()/.
6183 */
6184
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006185static void
6186xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006187 int lc = 1; /* Should we branch to LocationPath ? */
6188 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6189
6190 SKIP_BLANKS;
6191 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6192 (CUR == '\'') || (CUR == '"')) {
6193 lc = 0;
6194 } else if (CUR == '*') {
6195 /* relative or absolute location path */
6196 lc = 1;
6197 } else if (CUR == '/') {
6198 /* relative or absolute location path */
6199 lc = 1;
6200 } else if (CUR == '@') {
6201 /* relative abbreviated attribute location path */
6202 lc = 1;
6203 } else if (CUR == '.') {
6204 /* relative abbreviated attribute location path */
6205 lc = 1;
6206 } else {
6207 /*
6208 * Problem is finding if we have a name here whether it's:
6209 * - a nodetype
6210 * - a function call in which case it's followed by '('
6211 * - an axis in which case it's followed by ':'
6212 * - a element name
6213 * We do an a priori analysis here rather than having to
6214 * maintain parsed token content through the recursive function
6215 * calls. This looks uglier but makes the code quite easier to
6216 * read/write/debug.
6217 */
6218 SKIP_BLANKS;
6219 name = xmlXPathScanName(ctxt);
6220 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6221#ifdef DEBUG_STEP
6222 xmlGenericError(xmlGenericErrorContext,
6223 "PathExpr: Axis\n");
6224#endif
6225 lc = 1;
6226 xmlFree(name);
6227 } else if (name != NULL) {
6228 int len =xmlStrlen(name);
6229 int blank = 0;
6230
6231
6232 while (NXT(len) != 0) {
6233 if (NXT(len) == '/') {
6234 /* element name */
6235#ifdef DEBUG_STEP
6236 xmlGenericError(xmlGenericErrorContext,
6237 "PathExpr: AbbrRelLocation\n");
6238#endif
6239 lc = 1;
6240 break;
6241 } else if (IS_BLANK(NXT(len))) {
6242 /* skip to next */
6243 blank = 1;
6244 } else if (NXT(len) == ':') {
6245#ifdef DEBUG_STEP
6246 xmlGenericError(xmlGenericErrorContext,
6247 "PathExpr: AbbrRelLocation\n");
6248#endif
6249 lc = 1;
6250 break;
6251 } else if ((NXT(len) == '(')) {
6252 /* Note Type or Function */
6253 if (xmlXPathIsNodeType(name)) {
6254#ifdef DEBUG_STEP
6255 xmlGenericError(xmlGenericErrorContext,
6256 "PathExpr: Type search\n");
6257#endif
6258 lc = 1;
6259 } else {
6260#ifdef DEBUG_STEP
6261 xmlGenericError(xmlGenericErrorContext,
6262 "PathExpr: function call\n");
6263#endif
6264 lc = 0;
6265 }
6266 break;
6267 } else if ((NXT(len) == '[')) {
6268 /* element name */
6269#ifdef DEBUG_STEP
6270 xmlGenericError(xmlGenericErrorContext,
6271 "PathExpr: AbbrRelLocation\n");
6272#endif
6273 lc = 1;
6274 break;
6275 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6276 (NXT(len) == '=')) {
6277 lc = 1;
6278 break;
6279 } else {
6280 lc = 1;
6281 break;
6282 }
6283 len++;
6284 }
6285 if (NXT(len) == 0) {
6286#ifdef DEBUG_STEP
6287 xmlGenericError(xmlGenericErrorContext,
6288 "PathExpr: AbbrRelLocation\n");
6289#endif
6290 /* element name */
6291 lc = 1;
6292 }
6293 xmlFree(name);
6294 } else {
6295 /* make sure all cases are covered explicitely */
6296 XP_ERROR(XPATH_EXPR_ERROR);
6297 }
6298 }
6299
6300 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006301 if (CUR == '/') {
6302 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6303 } else {
6304 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006305 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006306 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006307 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006308 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006309 CHECK_ERROR;
6310 if ((CUR == '/') && (NXT(1) == '/')) {
6311 SKIP(2);
6312 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006313
6314 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6315 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6316 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6317
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006318 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006319 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006320 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006321 }
6322 }
6323 SKIP_BLANKS;
6324}
6325
6326/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006327 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006328 * @ctxt: the XPath Parser context
6329 *
6330 * [18] UnionExpr ::= PathExpr
6331 * | UnionExpr '|' PathExpr
6332 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006333 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006334 */
6335
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006336static void
6337xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6338 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006339 CHECK_ERROR;
6340 SKIP_BLANKS;
6341 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006342 int op1 = ctxt->comp->last;
6343 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006344
6345 NEXT;
6346 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006347 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006348
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006349 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6350
Owen Taylor3473f882001-02-23 17:55:21 +00006351 SKIP_BLANKS;
6352 }
Owen Taylor3473f882001-02-23 17:55:21 +00006353}
6354
6355/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006356 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006357 * @ctxt: the XPath Parser context
6358 *
6359 * [27] UnaryExpr ::= UnionExpr
6360 * | '-' UnaryExpr
6361 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006362 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006363 */
6364
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006365static void
6366xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006367 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006368 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006369
6370 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006371 while (CUR == '-') {
6372 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006373 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006374 NEXT;
6375 SKIP_BLANKS;
6376 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006377
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006378 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006379 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006380 if (found) {
6381 if (minus)
6382 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6383 else
6384 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006385 }
6386}
6387
6388/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006389 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006390 * @ctxt: the XPath Parser context
6391 *
6392 * [26] MultiplicativeExpr ::= UnaryExpr
6393 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6394 * | MultiplicativeExpr 'div' UnaryExpr
6395 * | MultiplicativeExpr 'mod' UnaryExpr
6396 * [34] MultiplyOperator ::= '*'
6397 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006398 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006399 */
6400
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006401static void
6402xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6403 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006404 CHECK_ERROR;
6405 SKIP_BLANKS;
6406 while ((CUR == '*') ||
6407 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6408 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6409 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006410 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006411
6412 if (CUR == '*') {
6413 op = 0;
6414 NEXT;
6415 } else if (CUR == 'd') {
6416 op = 1;
6417 SKIP(3);
6418 } else if (CUR == 'm') {
6419 op = 2;
6420 SKIP(3);
6421 }
6422 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006423 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006424 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006425 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006426 SKIP_BLANKS;
6427 }
6428}
6429
6430/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006431 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006432 * @ctxt: the XPath Parser context
6433 *
6434 * [25] AdditiveExpr ::= MultiplicativeExpr
6435 * | AdditiveExpr '+' MultiplicativeExpr
6436 * | AdditiveExpr '-' MultiplicativeExpr
6437 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006438 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006439 */
6440
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006441static void
6442xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006443
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006444 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006445 CHECK_ERROR;
6446 SKIP_BLANKS;
6447 while ((CUR == '+') || (CUR == '-')) {
6448 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006449 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006450
6451 if (CUR == '+') plus = 1;
6452 else plus = 0;
6453 NEXT;
6454 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006455 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006456 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006457 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006458 SKIP_BLANKS;
6459 }
6460}
6461
6462/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006463 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006464 * @ctxt: the XPath Parser context
6465 *
6466 * [24] RelationalExpr ::= AdditiveExpr
6467 * | RelationalExpr '<' AdditiveExpr
6468 * | RelationalExpr '>' AdditiveExpr
6469 * | RelationalExpr '<=' AdditiveExpr
6470 * | RelationalExpr '>=' AdditiveExpr
6471 *
6472 * A <= B > C is allowed ? Answer from James, yes with
6473 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6474 * which is basically what got implemented.
6475 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006476 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006477 * on the stack
6478 */
6479
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006480static void
6481xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6482 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006483 CHECK_ERROR;
6484 SKIP_BLANKS;
6485 while ((CUR == '<') ||
6486 (CUR == '>') ||
6487 ((CUR == '<') && (NXT(1) == '=')) ||
6488 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006489 int inf, strict;
6490 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006491
6492 if (CUR == '<') inf = 1;
6493 else inf = 0;
6494 if (NXT(1) == '=') strict = 0;
6495 else strict = 1;
6496 NEXT;
6497 if (!strict) NEXT;
6498 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006499 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006500 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006501 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006502 SKIP_BLANKS;
6503 }
6504}
6505
6506/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006507 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006508 * @ctxt: the XPath Parser context
6509 *
6510 * [23] EqualityExpr ::= RelationalExpr
6511 * | EqualityExpr '=' RelationalExpr
6512 * | EqualityExpr '!=' RelationalExpr
6513 *
6514 * A != B != C is allowed ? Answer from James, yes with
6515 * (RelationalExpr = RelationalExpr) = RelationalExpr
6516 * (RelationalExpr != RelationalExpr) != RelationalExpr
6517 * which is basically what got implemented.
6518 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006519 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006520 *
6521 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006522static void
6523xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6524 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006525 CHECK_ERROR;
6526 SKIP_BLANKS;
6527 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006528 int eq;
6529 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006530
6531 if (CUR == '=') eq = 1;
6532 else eq = 0;
6533 NEXT;
6534 if (!eq) NEXT;
6535 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006536 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006537 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006538 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006539 SKIP_BLANKS;
6540 }
6541}
6542
6543/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006544 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006545 * @ctxt: the XPath Parser context
6546 *
6547 * [22] AndExpr ::= EqualityExpr
6548 * | AndExpr 'and' EqualityExpr
6549 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006550 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006551 *
6552 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006553static void
6554xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6555 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006556 CHECK_ERROR;
6557 SKIP_BLANKS;
6558 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006559 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006560 SKIP(3);
6561 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006562 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006563 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006564 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006565 SKIP_BLANKS;
6566 }
6567}
6568
6569/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006570 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006571 * @ctxt: the XPath Parser context
6572 *
6573 * [14] Expr ::= OrExpr
6574 * [21] OrExpr ::= AndExpr
6575 * | OrExpr 'or' AndExpr
6576 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006577 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006578 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006579static void
6580xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6581 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006582 CHECK_ERROR;
6583 SKIP_BLANKS;
6584 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006585 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006586 SKIP(2);
6587 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006588 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006589 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006590 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6591 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006592 SKIP_BLANKS;
6593 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006594 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6595 /* more ops could be optimized too */
6596 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6597 }
Owen Taylor3473f882001-02-23 17:55:21 +00006598}
6599
6600/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006601 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006602 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006603 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006604 *
6605 * [8] Predicate ::= '[' PredicateExpr ']'
6606 * [9] PredicateExpr ::= Expr
6607 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006608 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006609 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006610static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006611xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006612 int op1 = ctxt->comp->last;
6613
6614 SKIP_BLANKS;
6615 if (CUR != '[') {
6616 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6617 }
6618 NEXT;
6619 SKIP_BLANKS;
6620
6621 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006622 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006623 CHECK_ERROR;
6624
6625 if (CUR != ']') {
6626 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6627 }
6628
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006629 if (filter)
6630 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6631 else
6632 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006633
6634 NEXT;
6635 SKIP_BLANKS;
6636}
6637
6638/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006639 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006640 * @ctxt: the XPath Parser context
6641 * @test: pointer to a xmlXPathTestVal
6642 * @type: pointer to a xmlXPathTypeVal
6643 * @prefix: placeholder for a possible name prefix
6644 *
6645 * [7] NodeTest ::= NameTest
6646 * | NodeType '(' ')'
6647 * | 'processing-instruction' '(' Literal ')'
6648 *
6649 * [37] NameTest ::= '*'
6650 * | NCName ':' '*'
6651 * | QName
6652 * [38] NodeType ::= 'comment'
6653 * | 'text'
6654 * | 'processing-instruction'
6655 * | 'node'
6656 *
6657 * Returns the name found and update @test, @type and @prefix appropriately
6658 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006659static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006660xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6661 xmlXPathTypeVal *type, const xmlChar **prefix,
6662 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006663 int blanks;
6664
6665 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6666 STRANGE;
6667 return(NULL);
6668 }
6669 *type = 0;
6670 *test = 0;
6671 *prefix = NULL;
6672 SKIP_BLANKS;
6673
6674 if ((name == NULL) && (CUR == '*')) {
6675 /*
6676 * All elements
6677 */
6678 NEXT;
6679 *test = NODE_TEST_ALL;
6680 return(NULL);
6681 }
6682
6683 if (name == NULL)
6684 name = xmlXPathParseNCName(ctxt);
6685 if (name == NULL) {
6686 XP_ERROR0(XPATH_EXPR_ERROR);
6687 }
6688
6689 blanks = IS_BLANK(CUR);
6690 SKIP_BLANKS;
6691 if (CUR == '(') {
6692 NEXT;
6693 /*
6694 * NodeType or PI search
6695 */
6696 if (xmlStrEqual(name, BAD_CAST "comment"))
6697 *type = NODE_TYPE_COMMENT;
6698 else if (xmlStrEqual(name, BAD_CAST "node"))
6699 *type = NODE_TYPE_NODE;
6700 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6701 *type = NODE_TYPE_PI;
6702 else if (xmlStrEqual(name, BAD_CAST "text"))
6703 *type = NODE_TYPE_TEXT;
6704 else {
6705 if (name != NULL)
6706 xmlFree(name);
6707 XP_ERROR0(XPATH_EXPR_ERROR);
6708 }
6709
6710 *test = NODE_TEST_TYPE;
6711
6712 SKIP_BLANKS;
6713 if (*type == NODE_TYPE_PI) {
6714 /*
6715 * Specific case: search a PI by name.
6716 */
Owen Taylor3473f882001-02-23 17:55:21 +00006717 if (name != NULL)
6718 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006719 name = NULL;
6720 if (CUR != ')') {
6721 name = xmlXPathParseLiteral(ctxt);
6722 CHECK_ERROR 0;
6723 SKIP_BLANKS;
6724 }
Owen Taylor3473f882001-02-23 17:55:21 +00006725 }
6726 if (CUR != ')') {
6727 if (name != NULL)
6728 xmlFree(name);
6729 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6730 }
6731 NEXT;
6732 return(name);
6733 }
6734 *test = NODE_TEST_NAME;
6735 if ((!blanks) && (CUR == ':')) {
6736 NEXT;
6737
6738 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006739 * Since currently the parser context don't have a
6740 * namespace list associated:
6741 * The namespace name for this prefix can be computed
6742 * only at evaluation time. The compilation is done
6743 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006744 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006745#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006746 *prefix = xmlXPathNsLookup(ctxt->context, name);
6747 if (name != NULL)
6748 xmlFree(name);
6749 if (*prefix == NULL) {
6750 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6751 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006752#else
6753 *prefix = name;
6754#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006755
6756 if (CUR == '*') {
6757 /*
6758 * All elements
6759 */
6760 NEXT;
6761 *test = NODE_TEST_ALL;
6762 return(NULL);
6763 }
6764
6765 name = xmlXPathParseNCName(ctxt);
6766 if (name == NULL) {
6767 XP_ERROR0(XPATH_EXPR_ERROR);
6768 }
6769 }
6770 return(name);
6771}
6772
6773/**
6774 * xmlXPathIsAxisName:
6775 * @name: a preparsed name token
6776 *
6777 * [6] AxisName ::= 'ancestor'
6778 * | 'ancestor-or-self'
6779 * | 'attribute'
6780 * | 'child'
6781 * | 'descendant'
6782 * | 'descendant-or-self'
6783 * | 'following'
6784 * | 'following-sibling'
6785 * | 'namespace'
6786 * | 'parent'
6787 * | 'preceding'
6788 * | 'preceding-sibling'
6789 * | 'self'
6790 *
6791 * Returns the axis or 0
6792 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006793static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006794xmlXPathIsAxisName(const xmlChar *name) {
6795 xmlXPathAxisVal ret = 0;
6796 switch (name[0]) {
6797 case 'a':
6798 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6799 ret = AXIS_ANCESTOR;
6800 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6801 ret = AXIS_ANCESTOR_OR_SELF;
6802 if (xmlStrEqual(name, BAD_CAST "attribute"))
6803 ret = AXIS_ATTRIBUTE;
6804 break;
6805 case 'c':
6806 if (xmlStrEqual(name, BAD_CAST "child"))
6807 ret = AXIS_CHILD;
6808 break;
6809 case 'd':
6810 if (xmlStrEqual(name, BAD_CAST "descendant"))
6811 ret = AXIS_DESCENDANT;
6812 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6813 ret = AXIS_DESCENDANT_OR_SELF;
6814 break;
6815 case 'f':
6816 if (xmlStrEqual(name, BAD_CAST "following"))
6817 ret = AXIS_FOLLOWING;
6818 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6819 ret = AXIS_FOLLOWING_SIBLING;
6820 break;
6821 case 'n':
6822 if (xmlStrEqual(name, BAD_CAST "namespace"))
6823 ret = AXIS_NAMESPACE;
6824 break;
6825 case 'p':
6826 if (xmlStrEqual(name, BAD_CAST "parent"))
6827 ret = AXIS_PARENT;
6828 if (xmlStrEqual(name, BAD_CAST "preceding"))
6829 ret = AXIS_PRECEDING;
6830 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6831 ret = AXIS_PRECEDING_SIBLING;
6832 break;
6833 case 's':
6834 if (xmlStrEqual(name, BAD_CAST "self"))
6835 ret = AXIS_SELF;
6836 break;
6837 }
6838 return(ret);
6839}
6840
6841/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006842 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006843 * @ctxt: the XPath Parser context
6844 *
6845 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6846 * | AbbreviatedStep
6847 *
6848 * [12] AbbreviatedStep ::= '.' | '..'
6849 *
6850 * [5] AxisSpecifier ::= AxisName '::'
6851 * | AbbreviatedAxisSpecifier
6852 *
6853 * [13] AbbreviatedAxisSpecifier ::= '@'?
6854 *
6855 * Modified for XPtr range support as:
6856 *
6857 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6858 * | AbbreviatedStep
6859 * | 'range-to' '(' Expr ')' Predicate*
6860 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006861 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006862 * A location step of . is short for self::node(). This is
6863 * particularly useful in conjunction with //. For example, the
6864 * location path .//para is short for
6865 * self::node()/descendant-or-self::node()/child::para
6866 * and so will select all para descendant elements of the context
6867 * node.
6868 * Similarly, a location step of .. is short for parent::node().
6869 * For example, ../title is short for parent::node()/child::title
6870 * and so will select the title children of the parent of the context
6871 * node.
6872 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006873static void
6874xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006875#ifdef LIBXML_XPTR_ENABLED
6876 int rangeto = 0;
6877 int op2 = -1;
6878#endif
6879
Owen Taylor3473f882001-02-23 17:55:21 +00006880 SKIP_BLANKS;
6881 if ((CUR == '.') && (NXT(1) == '.')) {
6882 SKIP(2);
6883 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006884 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6885 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006886 } else if (CUR == '.') {
6887 NEXT;
6888 SKIP_BLANKS;
6889 } else {
6890 xmlChar *name = NULL;
6891 const xmlChar *prefix = NULL;
6892 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006893 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006894 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006895 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006896
6897 /*
6898 * The modification needed for XPointer change to the production
6899 */
6900#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006901 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006902 name = xmlXPathParseNCName(ctxt);
6903 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006904 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006905 xmlFree(name);
6906 SKIP_BLANKS;
6907 if (CUR != '(') {
6908 XP_ERROR(XPATH_EXPR_ERROR);
6909 }
6910 NEXT;
6911 SKIP_BLANKS;
6912
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006913 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006914 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006915 CHECK_ERROR;
6916
6917 SKIP_BLANKS;
6918 if (CUR != ')') {
6919 XP_ERROR(XPATH_EXPR_ERROR);
6920 }
6921 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006922 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006923 goto eval_predicates;
6924 }
6925 }
6926#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006927 if (CUR == '*') {
6928 axis = AXIS_CHILD;
6929 } else {
6930 if (name == NULL)
6931 name = xmlXPathParseNCName(ctxt);
6932 if (name != NULL) {
6933 axis = xmlXPathIsAxisName(name);
6934 if (axis != 0) {
6935 SKIP_BLANKS;
6936 if ((CUR == ':') && (NXT(1) == ':')) {
6937 SKIP(2);
6938 xmlFree(name);
6939 name = NULL;
6940 } else {
6941 /* an element name can conflict with an axis one :-\ */
6942 axis = AXIS_CHILD;
6943 }
Owen Taylor3473f882001-02-23 17:55:21 +00006944 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00006945 axis = AXIS_CHILD;
6946 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006947 } else if (CUR == '@') {
6948 NEXT;
6949 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00006950 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00006951 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00006952 }
Owen Taylor3473f882001-02-23 17:55:21 +00006953 }
6954
6955 CHECK_ERROR;
6956
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006957 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006958 if (test == 0)
6959 return;
6960
6961#ifdef DEBUG_STEP
6962 xmlGenericError(xmlGenericErrorContext,
6963 "Basis : computing new set\n");
6964#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006965
Owen Taylor3473f882001-02-23 17:55:21 +00006966#ifdef DEBUG_STEP
6967 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006968 if (ctxt->value == NULL)
6969 xmlGenericError(xmlGenericErrorContext, "no value\n");
6970 else if (ctxt->value->nodesetval == NULL)
6971 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6972 else
6973 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006974#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006975
6976eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006977 op1 = ctxt->comp->last;
6978 ctxt->comp->last = -1;
6979
Owen Taylor3473f882001-02-23 17:55:21 +00006980 SKIP_BLANKS;
6981 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006982 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006983 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006984
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006985#ifdef LIBXML_XPTR_ENABLED
6986 if (rangeto) {
6987 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
6988 } else
6989#endif
6990 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
6991 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006992
Owen Taylor3473f882001-02-23 17:55:21 +00006993 }
6994#ifdef DEBUG_STEP
6995 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006996 if (ctxt->value == NULL)
6997 xmlGenericError(xmlGenericErrorContext, "no value\n");
6998 else if (ctxt->value->nodesetval == NULL)
6999 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7000 else
7001 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7002 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007003#endif
7004}
7005
7006/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007007 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007008 * @ctxt: the XPath Parser context
7009 *
7010 * [3] RelativeLocationPath ::= Step
7011 * | RelativeLocationPath '/' Step
7012 * | AbbreviatedRelativeLocationPath
7013 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7014 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007015 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007016 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007017static void
Owen Taylor3473f882001-02-23 17:55:21 +00007018#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007019xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007020#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007021xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007022#endif
7023(xmlXPathParserContextPtr ctxt) {
7024 SKIP_BLANKS;
7025 if ((CUR == '/') && (NXT(1) == '/')) {
7026 SKIP(2);
7027 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007028 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7029 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007030 } else if (CUR == '/') {
7031 NEXT;
7032 SKIP_BLANKS;
7033 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007034 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007035 SKIP_BLANKS;
7036 while (CUR == '/') {
7037 if ((CUR == '/') && (NXT(1) == '/')) {
7038 SKIP(2);
7039 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007040 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007041 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007042 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007043 } else if (CUR == '/') {
7044 NEXT;
7045 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007046 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007047 }
7048 SKIP_BLANKS;
7049 }
7050}
7051
7052/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007053 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007054 * @ctxt: the XPath Parser context
7055 *
7056 * [1] LocationPath ::= RelativeLocationPath
7057 * | AbsoluteLocationPath
7058 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7059 * | AbbreviatedAbsoluteLocationPath
7060 * [10] AbbreviatedAbsoluteLocationPath ::=
7061 * '//' RelativeLocationPath
7062 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007063 * Compile a location path
7064 *
Owen Taylor3473f882001-02-23 17:55:21 +00007065 * // is short for /descendant-or-self::node()/. For example,
7066 * //para is short for /descendant-or-self::node()/child::para and
7067 * so will select any para element in the document (even a para element
7068 * that is a document element will be selected by //para since the
7069 * document element node is a child of the root node); div//para is
7070 * short for div/descendant-or-self::node()/child::para and so will
7071 * select all para descendants of div children.
7072 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007073static void
7074xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007075 SKIP_BLANKS;
7076 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007077 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007078 } else {
7079 while (CUR == '/') {
7080 if ((CUR == '/') && (NXT(1) == '/')) {
7081 SKIP(2);
7082 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007083 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7084 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007085 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007086 } else if (CUR == '/') {
7087 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007088 SKIP_BLANKS;
7089 if ((CUR != 0 ) &&
7090 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7091 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007092 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007093 }
7094 }
7095 }
7096}
7097
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007098/************************************************************************
7099 * *
7100 * XPath precompiled expression evaluation *
7101 * *
7102 ************************************************************************/
7103
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007104static void
7105xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7106
7107/**
7108 * xmlXPathNodeCollectAndTest:
7109 * @ctxt: the XPath Parser context
7110 * @op: the XPath precompiled step operation
7111 *
7112 * This is the function implementing a step: based on the current list
7113 * of nodes, it builds up a new list, looking at all nodes under that
7114 * axis and selecting them it also do the predicate filtering
7115 *
7116 * Pushes the new NodeSet resulting from the search.
7117 */
7118static void
7119xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
7120 xmlXPathStepOpPtr op) {
7121 xmlXPathAxisVal axis = op->value;
7122 xmlXPathTestVal test = op->value2;
7123 xmlXPathTypeVal type = op->value3;
7124 const xmlChar *prefix = op->value4;
7125 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007126 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007127
7128#ifdef DEBUG_STEP
7129 int n = 0, t = 0;
7130#endif
7131 int i;
7132 xmlNodeSetPtr ret, list;
7133 xmlXPathTraversalFunction next = NULL;
7134 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
7135 xmlNodePtr cur = NULL;
7136 xmlXPathObjectPtr obj;
7137 xmlNodeSetPtr nodelist;
7138 xmlNodePtr tmp;
7139
7140 CHECK_TYPE(XPATH_NODESET);
7141 obj = valuePop(ctxt);
7142 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007143 if (prefix != NULL) {
7144 URI = xmlXPathNsLookup(ctxt->context, prefix);
7145 if (URI == NULL)
7146 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
7147 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007148
7149#ifdef DEBUG_STEP
7150 xmlGenericError(xmlGenericErrorContext,
7151 "new step : ");
7152#endif
7153 switch (axis) {
7154 case AXIS_ANCESTOR:
7155#ifdef DEBUG_STEP
7156 xmlGenericError(xmlGenericErrorContext,
7157 "axis 'ancestors' ");
7158#endif
7159 next = xmlXPathNextAncestor; break;
7160 case AXIS_ANCESTOR_OR_SELF:
7161#ifdef DEBUG_STEP
7162 xmlGenericError(xmlGenericErrorContext,
7163 "axis 'ancestors-or-self' ");
7164#endif
7165 next = xmlXPathNextAncestorOrSelf; break;
7166 case AXIS_ATTRIBUTE:
7167#ifdef DEBUG_STEP
7168 xmlGenericError(xmlGenericErrorContext,
7169 "axis 'attributes' ");
7170#endif
7171 next = xmlXPathNextAttribute; break;
7172 break;
7173 case AXIS_CHILD:
7174#ifdef DEBUG_STEP
7175 xmlGenericError(xmlGenericErrorContext,
7176 "axis 'child' ");
7177#endif
7178 next = xmlXPathNextChild; break;
7179 case AXIS_DESCENDANT:
7180#ifdef DEBUG_STEP
7181 xmlGenericError(xmlGenericErrorContext,
7182 "axis 'descendant' ");
7183#endif
7184 next = xmlXPathNextDescendant; break;
7185 case AXIS_DESCENDANT_OR_SELF:
7186#ifdef DEBUG_STEP
7187 xmlGenericError(xmlGenericErrorContext,
7188 "axis 'descendant-or-self' ");
7189#endif
7190 next = xmlXPathNextDescendantOrSelf; break;
7191 case AXIS_FOLLOWING:
7192#ifdef DEBUG_STEP
7193 xmlGenericError(xmlGenericErrorContext,
7194 "axis 'following' ");
7195#endif
7196 next = xmlXPathNextFollowing; break;
7197 case AXIS_FOLLOWING_SIBLING:
7198#ifdef DEBUG_STEP
7199 xmlGenericError(xmlGenericErrorContext,
7200 "axis 'following-siblings' ");
7201#endif
7202 next = xmlXPathNextFollowingSibling; break;
7203 case AXIS_NAMESPACE:
7204#ifdef DEBUG_STEP
7205 xmlGenericError(xmlGenericErrorContext,
7206 "axis 'namespace' ");
7207#endif
7208 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
7209 break;
7210 case AXIS_PARENT:
7211#ifdef DEBUG_STEP
7212 xmlGenericError(xmlGenericErrorContext,
7213 "axis 'parent' ");
7214#endif
7215 next = xmlXPathNextParent; break;
7216 case AXIS_PRECEDING:
7217#ifdef DEBUG_STEP
7218 xmlGenericError(xmlGenericErrorContext,
7219 "axis 'preceding' ");
7220#endif
7221 next = xmlXPathNextPreceding; break;
7222 case AXIS_PRECEDING_SIBLING:
7223#ifdef DEBUG_STEP
7224 xmlGenericError(xmlGenericErrorContext,
7225 "axis 'preceding-sibling' ");
7226#endif
7227 next = xmlXPathNextPrecedingSibling; break;
7228 case AXIS_SELF:
7229#ifdef DEBUG_STEP
7230 xmlGenericError(xmlGenericErrorContext,
7231 "axis 'self' ");
7232#endif
7233 next = xmlXPathNextSelf; break;
7234 }
7235 if (next == NULL)
7236 return;
7237
7238 nodelist = obj->nodesetval;
7239 if (nodelist == NULL) {
7240 xmlXPathFreeObject(obj);
7241 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7242 return;
7243 }
7244 addNode = xmlXPathNodeSetAddUnique;
7245 ret = NULL;
7246#ifdef DEBUG_STEP
7247 xmlGenericError(xmlGenericErrorContext,
7248 " context contains %d nodes\n",
7249 nodelist->nodeNr);
7250 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007251 case NODE_TEST_NONE:
7252 xmlGenericError(xmlGenericErrorContext,
7253 " searching for none !!!\n");
7254 break;
7255 case NODE_TEST_TYPE:
7256 xmlGenericError(xmlGenericErrorContext,
7257 " searching for type %d\n", type);
7258 break;
7259 case NODE_TEST_PI:
7260 xmlGenericError(xmlGenericErrorContext,
7261 " searching for PI !!!\n");
7262 break;
7263 case NODE_TEST_ALL:
7264 xmlGenericError(xmlGenericErrorContext,
7265 " searching for *\n");
7266 break;
7267 case NODE_TEST_NS:
7268 xmlGenericError(xmlGenericErrorContext,
7269 " searching for namespace %s\n",
7270 prefix);
7271 break;
7272 case NODE_TEST_NAME:
7273 xmlGenericError(xmlGenericErrorContext,
7274 " searching for name %s\n", name);
7275 if (prefix != NULL)
7276 xmlGenericError(xmlGenericErrorContext,
7277 " with namespace %s\n",
7278 prefix);
7279 break;
7280 }
7281 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7282#endif
7283 /*
7284 * 2.3 Node Tests
7285 * - For the attribute axis, the principal node type is attribute.
7286 * - For the namespace axis, the principal node type is namespace.
7287 * - For other axes, the principal node type is element.
7288 *
7289 * A node test * is true for any node of the
7290 * principal node type. For example, child::* willi
7291 * select all element children of the context node
7292 */
7293 tmp = ctxt->context->node;
7294 for (i = 0;i < nodelist->nodeNr; i++) {
7295 ctxt->context->node = nodelist->nodeTab[i];
7296
7297 cur = NULL;
7298 list = xmlXPathNodeSetCreate(NULL);
7299 do {
7300 cur = next(ctxt, cur);
7301 if (cur == NULL) break;
7302#ifdef DEBUG_STEP
7303 t++;
7304 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7305#endif
7306 switch (test) {
7307 case NODE_TEST_NONE:
7308 ctxt->context->node = tmp;
7309 STRANGE
7310 return;
7311 case NODE_TEST_TYPE:
7312 if ((cur->type == type) ||
7313 ((type == NODE_TYPE_NODE) &&
7314 ((cur->type == XML_DOCUMENT_NODE) ||
7315 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7316 (cur->type == XML_ELEMENT_NODE) ||
7317 (cur->type == XML_PI_NODE) ||
7318 (cur->type == XML_COMMENT_NODE) ||
7319 (cur->type == XML_CDATA_SECTION_NODE) ||
7320 (cur->type == XML_TEXT_NODE)))) {
7321#ifdef DEBUG_STEP
7322 n++;
7323#endif
7324 addNode(list, cur);
7325 }
7326 break;
7327 case NODE_TEST_PI:
7328 if (cur->type == XML_PI_NODE) {
7329 if ((name != NULL) &&
7330 (!xmlStrEqual(name, cur->name)))
7331 break;
7332#ifdef DEBUG_STEP
7333 n++;
7334#endif
7335 addNode(list, cur);
7336 }
7337 break;
7338 case NODE_TEST_ALL:
7339 if (axis == AXIS_ATTRIBUTE) {
7340 if (cur->type == XML_ATTRIBUTE_NODE) {
7341#ifdef DEBUG_STEP
7342 n++;
7343#endif
7344 addNode(list, cur);
7345 }
7346 } else if (axis == AXIS_NAMESPACE) {
7347 if (cur->type == XML_NAMESPACE_DECL) {
7348#ifdef DEBUG_STEP
7349 n++;
7350#endif
7351 addNode(list, cur);
7352 }
7353 } else {
7354 if ((cur->type == XML_ELEMENT_NODE) ||
7355 (cur->type == XML_DOCUMENT_NODE) ||
7356 (cur->type == XML_HTML_DOCUMENT_NODE)) {
7357 if (prefix == NULL) {
7358#ifdef DEBUG_STEP
7359 n++;
7360#endif
7361 addNode(list, cur);
7362 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007363 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007364 cur->ns->href))) {
7365#ifdef DEBUG_STEP
7366 n++;
7367#endif
7368 addNode(list, cur);
7369 }
7370 }
7371 }
7372 break;
7373 case NODE_TEST_NS: {
7374 TODO;
7375 break;
7376 }
7377 case NODE_TEST_NAME:
7378 switch (cur->type) {
7379 case XML_ELEMENT_NODE:
7380 if (xmlStrEqual(name, cur->name)) {
7381 if (prefix == NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00007382 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007383#ifdef DEBUG_STEP
7384 n++;
7385#endif
7386 addNode(list, cur);
7387 }
7388 } else {
7389 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007390 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007391 cur->ns->href))) {
7392#ifdef DEBUG_STEP
7393 n++;
7394#endif
7395 addNode(list, cur);
7396 }
7397 }
7398 }
7399 break;
7400 case XML_ATTRIBUTE_NODE: {
7401 xmlAttrPtr attr = (xmlAttrPtr) cur;
7402 if (xmlStrEqual(name, attr->name)) {
7403 if (prefix == NULL) {
7404 if ((attr->ns == NULL) ||
7405 (attr->ns->prefix == NULL)) {
7406#ifdef DEBUG_STEP
7407 n++;
7408#endif
7409 addNode(list, (xmlNodePtr) attr);
7410 }
7411 } else {
7412 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007413 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007414 attr->ns->href))) {
7415#ifdef DEBUG_STEP
7416 n++;
7417#endif
7418 addNode(list, (xmlNodePtr) attr);
7419 }
7420 }
7421 }
7422 break;
7423 }
7424 case XML_NAMESPACE_DECL: {
7425 TODO;
7426 break;
7427 }
7428 default:
7429 break;
7430 }
7431 break;
7432 }
7433 } while (cur != NULL);
7434
7435 /*
7436 * If there is some predicate filtering do it now
7437 */
7438 if (op->ch2 != -1) {
7439 xmlXPathObjectPtr obj2;
7440
7441 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7442 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7443 CHECK_TYPE(XPATH_NODESET);
7444 obj2 = valuePop(ctxt);
7445 list = obj2->nodesetval;
7446 obj2->nodesetval = NULL;
7447 xmlXPathFreeObject(obj2);
7448 }
7449 if (ret == NULL) {
7450 ret = list;
7451 } else {
7452 ret = xmlXPathNodeSetMerge(ret, list);
7453 xmlXPathFreeNodeSet(list);
7454 }
7455 }
7456 ctxt->context->node = tmp;
7457#ifdef DEBUG_STEP
7458 xmlGenericError(xmlGenericErrorContext,
7459 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7460#endif
7461 xmlXPathFreeObject(obj);
7462 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7463}
7464
Owen Taylor3473f882001-02-23 17:55:21 +00007465/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007466 * xmlXPathCompOpEval:
7467 * @ctxt: the XPath parser context with the compiled expression
7468 * @op: an XPath compiled operation
7469 *
7470 * Evaluate the Precompiled XPath operation
7471 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007472static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007473xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7474 int equal, ret;
7475 xmlXPathCompExprPtr comp;
7476 xmlXPathObjectPtr arg1, arg2;
7477
7478 comp = ctxt->comp;
7479 switch (op->op) {
7480 case XPATH_OP_END:
7481 return;
7482 case XPATH_OP_AND:
7483 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7484 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007485 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007486 return;
7487 arg2 = valuePop(ctxt);
7488 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7489 xmlXPathBooleanFunction(ctxt, 1);
7490 arg1 = valuePop(ctxt);
7491 arg1->boolval &= arg2->boolval;
7492 valuePush(ctxt, arg1);
7493 xmlXPathFreeObject(arg2);
7494 return;
7495 case XPATH_OP_OR:
7496 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7497 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007498 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007499 return;
7500 arg2 = valuePop(ctxt);
7501 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7502 xmlXPathBooleanFunction(ctxt, 1);
7503 arg1 = valuePop(ctxt);
7504 arg1->boolval |= arg2->boolval;
7505 valuePush(ctxt, arg1);
7506 xmlXPathFreeObject(arg2);
7507 return;
7508 case XPATH_OP_EQUAL:
7509 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7510 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7511 equal = xmlXPathEqualValues(ctxt);
7512 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7513 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7514 return;
7515 case XPATH_OP_CMP:
7516 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7517 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7518 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7519 valuePush(ctxt, xmlXPathNewBoolean(ret));
7520 return;
7521 case XPATH_OP_PLUS:
7522 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7523 if (op->ch2 != -1)
7524 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7525 if (op->value == 0) xmlXPathSubValues(ctxt);
7526 else if (op->value == 1) xmlXPathAddValues(ctxt);
7527 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7528 else if (op->value == 3) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007529 CAST_TO_NUMBER;
7530 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007531 }
7532 return;
7533 case XPATH_OP_MULT:
7534 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7535 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7536 if (op->value == 0) xmlXPathMultValues(ctxt);
7537 else if (op->value == 1) xmlXPathDivValues(ctxt);
7538 else if (op->value == 2) xmlXPathModValues(ctxt);
7539 return;
7540 case XPATH_OP_UNION:
7541 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7542 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7543 CHECK_TYPE(XPATH_NODESET);
7544 arg2 = valuePop(ctxt);
7545
7546 CHECK_TYPE(XPATH_NODESET);
7547 arg1 = valuePop(ctxt);
7548
7549 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7550 arg2->nodesetval);
7551 valuePush(ctxt, arg1);
7552 xmlXPathFreeObject(arg2);
7553 return;
7554 case XPATH_OP_ROOT:
7555 xmlXPathRoot(ctxt);
7556 return;
7557 case XPATH_OP_NODE:
7558 if (op->ch1 != -1)
7559 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7560 if (op->ch2 != -1)
7561 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7562 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7563 return;
7564 case XPATH_OP_RESET:
7565 if (op->ch1 != -1)
7566 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7567 if (op->ch2 != -1)
7568 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7569 ctxt->context->node = NULL;
7570 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007571 case XPATH_OP_COLLECT: {
7572 if (op->ch1 == -1)
7573 return;
7574
7575 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7576 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007577 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007578 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007579 case XPATH_OP_VALUE:
7580 valuePush(ctxt,
7581 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7582 return;
7583 case XPATH_OP_VARIABLE: {
7584 if (op->ch1 != -1)
7585 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7586 if (op->value5 == NULL)
7587 valuePush(ctxt,
7588 xmlXPathVariableLookup(ctxt->context, op->value4));
7589 else {
7590 const xmlChar *URI;
7591 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7592 if (URI == NULL) {
7593 xmlGenericError(xmlGenericErrorContext,
7594 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7595 op->value4, op->value5);
7596 return;
7597 }
7598 valuePush(ctxt,
7599 xmlXPathVariableLookupNS(ctxt->context,
7600 op->value4, URI));
7601 }
7602 return;
7603 }
7604 case XPATH_OP_FUNCTION: {
7605 xmlXPathFunction func;
Daniel Veillard42596ad2001-05-22 16:57:14 +00007606 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007607
7608 if (op->ch1 != -1)
7609 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007610 if (op->cache != NULL)
7611 func = (xmlXPathFunction) op->cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007612 else {
Daniel Veillard42596ad2001-05-22 16:57:14 +00007613 const xmlChar *URI = NULL;
7614
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007615 if (op->value5 == NULL)
7616 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7617 else {
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007618 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7619 if (URI == NULL) {
7620 xmlGenericError(xmlGenericErrorContext,
7621 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7622 op->value4, op->value5);
7623 return;
7624 }
7625 func = xmlXPathFunctionLookupNS(ctxt->context,
7626 op->value4, URI);
7627 }
7628 if (func == NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007629 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007630 "xmlXPathRunEval: function %s not found\n",
7631 op->value4);
7632 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007633 return;
7634 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007635 op->cache = (void *) func;
Daniel Veillard42596ad2001-05-22 16:57:14 +00007636 op->cacheURI = (void *) URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007637 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00007638 oldFunc = ctxt->context->function;
7639 oldFuncURI = ctxt->context->functionURI;
7640 ctxt->context->function = op->value4;
7641 ctxt->context->functionURI = op->cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007642 func(ctxt, op->value);
Daniel Veillard42596ad2001-05-22 16:57:14 +00007643 ctxt->context->function = oldFunc;
7644 ctxt->context->functionURI = oldFuncURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007645 return;
7646 }
7647 case XPATH_OP_ARG:
7648 if (op->ch1 != -1)
7649 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7650 if (op->ch2 != -1)
7651 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7652 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007653 case XPATH_OP_PREDICATE:
7654 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007655 xmlXPathObjectPtr res;
7656 xmlXPathObjectPtr obj, tmp;
7657 xmlNodeSetPtr newset = NULL;
7658 xmlNodeSetPtr oldset;
7659 xmlNodePtr oldnode;
7660 int i;
7661
7662 if (op->ch1 != -1)
7663 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7664 if (op->ch2 == -1)
7665 return;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007666 if (ctxt->value == NULL)
7667 return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007668
7669 oldnode = ctxt->context->node;
7670
7671#ifdef LIBXML_XPTR_ENABLED
7672 /*
7673 * Hum are we filtering the result of an XPointer expression
7674 */
7675 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007676 xmlLocationSetPtr newlocset = NULL;
7677 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007678
7679 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007680 * Extract the old locset, and then evaluate the result of the
7681 * expression for all the element in the locset. use it to grow
7682 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007683 */
7684 CHECK_TYPE(XPATH_LOCATIONSET);
7685 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007686 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007687 ctxt->context->node = NULL;
7688
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007689 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007690 ctxt->context->contextSize = 0;
7691 ctxt->context->proximityPosition = 0;
7692 if (op->ch2 != -1)
7693 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7694 res = valuePop(ctxt);
7695 if (res != NULL)
7696 xmlXPathFreeObject(res);
7697 valuePush(ctxt, obj);
7698 CHECK_ERROR;
7699 return;
7700 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007701 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007702
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007703 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007704 /*
7705 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007706 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007707 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007708 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007709 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7710 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007711 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007712 ctxt->context->proximityPosition = i + 1;
7713
7714 if (op->ch2 != -1)
7715 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7716 CHECK_ERROR;
7717
7718 /*
7719 * The result of the evaluation need to be tested to
7720 * decided whether the filter succeeded or not
7721 */
7722 res = valuePop(ctxt);
7723 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007724 xmlXPtrLocationSetAdd(newlocset,
7725 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007726 }
7727
7728 /*
7729 * Cleanup
7730 */
7731 if (res != NULL)
7732 xmlXPathFreeObject(res);
7733 if (ctxt->value == tmp) {
7734 res = valuePop(ctxt);
7735 xmlXPathFreeObject(res);
7736 }
7737
7738 ctxt->context->node = NULL;
7739 }
7740
7741 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007742 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007743 */
7744 xmlXPathFreeObject(obj);
7745 ctxt->context->node = NULL;
7746 ctxt->context->contextSize = -1;
7747 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007748 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007749 ctxt->context->node = oldnode;
7750 return;
7751 }
7752#endif /* LIBXML_XPTR_ENABLED */
7753
7754 /*
7755 * Extract the old set, and then evaluate the result of the
7756 * expression for all the element in the set. use it to grow
7757 * up a new set.
7758 */
7759 CHECK_TYPE(XPATH_NODESET);
7760 obj = valuePop(ctxt);
7761 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007762
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007763 oldnode = ctxt->context->node;
7764 ctxt->context->node = NULL;
7765
7766 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7767 ctxt->context->contextSize = 0;
7768 ctxt->context->proximityPosition = 0;
7769 if (op->ch2 != -1)
7770 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7771 res = valuePop(ctxt);
7772 if (res != NULL)
7773 xmlXPathFreeObject(res);
7774 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007775 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007776 CHECK_ERROR;
7777 } else {
7778 /*
7779 * Initialize the new set.
7780 */
7781 newset = xmlXPathNodeSetCreate(NULL);
7782
7783 for (i = 0; i < oldset->nodeNr; i++) {
7784 /*
7785 * Run the evaluation with a node list made of
7786 * a single item in the nodeset.
7787 */
7788 ctxt->context->node = oldset->nodeTab[i];
7789 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7790 valuePush(ctxt, tmp);
7791 ctxt->context->contextSize = oldset->nodeNr;
7792 ctxt->context->proximityPosition = i + 1;
7793
7794 if (op->ch2 != -1)
7795 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7796 CHECK_ERROR;
7797
7798 /*
7799 * The result of the evaluation need to be tested to
7800 * decided whether the filter succeeded or not
7801 */
7802 res = valuePop(ctxt);
7803 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7804 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7805 }
7806
7807 /*
7808 * Cleanup
7809 */
7810 if (res != NULL)
7811 xmlXPathFreeObject(res);
7812 if (ctxt->value == tmp) {
7813 res = valuePop(ctxt);
7814 xmlXPathFreeObject(res);
7815 }
7816
7817 ctxt->context->node = NULL;
7818 }
7819
7820 /*
7821 * The result is used as the new evaluation set.
7822 */
7823 xmlXPathFreeObject(obj);
7824 ctxt->context->node = NULL;
7825 ctxt->context->contextSize = -1;
7826 ctxt->context->proximityPosition = -1;
7827 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7828 }
7829 ctxt->context->node = oldnode;
7830 return;
7831 }
7832 case XPATH_OP_SORT:
7833 if (op->ch1 != -1)
7834 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7835 if ((ctxt->value != NULL) &&
7836 (ctxt->value->type == XPATH_NODESET) &&
7837 (ctxt->value->nodesetval != NULL))
7838 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7839 return;
7840#ifdef LIBXML_XPTR_ENABLED
7841 case XPATH_OP_RANGETO: {
7842 xmlXPathObjectPtr range;
7843 xmlXPathObjectPtr res, obj;
7844 xmlXPathObjectPtr tmp;
7845 xmlLocationSetPtr newset = NULL;
7846 xmlNodeSetPtr oldset;
7847 int i;
7848
7849 if (op->ch1 != -1)
7850 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7851 if (op->ch2 == -1)
7852 return;
7853
7854 CHECK_TYPE(XPATH_NODESET);
7855 obj = valuePop(ctxt);
7856 oldset = obj->nodesetval;
7857 ctxt->context->node = NULL;
7858
7859 newset = xmlXPtrLocationSetCreate(NULL);
7860
Daniel Veillard911f49a2001-04-07 15:39:35 +00007861 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007862 for (i = 0; i < oldset->nodeNr; i++) {
7863 /*
7864 * Run the evaluation with a node list made of a single item
7865 * in the nodeset.
7866 */
7867 ctxt->context->node = oldset->nodeTab[i];
7868 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7869 valuePush(ctxt, tmp);
7870
7871 if (op->ch2 != -1)
7872 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7873 CHECK_ERROR;
7874
7875 /*
7876 * The result of the evaluation need to be tested to
7877 * decided whether the filter succeeded or not
7878 */
7879 res = valuePop(ctxt);
7880 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7881 if (range != NULL) {
7882 xmlXPtrLocationSetAdd(newset, range);
7883 }
7884
7885 /*
7886 * Cleanup
7887 */
7888 if (res != NULL)
7889 xmlXPathFreeObject(res);
7890 if (ctxt->value == tmp) {
7891 res = valuePop(ctxt);
7892 xmlXPathFreeObject(res);
7893 }
7894
7895 ctxt->context->node = NULL;
7896 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007897 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007898
7899 /*
7900 * The result is used as the new evaluation set.
7901 */
7902 xmlXPathFreeObject(obj);
7903 ctxt->context->node = NULL;
7904 ctxt->context->contextSize = -1;
7905 ctxt->context->proximityPosition = -1;
7906 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7907 return;
7908 }
7909#endif /* LIBXML_XPTR_ENABLED */
7910 }
7911 xmlGenericError(xmlGenericErrorContext,
7912 "XPath: unknown precompiled operation %d\n",
7913 op->op);
7914 return;
7915}
7916
7917/**
7918 * xmlXPathRunEval:
7919 * @ctxt: the XPath parser context with the compiled expression
7920 *
7921 * Evaluate the Precompiled XPath expression in the given context.
7922 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007923static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007924xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7925 xmlXPathCompExprPtr comp;
7926
7927 if ((ctxt == NULL) || (ctxt->comp == NULL))
7928 return;
7929
7930 if (ctxt->valueTab == NULL) {
7931 /* Allocate the value stack */
7932 ctxt->valueTab = (xmlXPathObjectPtr *)
7933 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7934 if (ctxt->valueTab == NULL) {
7935 xmlFree(ctxt);
7936 xmlGenericError(xmlGenericErrorContext,
7937 "xmlXPathRunEval: out of memory\n");
7938 return;
7939 }
7940 ctxt->valueNr = 0;
7941 ctxt->valueMax = 10;
7942 ctxt->value = NULL;
7943 }
7944 comp = ctxt->comp;
7945 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7946}
7947
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007948/************************************************************************
7949 * *
7950 * Public interfaces *
7951 * *
7952 ************************************************************************/
7953
7954/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007955 * xmlXPathEvalPredicate:
7956 * @ctxt: the XPath context
7957 * @res: the Predicate Expression evaluation result
7958 *
7959 * Evaluate a predicate result for the current node.
7960 * A PredicateExpr is evaluated by evaluating the Expr and converting
7961 * the result to a boolean. If the result is a number, the result will
7962 * be converted to true if the number is equal to the position of the
7963 * context node in the context node list (as returned by the position
7964 * function) and will be converted to false otherwise; if the result
7965 * is not a number, then the result will be converted as if by a call
7966 * to the boolean function.
7967 *
7968 * Return 1 if predicate is true, 0 otherwise
7969 */
7970int
7971xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7972 if (res == NULL) return(0);
7973 switch (res->type) {
7974 case XPATH_BOOLEAN:
7975 return(res->boolval);
7976 case XPATH_NUMBER:
7977 return(res->floatval == ctxt->proximityPosition);
7978 case XPATH_NODESET:
7979 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007980 if (res->nodesetval == NULL)
7981 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007982 return(res->nodesetval->nodeNr != 0);
7983 case XPATH_STRING:
7984 return((res->stringval != NULL) &&
7985 (xmlStrlen(res->stringval) != 0));
7986 default:
7987 STRANGE
7988 }
7989 return(0);
7990}
7991
7992/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007993 * xmlXPathEvaluatePredicateResult:
7994 * @ctxt: the XPath Parser context
7995 * @res: the Predicate Expression evaluation result
7996 *
7997 * Evaluate a predicate result for the current node.
7998 * A PredicateExpr is evaluated by evaluating the Expr and converting
7999 * the result to a boolean. If the result is a number, the result will
8000 * be converted to true if the number is equal to the position of the
8001 * context node in the context node list (as returned by the position
8002 * function) and will be converted to false otherwise; if the result
8003 * is not a number, then the result will be converted as if by a call
8004 * to the boolean function.
8005 *
8006 * Return 1 if predicate is true, 0 otherwise
8007 */
8008int
8009xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
8010 xmlXPathObjectPtr res) {
8011 if (res == NULL) return(0);
8012 switch (res->type) {
8013 case XPATH_BOOLEAN:
8014 return(res->boolval);
8015 case XPATH_NUMBER:
8016 return(res->floatval == ctxt->context->proximityPosition);
8017 case XPATH_NODESET:
8018 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00008019 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00008020 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008021 return(res->nodesetval->nodeNr != 0);
8022 case XPATH_STRING:
8023 return((res->stringval != NULL) &&
8024 (xmlStrlen(res->stringval) != 0));
8025 default:
8026 STRANGE
8027 }
8028 return(0);
8029}
8030
8031/**
8032 * xmlXPathCompile:
8033 * @str: the XPath expression
8034 *
8035 * Compile an XPath expression
8036 *
8037 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8038 * the caller has to free the object.
8039 */
8040xmlXPathCompExprPtr
8041xmlXPathCompile(const xmlChar *str) {
8042 xmlXPathParserContextPtr ctxt;
8043 xmlXPathCompExprPtr comp;
8044
8045 xmlXPathInit();
8046
8047 ctxt = xmlXPathNewParserContext(str, NULL);
8048 xmlXPathCompileExpr(ctxt);
8049
Daniel Veillard40af6492001-04-22 08:50:55 +00008050 if (*ctxt->cur != 0) {
8051 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8052 comp = NULL;
8053 } else {
8054 comp = ctxt->comp;
8055 ctxt->comp = NULL;
8056 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008057 xmlXPathFreeParserContext(ctxt);
8058 return(comp);
8059}
8060
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008061/**
8062 * xmlXPathCompiledEval:
8063 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00008064 * @ctx: the XPath context
8065 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008066 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00008067 *
8068 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8069 * the caller has to free the object.
8070 */
8071xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008072xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00008073 xmlXPathParserContextPtr ctxt;
8074 xmlXPathObjectPtr res, tmp, init = NULL;
8075 int stack = 0;
8076
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008077 if ((comp == NULL) || (ctx == NULL))
8078 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008079 xmlXPathInit();
8080
8081 CHECK_CONTEXT(ctx)
8082
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008083 ctxt = xmlXPathCompParserContext(comp, ctx);
8084 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008085
8086 if (ctxt->value == NULL) {
8087 xmlGenericError(xmlGenericErrorContext,
8088 "xmlXPathEval: evaluation failed\n");
8089 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00008090 } else {
8091 res = valuePop(ctxt);
8092 }
8093
8094 do {
8095 tmp = valuePop(ctxt);
8096 if (tmp != NULL) {
8097 if (tmp != init)
8098 stack++;
8099 xmlXPathFreeObject(tmp);
8100 }
8101 } while (tmp != NULL);
8102 if ((stack != 0) && (res != NULL)) {
8103 xmlGenericError(xmlGenericErrorContext,
8104 "xmlXPathEval: %d object left on the stack\n",
8105 stack);
8106 }
8107 if (ctxt->error != XPATH_EXPRESSION_OK) {
8108 xmlXPathFreeObject(res);
8109 res = NULL;
8110 }
8111
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008112
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008113 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008114 xmlXPathFreeParserContext(ctxt);
8115 return(res);
8116}
8117
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008118/**
8119 * xmlXPathEvalExpr:
8120 * @ctxt: the XPath Parser context
8121 *
8122 * Parse and evaluate an XPath expression in the given context,
8123 * then push the result on the context stack
8124 */
8125void
8126xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
8127 xmlXPathCompileExpr(ctxt);
8128 xmlXPathRunEval(ctxt);
8129}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008130
8131/**
8132 * xmlXPathEval:
8133 * @str: the XPath expression
8134 * @ctx: the XPath context
8135 *
8136 * Evaluate the XPath Location Path in the given context.
8137 *
8138 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8139 * the caller has to free the object.
8140 */
8141xmlXPathObjectPtr
8142xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
8143 xmlXPathParserContextPtr ctxt;
8144 xmlXPathObjectPtr res, tmp, init = NULL;
8145 int stack = 0;
8146
8147 xmlXPathInit();
8148
8149 CHECK_CONTEXT(ctx)
8150
8151 ctxt = xmlXPathNewParserContext(str, ctx);
8152 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008153
8154 if (ctxt->value == NULL) {
8155 xmlGenericError(xmlGenericErrorContext,
8156 "xmlXPathEval: evaluation failed\n");
8157 res = NULL;
8158 } else if (*ctxt->cur != 0) {
8159 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8160 res = NULL;
8161 } else {
8162 res = valuePop(ctxt);
8163 }
8164
8165 do {
8166 tmp = valuePop(ctxt);
8167 if (tmp != NULL) {
8168 if (tmp != init)
8169 stack++;
8170 xmlXPathFreeObject(tmp);
8171 }
8172 } while (tmp != NULL);
8173 if ((stack != 0) && (res != NULL)) {
8174 xmlGenericError(xmlGenericErrorContext,
8175 "xmlXPathEval: %d object left on the stack\n",
8176 stack);
8177 }
8178 if (ctxt->error != XPATH_EXPRESSION_OK) {
8179 xmlXPathFreeObject(res);
8180 res = NULL;
8181 }
8182
Owen Taylor3473f882001-02-23 17:55:21 +00008183 xmlXPathFreeParserContext(ctxt);
8184 return(res);
8185}
8186
8187/**
8188 * xmlXPathEvalExpression:
8189 * @str: the XPath expression
8190 * @ctxt: the XPath context
8191 *
8192 * Evaluate the XPath expression in the given context.
8193 *
8194 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
8195 * the caller has to free the object.
8196 */
8197xmlXPathObjectPtr
8198xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
8199 xmlXPathParserContextPtr pctxt;
8200 xmlXPathObjectPtr res, tmp;
8201 int stack = 0;
8202
8203 xmlXPathInit();
8204
8205 CHECK_CONTEXT(ctxt)
8206
8207 pctxt = xmlXPathNewParserContext(str, ctxt);
8208 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008209
8210 if (*pctxt->cur != 0) {
8211 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8212 res = NULL;
8213 } else {
8214 res = valuePop(pctxt);
8215 }
8216 do {
8217 tmp = valuePop(pctxt);
8218 if (tmp != NULL) {
8219 xmlXPathFreeObject(tmp);
8220 stack++;
8221 }
8222 } while (tmp != NULL);
8223 if ((stack != 0) && (res != NULL)) {
8224 xmlGenericError(xmlGenericErrorContext,
8225 "xmlXPathEvalExpression: %d object left on the stack\n",
8226 stack);
8227 }
8228 xmlXPathFreeParserContext(pctxt);
8229 return(res);
8230}
8231
8232/**
8233 * xmlXPathRegisterAllFunctions:
8234 * @ctxt: the XPath context
8235 *
8236 * Registers all default XPath functions in this context
8237 */
8238void
8239xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
8240{
8241 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
8242 xmlXPathBooleanFunction);
8243 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
8244 xmlXPathCeilingFunction);
8245 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
8246 xmlXPathCountFunction);
8247 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
8248 xmlXPathConcatFunction);
8249 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
8250 xmlXPathContainsFunction);
8251 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
8252 xmlXPathIdFunction);
8253 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
8254 xmlXPathFalseFunction);
8255 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
8256 xmlXPathFloorFunction);
8257 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
8258 xmlXPathLastFunction);
8259 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
8260 xmlXPathLangFunction);
8261 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
8262 xmlXPathLocalNameFunction);
8263 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
8264 xmlXPathNotFunction);
8265 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
8266 xmlXPathNameFunction);
8267 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
8268 xmlXPathNamespaceURIFunction);
8269 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
8270 xmlXPathNormalizeFunction);
8271 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
8272 xmlXPathNumberFunction);
8273 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
8274 xmlXPathPositionFunction);
8275 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
8276 xmlXPathRoundFunction);
8277 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
8278 xmlXPathStringFunction);
8279 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
8280 xmlXPathStringLengthFunction);
8281 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
8282 xmlXPathStartsWithFunction);
8283 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
8284 xmlXPathSubstringFunction);
8285 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
8286 xmlXPathSubstringBeforeFunction);
8287 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
8288 xmlXPathSubstringAfterFunction);
8289 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
8290 xmlXPathSumFunction);
8291 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
8292 xmlXPathTrueFunction);
8293 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
8294 xmlXPathTranslateFunction);
8295}
8296
8297#endif /* LIBXML_XPATH_ENABLED */