blob: 57311cd350ec4673ca5d1c41bb103fea639df899 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See COPYRIGHT for the status of this software
12 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020#ifdef LIBXML_XPATH_ENABLED
21
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_MATH_H
28#include <math.h>
29#endif
30#ifdef HAVE_FLOAT_H
31#include <float.h>
32#endif
33#ifdef HAVE_IEEEFP_H
34#include <ieeefp.h>
35#endif
36#ifdef HAVE_NAN_H
37#include <nan.h>
38#endif
39#ifdef HAVE_CTYPE_H
40#include <ctype.h>
41#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000042#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000043#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000044#endif
Owen Taylor3473f882001-02-23 17:55:21 +000045
46#include <libxml/xmlmemory.h>
47#include <libxml/tree.h>
48#include <libxml/valid.h>
49#include <libxml/xpath.h>
50#include <libxml/xpathInternals.h>
51#include <libxml/parserInternals.h>
52#include <libxml/hash.h>
53#ifdef LIBXML_XPTR_ENABLED
54#include <libxml/xpointer.h>
55#endif
56#ifdef LIBXML_DEBUG_ENABLED
57#include <libxml/debugXML.h>
58#endif
59#include <libxml/xmlerror.h>
60
61/* #define DEBUG */
62/* #define DEBUG_STEP */
63/* #define DEBUG_EXPR */
64
65void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
66double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000067double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000068
Daniel Veillard9e7160d2001-03-18 23:17:47 +000069/************************************************************************
70 * *
71 * Floating point stuff *
72 * *
73 ************************************************************************/
74
Owen Taylor3473f882001-02-23 17:55:21 +000075/*
Owen Taylor3473f882001-02-23 17:55:21 +000076 * The lack of portability of this section of the libc is annoying !
77 */
78double xmlXPathNAN = 0;
79double xmlXPathPINF = 1;
80double xmlXPathNINF = -1;
81
82#ifndef isinf
83#ifndef HAVE_ISINF
84
85#if HAVE_FPCLASS
86
87int isinf(double d) {
88 fpclass_t type = fpclass(d);
89 switch (type) {
90 case FP_NINF:
91 return(-1);
92 case FP_PINF:
93 return(1);
94 }
95 return(0);
96}
97
98#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
99
100#if HAVE_FP_CLASS_H
101#include <fp_class.h>
102#endif
103
104int isinf(double d) {
105#if HAVE_FP_CLASS
106 int fpclass = fp_class(d);
107#else
108 int fpclass = fp_class_d(d);
109#endif
110 if (fpclass == FP_POS_INF)
111 return(1);
112 if (fpclass == FP_NEG_INF)
113 return(-1);
114 return(0);
115}
116
117#elif defined(HAVE_CLASS)
118
119int isinf(double d) {
120 int fpclass = class(d);
121 if (fpclass == FP_PLUS_INF)
122 return(1);
123 if (fpclass == FP_MINUS_INF)
124 return(-1);
125 return(0);
126}
127#elif defined(finite) || defined(HAVE_FINITE)
128int isinf(double x) { return !finite(x) && x==x; }
129#elif defined(HUGE_VAL)
130int isinf(double x)
131{
132 if (x == HUGE_VAL)
133 return(1);
134 if (x == -HUGE_VAL)
135 return(-1);
136 return(0);
137}
138#endif
139
140#endif /* ! HAVE_ISINF */
141#endif /* ! defined(isinf) */
142
143#ifndef isnan
144#ifndef HAVE_ISNAN
145
146#ifdef HAVE_ISNAND
147#define isnan(f) isnand(f)
148#endif /* HAVE_iSNAND */
149
150#endif /* ! HAVE_iSNAN */
151#endif /* ! defined(isnan) */
152
Daniel Veillard5792e162001-04-30 17:44:45 +0000153
154/**
155 * xmlXPathDivideBy:
156 *
157 * The best way found so far to generate the NAN, +-INF
158 * without hitting a compiler bug or optimization :-\
159 *
160 * Returns the double resulting from the division
161 */
162double
163xmlXPathDivideBy(double f, double fzero) {
Daniel Veillard81418e32001-05-22 15:08:55 +0000164 double ret;
Daniel Veillard5792e162001-04-30 17:44:45 +0000165#ifdef HAVE_SIGNAL
166#ifdef SIGFPE
167#ifdef SIG_IGN
168 void (*sighandler)(int);
169 sighandler = signal(SIGFPE, SIG_IGN);
170#endif
171#endif
172#endif
173 ret = f / fzero;
174#ifdef HAVE_SIGNAL
175#ifdef SIGFPE
176#ifdef SIG_IGN
177 signal(SIGFPE, sighandler);
178#endif
179#endif
180#endif
181 return(ret);
182}
183
Owen Taylor3473f882001-02-23 17:55:21 +0000184/**
185 * xmlXPathInit:
186 *
187 * Initialize the XPath environment
188 */
189void
190xmlXPathInit(void) {
191 static int initialized = 0;
192
193 if (initialized) return;
194
Daniel Veillard5792e162001-04-30 17:44:45 +0000195 xmlXPathNAN = xmlXPathDivideBy(0.0, 0.0);
196 xmlXPathPINF = xmlXPathDivideBy(1.0, 0.0);
Daniel Veillard541d6552001-06-07 14:20:01 +0000197 xmlXPathNINF = xmlXPathDivideBy(-1.0, 0.0);
Owen Taylor3473f882001-02-23 17:55:21 +0000198
199 initialized = 1;
200}
201
202/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000203 * *
204 * Parser Types *
205 * *
206 ************************************************************************/
207
208/*
209 * Types are private:
210 */
211
212typedef enum {
213 XPATH_OP_END=0,
214 XPATH_OP_AND,
215 XPATH_OP_OR,
216 XPATH_OP_EQUAL,
217 XPATH_OP_CMP,
218 XPATH_OP_PLUS,
219 XPATH_OP_MULT,
220 XPATH_OP_UNION,
221 XPATH_OP_ROOT,
222 XPATH_OP_NODE,
223 XPATH_OP_RESET,
224 XPATH_OP_COLLECT,
225 XPATH_OP_VALUE,
226 XPATH_OP_VARIABLE,
227 XPATH_OP_FUNCTION,
228 XPATH_OP_ARG,
229 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000230 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000231 XPATH_OP_SORT
232#ifdef LIBXML_XPTR_ENABLED
233 ,XPATH_OP_RANGETO
234#endif
235} xmlXPathOp;
236
237typedef enum {
238 AXIS_ANCESTOR = 1,
239 AXIS_ANCESTOR_OR_SELF,
240 AXIS_ATTRIBUTE,
241 AXIS_CHILD,
242 AXIS_DESCENDANT,
243 AXIS_DESCENDANT_OR_SELF,
244 AXIS_FOLLOWING,
245 AXIS_FOLLOWING_SIBLING,
246 AXIS_NAMESPACE,
247 AXIS_PARENT,
248 AXIS_PRECEDING,
249 AXIS_PRECEDING_SIBLING,
250 AXIS_SELF
251} xmlXPathAxisVal;
252
253typedef enum {
254 NODE_TEST_NONE = 0,
255 NODE_TEST_TYPE = 1,
256 NODE_TEST_PI = 2,
257 NODE_TEST_ALL = 3,
258 NODE_TEST_NS = 4,
259 NODE_TEST_NAME = 5
260} xmlXPathTestVal;
261
262typedef enum {
263 NODE_TYPE_NODE = 0,
264 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
265 NODE_TYPE_TEXT = XML_TEXT_NODE,
266 NODE_TYPE_PI = XML_PI_NODE
267} xmlXPathTypeVal;
268
269
270typedef struct _xmlXPathStepOp xmlXPathStepOp;
271typedef xmlXPathStepOp *xmlXPathStepOpPtr;
272struct _xmlXPathStepOp {
273 xmlXPathOp op;
274 int ch1;
275 int ch2;
276 int value;
277 int value2;
278 int value3;
279 void *value4;
280 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000281 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000282 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000283};
284
285struct _xmlXPathCompExpr {
286 int nbStep;
287 int maxStep;
288 xmlXPathStepOp *steps; /* ops for computation */
289 int last;
290};
291
292/************************************************************************
293 * *
294 * Parser Type functions *
295 * *
296 ************************************************************************/
297
298/**
299 * xmlXPathNewCompExpr:
300 *
301 * Create a new Xpath component
302 *
303 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
304 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000305static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000306xmlXPathNewCompExpr(void) {
307 xmlXPathCompExprPtr cur;
308
309 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
310 if (cur == NULL) {
311 xmlGenericError(xmlGenericErrorContext,
312 "xmlXPathNewCompExpr : malloc failed\n");
313 return(NULL);
314 }
315 memset(cur, 0, sizeof(xmlXPathCompExpr));
316 cur->maxStep = 10;
317 cur->nbStep = 0;
318 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
319 sizeof(xmlXPathStepOp));
320 if (cur->steps == NULL) {
321 xmlGenericError(xmlGenericErrorContext,
322 "xmlXPathNewCompExpr : malloc failed\n");
323 xmlFree(cur);
324 return(NULL);
325 }
326 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
327 cur->last = -1;
328 return(cur);
329}
330
331/**
332 * xmlXPathFreeCompExpr:
333 * @comp: an XPATH comp
334 *
335 * Free up the memory allocated by @comp
336 */
337void
338xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) {
339 xmlXPathStepOpPtr op;
340 int i;
341
342 if (comp == NULL)
343 return;
344 for (i = 0;i < comp->nbStep;i++) {
345 op = &comp->steps[i];
346 if (op->value4 != NULL) {
347 if (op->op == XPATH_OP_VALUE)
348 xmlXPathFreeObject(op->value4);
349 else
350 xmlFree(op->value4);
351 }
352 if (op->value5 != NULL)
353 xmlFree(op->value5);
354 }
355 if (comp->steps != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000356 xmlFree(comp->steps);
357 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000358 xmlFree(comp);
359}
360
361/**
362 * xmlXPathCompExprAdd:
363 * @comp: the compiled expression
364 * @ch1: first child index
365 * @ch2: second child index
366 * @op: an op
367 * @value: the first int value
368 * @value2: the second int value
369 * @value3: the third int value
370 * @value4: the first string value
371 * @value5: the second string value
372 *
373 * Add an step to an XPath Compiled Expression
374 *
375 * Returns -1 in case of failure, the index otherwise
376 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000377static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000378xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
379 xmlXPathOp op, int value,
380 int value2, int value3, void *value4, void *value5) {
381 if (comp->nbStep >= comp->maxStep) {
382 xmlXPathStepOp *real;
383
384 comp->maxStep *= 2;
385 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
386 comp->maxStep * sizeof(xmlXPathStepOp));
387 if (real == NULL) {
388 comp->maxStep /= 2;
389 xmlGenericError(xmlGenericErrorContext,
390 "xmlXPathCompExprAdd : realloc failed\n");
391 return(-1);
392 }
393 comp->steps = real;
394 }
395 comp->last = comp->nbStep;
396 comp->steps[comp->nbStep].ch1 = ch1;
397 comp->steps[comp->nbStep].ch2 = ch2;
398 comp->steps[comp->nbStep].op = op;
399 comp->steps[comp->nbStep].value = value;
400 comp->steps[comp->nbStep].value2 = value2;
401 comp->steps[comp->nbStep].value3 = value3;
402 comp->steps[comp->nbStep].value4 = value4;
403 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000404 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000405 return(comp->nbStep++);
406}
407
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000408#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
409 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
410 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000411#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
412 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
413 (op), (val), (val2), (val3), (val4), (val5))
414
415#define PUSH_LEAVE_EXPR(op, val, val2) \
416xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
417
418#define PUSH_UNARY_EXPR(op, ch, val, val2) \
419xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
420
421#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
422xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
423
424/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000425 * *
426 * Debugging related functions *
427 * *
428 ************************************************************************/
429
430#define TODO \
431 xmlGenericError(xmlGenericErrorContext, \
432 "Unimplemented block at %s:%d\n", \
433 __FILE__, __LINE__);
434
435#define STRANGE \
436 xmlGenericError(xmlGenericErrorContext, \
437 "Internal error at %s:%d\n", \
438 __FILE__, __LINE__);
439
440#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000441static void
442xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000443 int i;
444 char shift[100];
445
446 for (i = 0;((i < depth) && (i < 25));i++)
447 shift[2 * i] = shift[2 * i + 1] = ' ';
448 shift[2 * i] = shift[2 * i + 1] = 0;
449 if (cur == NULL) {
450 fprintf(output, shift);
451 fprintf(output, "Node is NULL !\n");
452 return;
453
454 }
455
456 if ((cur->type == XML_DOCUMENT_NODE) ||
457 (cur->type == XML_HTML_DOCUMENT_NODE)) {
458 fprintf(output, shift);
459 fprintf(output, " /\n");
460 } else if (cur->type == XML_ATTRIBUTE_NODE)
461 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
462 else
463 xmlDebugDumpOneNode(output, cur, depth);
464}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000465static void
466xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000467 xmlNodePtr tmp;
468 int i;
469 char shift[100];
470
471 for (i = 0;((i < depth) && (i < 25));i++)
472 shift[2 * i] = shift[2 * i + 1] = ' ';
473 shift[2 * i] = shift[2 * i + 1] = 0;
474 if (cur == NULL) {
475 fprintf(output, shift);
476 fprintf(output, "Node is NULL !\n");
477 return;
478
479 }
480
481 while (cur != NULL) {
482 tmp = cur;
483 cur = cur->next;
484 xmlDebugDumpOneNode(output, tmp, depth);
485 }
486}
Owen Taylor3473f882001-02-23 17:55:21 +0000487
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000488static void
489xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000490 int i;
491 char shift[100];
492
493 for (i = 0;((i < depth) && (i < 25));i++)
494 shift[2 * i] = shift[2 * i + 1] = ' ';
495 shift[2 * i] = shift[2 * i + 1] = 0;
496
497 if (cur == NULL) {
498 fprintf(output, shift);
499 fprintf(output, "NodeSet is NULL !\n");
500 return;
501
502 }
503
Daniel Veillard911f49a2001-04-07 15:39:35 +0000504 if (cur != NULL) {
505 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
506 for (i = 0;i < cur->nodeNr;i++) {
507 fprintf(output, shift);
508 fprintf(output, "%d", i + 1);
509 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
510 }
Owen Taylor3473f882001-02-23 17:55:21 +0000511 }
512}
513
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000514static void
515xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000516 int i;
517 char shift[100];
518
519 for (i = 0;((i < depth) && (i < 25));i++)
520 shift[2 * i] = shift[2 * i + 1] = ' ';
521 shift[2 * i] = shift[2 * i + 1] = 0;
522
523 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
524 fprintf(output, shift);
525 fprintf(output, "Value Tree is NULL !\n");
526 return;
527
528 }
529
530 fprintf(output, shift);
531 fprintf(output, "%d", i + 1);
532 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
533}
Owen Taylor3473f882001-02-23 17:55:21 +0000534#if defined(LIBXML_XPTR_ENABLED)
535void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000536static void
537xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000538 int i;
539 char shift[100];
540
541 for (i = 0;((i < depth) && (i < 25));i++)
542 shift[2 * i] = shift[2 * i + 1] = ' ';
543 shift[2 * i] = shift[2 * i + 1] = 0;
544
545 if (cur == NULL) {
546 fprintf(output, shift);
547 fprintf(output, "LocationSet is NULL !\n");
548 return;
549
550 }
551
552 for (i = 0;i < cur->locNr;i++) {
553 fprintf(output, shift);
554 fprintf(output, "%d : ", i + 1);
555 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
556 }
557}
Daniel Veillard017b1082001-06-21 11:20:21 +0000558#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000559
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000560/**
561 * xmlXPathDebugDumpObject:
562 * @output: the FILE * to dump the output
563 * @cur: the object to inspect
564 * @depth: indentation level
565 *
566 * Dump the content of the object for debugging purposes
567 */
568void
569xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000570 int i;
571 char shift[100];
572
573 for (i = 0;((i < depth) && (i < 25));i++)
574 shift[2 * i] = shift[2 * i + 1] = ' ';
575 shift[2 * i] = shift[2 * i + 1] = 0;
576
577 fprintf(output, shift);
578
579 if (cur == NULL) {
580 fprintf(output, "Object is empty (NULL)\n");
581 return;
582 }
583 switch(cur->type) {
584 case XPATH_UNDEFINED:
585 fprintf(output, "Object is uninitialized\n");
586 break;
587 case XPATH_NODESET:
588 fprintf(output, "Object is a Node Set :\n");
589 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
590 break;
591 case XPATH_XSLT_TREE:
592 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000593 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000594 break;
595 case XPATH_BOOLEAN:
596 fprintf(output, "Object is a Boolean : ");
597 if (cur->boolval) fprintf(output, "true\n");
598 else fprintf(output, "false\n");
599 break;
600 case XPATH_NUMBER:
Daniel Veillard357c9602001-05-03 10:49:20 +0000601 switch (isinf(cur->floatval)) {
602 case 1:
603 fprintf(output, "Object is a number : +Infinity\n");
604 break;
605 case -1:
606 fprintf(output, "Object is a number : -Infinity\n");
607 break;
608 default:
609 if (isnan(cur->floatval)) {
610 fprintf(output, "Object is a number : NaN\n");
611 } else {
612 fprintf(output, "Object is a number : %0g\n", cur->floatval);
613 }
614 }
Owen Taylor3473f882001-02-23 17:55:21 +0000615 break;
616 case XPATH_STRING:
617 fprintf(output, "Object is a string : ");
618 xmlDebugDumpString(output, cur->stringval);
619 fprintf(output, "\n");
620 break;
621 case XPATH_POINT:
622 fprintf(output, "Object is a point : index %d in node", cur->index);
623 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
624 fprintf(output, "\n");
625 break;
626 case XPATH_RANGE:
627 if ((cur->user2 == NULL) ||
628 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
629 fprintf(output, "Object is a collapsed range :\n");
630 fprintf(output, shift);
631 if (cur->index >= 0)
632 fprintf(output, "index %d in ", cur->index);
633 fprintf(output, "node\n");
634 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
635 depth + 1);
636 } else {
637 fprintf(output, "Object is a range :\n");
638 fprintf(output, shift);
639 fprintf(output, "From ");
640 if (cur->index >= 0)
641 fprintf(output, "index %d in ", cur->index);
642 fprintf(output, "node\n");
643 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
644 depth + 1);
645 fprintf(output, shift);
646 fprintf(output, "To ");
647 if (cur->index2 >= 0)
648 fprintf(output, "index %d in ", cur->index2);
649 fprintf(output, "node\n");
650 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
651 depth + 1);
652 fprintf(output, "\n");
653 }
654 break;
655 case XPATH_LOCATIONSET:
656#if defined(LIBXML_XPTR_ENABLED)
657 fprintf(output, "Object is a Location Set:\n");
658 xmlXPathDebugDumpLocationSet(output,
659 (xmlLocationSetPtr) cur->user, depth);
660#endif
661 break;
662 case XPATH_USERS:
663 fprintf(output, "Object is user defined\n");
664 break;
665 }
666}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000667
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000668static void
669xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000670 xmlXPathStepOpPtr op, int depth) {
671 int i;
672 char shift[100];
673
674 for (i = 0;((i < depth) && (i < 25));i++)
675 shift[2 * i] = shift[2 * i + 1] = ' ';
676 shift[2 * i] = shift[2 * i + 1] = 0;
677
678 fprintf(output, shift);
679 if (op == NULL) {
680 fprintf(output, "Step is NULL\n");
681 return;
682 }
683 switch (op->op) {
684 case XPATH_OP_END:
685 fprintf(output, "END"); break;
686 case XPATH_OP_AND:
687 fprintf(output, "AND"); break;
688 case XPATH_OP_OR:
689 fprintf(output, "OR"); break;
690 case XPATH_OP_EQUAL:
691 if (op->value)
692 fprintf(output, "EQUAL =");
693 else
694 fprintf(output, "EQUAL !=");
695 break;
696 case XPATH_OP_CMP:
697 if (op->value)
698 fprintf(output, "CMP <");
699 else
700 fprintf(output, "CMP >");
701 if (!op->value2)
702 fprintf(output, "=");
703 break;
704 case XPATH_OP_PLUS:
705 if (op->value == 0)
706 fprintf(output, "PLUS -");
707 else if (op->value == 1)
708 fprintf(output, "PLUS +");
709 else if (op->value == 2)
710 fprintf(output, "PLUS unary -");
711 else if (op->value == 3)
712 fprintf(output, "PLUS unary - -");
713 break;
714 case XPATH_OP_MULT:
715 if (op->value == 0)
716 fprintf(output, "MULT *");
717 else if (op->value == 1)
718 fprintf(output, "MULT div");
719 else
720 fprintf(output, "MULT mod");
721 break;
722 case XPATH_OP_UNION:
723 fprintf(output, "UNION"); break;
724 case XPATH_OP_ROOT:
725 fprintf(output, "ROOT"); break;
726 case XPATH_OP_NODE:
727 fprintf(output, "NODE"); break;
728 case XPATH_OP_RESET:
729 fprintf(output, "RESET"); break;
730 case XPATH_OP_SORT:
731 fprintf(output, "SORT"); break;
732 case XPATH_OP_COLLECT: {
733 xmlXPathAxisVal axis = op->value;
734 xmlXPathTestVal test = op->value2;
735 xmlXPathTypeVal type = op->value3;
736 const xmlChar *prefix = op->value4;
737 const xmlChar *name = op->value5;
738
739 fprintf(output, "COLLECT ");
740 switch (axis) {
741 case AXIS_ANCESTOR:
742 fprintf(output, " 'ancestors' "); break;
743 case AXIS_ANCESTOR_OR_SELF:
744 fprintf(output, " 'ancestors-or-self' "); break;
745 case AXIS_ATTRIBUTE:
746 fprintf(output, " 'attributes' "); break;
747 case AXIS_CHILD:
748 fprintf(output, " 'child' "); break;
749 case AXIS_DESCENDANT:
750 fprintf(output, " 'descendant' "); break;
751 case AXIS_DESCENDANT_OR_SELF:
752 fprintf(output, " 'descendant-or-self' "); break;
753 case AXIS_FOLLOWING:
754 fprintf(output, " 'following' "); break;
755 case AXIS_FOLLOWING_SIBLING:
756 fprintf(output, " 'following-siblings' "); break;
757 case AXIS_NAMESPACE:
758 fprintf(output, " 'namespace' "); break;
759 case AXIS_PARENT:
760 fprintf(output, " 'parent' "); break;
761 case AXIS_PRECEDING:
762 fprintf(output, " 'preceding' "); break;
763 case AXIS_PRECEDING_SIBLING:
764 fprintf(output, " 'preceding-sibling' "); break;
765 case AXIS_SELF:
766 fprintf(output, " 'self' "); break;
767 }
768 switch (test) {
769 case NODE_TEST_NONE:
770 fprintf(output, "'none' "); break;
771 case NODE_TEST_TYPE:
772 fprintf(output, "'type' "); break;
773 case NODE_TEST_PI:
774 fprintf(output, "'PI' "); break;
775 case NODE_TEST_ALL:
776 fprintf(output, "'all' "); break;
777 case NODE_TEST_NS:
778 fprintf(output, "'namespace' "); break;
779 case NODE_TEST_NAME:
780 fprintf(output, "'name' "); break;
781 }
782 switch (type) {
783 case NODE_TYPE_NODE:
784 fprintf(output, "'node' "); break;
785 case NODE_TYPE_COMMENT:
786 fprintf(output, "'comment' "); break;
787 case NODE_TYPE_TEXT:
788 fprintf(output, "'text' "); break;
789 case NODE_TYPE_PI:
790 fprintf(output, "'PI' "); break;
791 }
792 if (prefix != NULL)
793 fprintf(output, "%s:", prefix);
794 if (name != NULL)
795 fprintf(output, "%s", name);
796 break;
797
798 }
799 case XPATH_OP_VALUE: {
800 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
801
802 fprintf(output, "ELEM ");
803 xmlXPathDebugDumpObject(output, object, 0);
804 goto finish;
805 }
806 case XPATH_OP_VARIABLE: {
807 const xmlChar *prefix = op->value5;
808 const xmlChar *name = op->value4;
809
810 if (prefix != NULL)
811 fprintf(output, "VARIABLE %s:%s", prefix, name);
812 else
813 fprintf(output, "VARIABLE %s", name);
814 break;
815 }
816 case XPATH_OP_FUNCTION: {
817 int nbargs = op->value;
818 const xmlChar *prefix = op->value5;
819 const xmlChar *name = op->value4;
820
821 if (prefix != NULL)
822 fprintf(output, "FUNCTION %s:%s(%d args)",
823 prefix, name, nbargs);
824 else
825 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
826 break;
827 }
828 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
829 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000830 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000831#ifdef LIBXML_XPTR_ENABLED
832 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
833#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000834 default:
835 fprintf(output, "UNKNOWN %d\n", op->op); return;
836 }
837 fprintf(output, "\n");
838finish:
839 if (op->ch1 >= 0)
840 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
841 if (op->ch2 >= 0)
842 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
843}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000844
845void
846xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
847 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000848 int i;
849 char shift[100];
850
851 for (i = 0;((i < depth) && (i < 25));i++)
852 shift[2 * i] = shift[2 * i + 1] = ' ';
853 shift[2 * i] = shift[2 * i + 1] = 0;
854
855 fprintf(output, shift);
856
857 if (comp == NULL) {
858 fprintf(output, "Compiled Expression is NULL\n");
859 return;
860 }
861 fprintf(output, "Compiled Expression : %d elements\n",
862 comp->nbStep);
863 i = comp->last;
864 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
865}
Daniel Veillard017b1082001-06-21 11:20:21 +0000866#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000867
868/************************************************************************
869 * *
870 * Parser stacks related functions and macros *
871 * *
872 ************************************************************************/
873
874/*
875 * Generic function for accessing stacks in the Parser Context
876 */
877
878#define PUSH_AND_POP(type, name) \
879extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
880 if (ctxt->name##Nr >= ctxt->name##Max) { \
881 ctxt->name##Max *= 2; \
882 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
883 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
884 if (ctxt->name##Tab == NULL) { \
885 xmlGenericError(xmlGenericErrorContext, \
886 "realloc failed !\n"); \
887 return(0); \
888 } \
889 } \
890 ctxt->name##Tab[ctxt->name##Nr] = value; \
891 ctxt->name = value; \
892 return(ctxt->name##Nr++); \
893} \
894extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
895 type ret; \
896 if (ctxt->name##Nr <= 0) return(0); \
897 ctxt->name##Nr--; \
898 if (ctxt->name##Nr > 0) \
899 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
900 else \
901 ctxt->name = NULL; \
902 ret = ctxt->name##Tab[ctxt->name##Nr]; \
903 ctxt->name##Tab[ctxt->name##Nr] = 0; \
904 return(ret); \
905} \
906
907PUSH_AND_POP(xmlXPathObjectPtr, value)
908
909/*
910 * Macros for accessing the content. Those should be used only by the parser,
911 * and not exported.
912 *
913 * Dirty macros, i.e. one need to make assumption on the context to use them
914 *
915 * CUR_PTR return the current pointer to the xmlChar to be parsed.
916 * CUR returns the current xmlChar value, i.e. a 8 bit value
917 * in ISO-Latin or UTF-8.
918 * This should be used internally by the parser
919 * only to compare to ASCII values otherwise it would break when
920 * running with UTF-8 encoding.
921 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
922 * to compare on ASCII based substring.
923 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
924 * strings within the parser.
925 * CURRENT Returns the current char value, with the full decoding of
926 * UTF-8 if we are using this mode. It returns an int.
927 * NEXT Skip to the next character, this does the proper decoding
928 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
929 * It returns the pointer to the current xmlChar.
930 */
931
932#define CUR (*ctxt->cur)
933#define SKIP(val) ctxt->cur += (val)
934#define NXT(val) ctxt->cur[(val)]
935#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +0000936#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
937
938#define COPY_BUF(l,b,i,v) \
939 if (l == 1) b[i++] = (xmlChar) v; \
940 else i += xmlCopyChar(l,&b[i],v)
941
942#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +0000943
944#define SKIP_BLANKS \
945 while (IS_BLANK(*(ctxt->cur))) NEXT
946
947#define CURRENT (*ctxt->cur)
948#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
949
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000950
951#ifndef DBL_DIG
952#define DBL_DIG 16
953#endif
954#ifndef DBL_EPSILON
955#define DBL_EPSILON 1E-9
956#endif
957
958#define UPPER_DOUBLE 1E9
959#define LOWER_DOUBLE 1E-5
960
961#define INTEGER_DIGITS DBL_DIG
962#define FRACTION_DIGITS (DBL_DIG + 1)
963#define EXPONENT_DIGITS (3 + 2)
964
965/**
966 * xmlXPathFormatNumber:
967 * @number: number to format
968 * @buffer: output buffer
969 * @buffersize: size of output buffer
970 *
971 * Convert the number into a string representation.
972 */
973static void
974xmlXPathFormatNumber(double number, char buffer[], int buffersize)
975{
976 switch (isinf(number)) {
977 case 1:
978 if (buffersize > (int)sizeof("+Infinity"))
979 sprintf(buffer, "+Infinity");
980 break;
981 case -1:
982 if (buffersize > (int)sizeof("-Infinity"))
983 sprintf(buffer, "-Infinity");
984 break;
985 default:
986 if (isnan(number)) {
987 if (buffersize > (int)sizeof("NaN"))
988 sprintf(buffer, "NaN");
989 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000990 /* 3 is sign, decimal point, and terminating zero */
991 char work[DBL_DIG + EXPONENT_DIGITS + 3];
992 int integer_place, fraction_place;
993 char *ptr;
994 char *after_fraction;
995 double absolute_value;
996 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000997
Bjorn Reese70a9da52001-04-21 16:57:29 +0000998 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000999
Bjorn Reese70a9da52001-04-21 16:57:29 +00001000 /*
1001 * First choose format - scientific or regular floating point.
1002 * In either case, result is in work, and after_fraction points
1003 * just past the fractional part.
1004 */
1005 if ( ((absolute_value > UPPER_DOUBLE) ||
1006 (absolute_value < LOWER_DOUBLE)) &&
1007 (absolute_value != 0.0) ) {
1008 /* Use scientific notation */
1009 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1010 fraction_place = DBL_DIG - 1;
1011 snprintf(work, sizeof(work),"%*.*e",
1012 integer_place, fraction_place, number);
1013 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001014 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001015 else {
1016 /* Use regular notation */
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;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005734 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005735 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 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005747 /*
5748 * tmp is a workaroudn against a gcc compiler bug
5749 */
Owen Taylor3473f882001-02-23 17:55:21 +00005750 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005751 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00005752 ok = 1;
5753 cur++;
5754 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005755 ret = (double) tmp;
5756
Owen Taylor3473f882001-02-23 17:55:21 +00005757 if (*cur == '.') {
5758 cur++;
5759 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5760 return(xmlXPathNAN);
5761 }
5762 while ((*cur >= '0') && (*cur <= '9')) {
5763 mult /= 10;
5764 ret = ret + (*cur - '0') * mult;
5765 cur++;
5766 }
5767 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005768 if ((*cur == 'e') || (*cur == 'E')) {
5769 cur++;
5770 if (*cur == '-') {
5771 is_exponent_negative = 1;
5772 cur++;
5773 }
5774 while ((*cur >= '0') && (*cur <= '9')) {
5775 exponent = exponent * 10 + (*cur - '0');
5776 cur++;
5777 }
5778 }
Owen Taylor3473f882001-02-23 17:55:21 +00005779 while (IS_BLANK(*cur)) cur++;
5780 if (*cur != 0) return(xmlXPathNAN);
5781 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005782 if (is_exponent_negative) exponent = -exponent;
5783 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005784 return(ret);
5785}
5786
5787/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005788 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005789 * @ctxt: the XPath Parser context
5790 *
5791 * [30] Number ::= Digits ('.' Digits?)?
5792 * | '.' Digits
5793 * [31] Digits ::= [0-9]+
5794 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005795 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005796 *
5797 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005798static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005799xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
5800{
Owen Taylor3473f882001-02-23 17:55:21 +00005801 double ret = 0.0;
5802 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005803 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005804 int exponent = 0;
5805 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005806
5807 CHECK_ERROR;
5808 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5809 XP_ERROR(XPATH_NUMBER_ERROR);
5810 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005811 /*
5812 * Try to work around a gcc optimizer bug
5813 */
Owen Taylor3473f882001-02-23 17:55:21 +00005814 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005815 tmp = tmp * 10 + (CUR - '0');
5816 ok = 1;
5817 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00005818 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005819 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005820 if (CUR == '.') {
5821 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005822 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5823 XP_ERROR(XPATH_NUMBER_ERROR);
5824 }
5825 while ((CUR >= '0') && (CUR <= '9')) {
5826 mult /= 10;
5827 ret = ret + (CUR - '0') * mult;
5828 NEXT;
5829 }
Owen Taylor3473f882001-02-23 17:55:21 +00005830 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005831 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005832 NEXT;
5833 if (CUR == '-') {
5834 is_exponent_negative = 1;
5835 NEXT;
5836 }
5837 while ((CUR >= '0') && (CUR <= '9')) {
5838 exponent = exponent * 10 + (CUR - '0');
5839 NEXT;
5840 }
5841 if (is_exponent_negative)
5842 exponent = -exponent;
5843 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005844 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005845 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005846 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005847}
5848
5849/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005850 * xmlXPathParseLiteral:
5851 * @ctxt: the XPath Parser context
5852 *
5853 * Parse a Literal
5854 *
5855 * [29] Literal ::= '"' [^"]* '"'
5856 * | "'" [^']* "'"
5857 *
5858 * Returns the value found or NULL in case of error
5859 */
5860static xmlChar *
5861xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5862 const xmlChar *q;
5863 xmlChar *ret = NULL;
5864
5865 if (CUR == '"') {
5866 NEXT;
5867 q = CUR_PTR;
5868 while ((IS_CHAR(CUR)) && (CUR != '"'))
5869 NEXT;
5870 if (!IS_CHAR(CUR)) {
5871 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5872 } else {
5873 ret = xmlStrndup(q, CUR_PTR - q);
5874 NEXT;
5875 }
5876 } else if (CUR == '\'') {
5877 NEXT;
5878 q = CUR_PTR;
5879 while ((IS_CHAR(CUR)) && (CUR != '\''))
5880 NEXT;
5881 if (!IS_CHAR(CUR)) {
5882 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5883 } else {
5884 ret = xmlStrndup(q, CUR_PTR - q);
5885 NEXT;
5886 }
5887 } else {
5888 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5889 }
5890 return(ret);
5891}
5892
5893/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005894 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005895 * @ctxt: the XPath Parser context
5896 *
5897 * Parse a Literal and push it on the stack.
5898 *
5899 * [29] Literal ::= '"' [^"]* '"'
5900 * | "'" [^']* "'"
5901 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005902 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005903 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005904static void
5905xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005906 const xmlChar *q;
5907 xmlChar *ret = NULL;
5908
5909 if (CUR == '"') {
5910 NEXT;
5911 q = CUR_PTR;
5912 while ((IS_CHAR(CUR)) && (CUR != '"'))
5913 NEXT;
5914 if (!IS_CHAR(CUR)) {
5915 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5916 } else {
5917 ret = xmlStrndup(q, CUR_PTR - q);
5918 NEXT;
5919 }
5920 } else if (CUR == '\'') {
5921 NEXT;
5922 q = CUR_PTR;
5923 while ((IS_CHAR(CUR)) && (CUR != '\''))
5924 NEXT;
5925 if (!IS_CHAR(CUR)) {
5926 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5927 } else {
5928 ret = xmlStrndup(q, CUR_PTR - q);
5929 NEXT;
5930 }
5931 } else {
5932 XP_ERROR(XPATH_START_LITERAL_ERROR);
5933 }
5934 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005935 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5936 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005937 xmlFree(ret);
5938}
5939
5940/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005941 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005942 * @ctxt: the XPath Parser context
5943 *
5944 * Parse a VariableReference, evaluate it and push it on the stack.
5945 *
5946 * The variable bindings consist of a mapping from variable names
5947 * to variable values. The value of a variable is an object, which
5948 * of any of the types that are possible for the value of an expression,
5949 * and may also be of additional types not specified here.
5950 *
5951 * Early evaluation is possible since:
5952 * The variable bindings [...] used to evaluate a subexpression are
5953 * always the same as those used to evaluate the containing expression.
5954 *
5955 * [36] VariableReference ::= '$' QName
5956 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005957static void
5958xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005959 xmlChar *name;
5960 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005961
5962 SKIP_BLANKS;
5963 if (CUR != '$') {
5964 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5965 }
5966 NEXT;
5967 name = xmlXPathParseQName(ctxt, &prefix);
5968 if (name == NULL) {
5969 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5970 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005971 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005972 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5973 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005974 SKIP_BLANKS;
5975}
5976
5977/**
5978 * xmlXPathIsNodeType:
5979 * @ctxt: the XPath Parser context
5980 * @name: a name string
5981 *
5982 * Is the name given a NodeType one.
5983 *
5984 * [38] NodeType ::= 'comment'
5985 * | 'text'
5986 * | 'processing-instruction'
5987 * | 'node'
5988 *
5989 * Returns 1 if true 0 otherwise
5990 */
5991int
5992xmlXPathIsNodeType(const xmlChar *name) {
5993 if (name == NULL)
5994 return(0);
5995
5996 if (xmlStrEqual(name, BAD_CAST "comment"))
5997 return(1);
5998 if (xmlStrEqual(name, BAD_CAST "text"))
5999 return(1);
6000 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6001 return(1);
6002 if (xmlStrEqual(name, BAD_CAST "node"))
6003 return(1);
6004 return(0);
6005}
6006
6007/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006008 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006009 * @ctxt: the XPath Parser context
6010 *
6011 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6012 * [17] Argument ::= Expr
6013 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006014 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006015 * pushed on the stack
6016 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006017static void
6018xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006019 xmlChar *name;
6020 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006021 int nbargs = 0;
6022
6023 name = xmlXPathParseQName(ctxt, &prefix);
6024 if (name == NULL) {
6025 XP_ERROR(XPATH_EXPR_ERROR);
6026 }
6027 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006028#ifdef DEBUG_EXPR
6029 if (prefix == NULL)
6030 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6031 name);
6032 else
6033 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6034 prefix, name);
6035#endif
6036
Owen Taylor3473f882001-02-23 17:55:21 +00006037 if (CUR != '(') {
6038 XP_ERROR(XPATH_EXPR_ERROR);
6039 }
6040 NEXT;
6041 SKIP_BLANKS;
6042
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006043 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006044 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006045 int op1 = ctxt->comp->last;
6046 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006047 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006048 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006049 nbargs++;
6050 if (CUR == ')') break;
6051 if (CUR != ',') {
6052 XP_ERROR(XPATH_EXPR_ERROR);
6053 }
6054 NEXT;
6055 SKIP_BLANKS;
6056 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006057 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6058 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006059 NEXT;
6060 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006061}
6062
6063/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006064 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006065 * @ctxt: the XPath Parser context
6066 *
6067 * [15] PrimaryExpr ::= VariableReference
6068 * | '(' Expr ')'
6069 * | Literal
6070 * | Number
6071 * | FunctionCall
6072 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006073 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006074 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006075static void
6076xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006077 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006078 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006079 else if (CUR == '(') {
6080 NEXT;
6081 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006082 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006083 if (CUR != ')') {
6084 XP_ERROR(XPATH_EXPR_ERROR);
6085 }
6086 NEXT;
6087 SKIP_BLANKS;
6088 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006089 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006090 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006091 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006092 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006093 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006094 }
6095 SKIP_BLANKS;
6096}
6097
6098/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006099 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006100 * @ctxt: the XPath Parser context
6101 *
6102 * [20] FilterExpr ::= PrimaryExpr
6103 * | FilterExpr Predicate
6104 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006105 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006106 * Square brackets are used to filter expressions in the same way that
6107 * they are used in location paths. It is an error if the expression to
6108 * be filtered does not evaluate to a node-set. The context node list
6109 * used for evaluating the expression in square brackets is the node-set
6110 * to be filtered listed in document order.
6111 */
6112
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006113static void
6114xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6115 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006116 CHECK_ERROR;
6117 SKIP_BLANKS;
6118
6119 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006120 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006121 SKIP_BLANKS;
6122 }
6123
6124
6125}
6126
6127/**
6128 * xmlXPathScanName:
6129 * @ctxt: the XPath Parser context
6130 *
6131 * Trickery: parse an XML name but without consuming the input flow
6132 * Needed to avoid insanity in the parser state.
6133 *
6134 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6135 * CombiningChar | Extender
6136 *
6137 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6138 *
6139 * [6] Names ::= Name (S Name)*
6140 *
6141 * Returns the Name parsed or NULL
6142 */
6143
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006144static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006145xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6146 xmlChar buf[XML_MAX_NAMELEN];
6147 int len = 0;
6148
6149 SKIP_BLANKS;
6150 if (!IS_LETTER(CUR) && (CUR != '_') &&
6151 (CUR != ':')) {
6152 return(NULL);
6153 }
6154
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 buf[len] = NXT(len);
6161 len++;
6162 if (len >= XML_MAX_NAMELEN) {
6163 xmlGenericError(xmlGenericErrorContext,
6164 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6165 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6166 (NXT(len) == '.') || (NXT(len) == '-') ||
6167 (NXT(len) == '_') || (NXT(len) == ':') ||
6168 (IS_COMBINING(NXT(len))) ||
6169 (IS_EXTENDER(NXT(len))))
6170 len++;
6171 break;
6172 }
6173 }
6174 return(xmlStrndup(buf, len));
6175}
6176
6177/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006178 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006179 * @ctxt: the XPath Parser context
6180 *
6181 * [19] PathExpr ::= LocationPath
6182 * | FilterExpr
6183 * | FilterExpr '/' RelativeLocationPath
6184 * | FilterExpr '//' RelativeLocationPath
6185 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006186 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006187 * The / operator and // operators combine an arbitrary expression
6188 * and a relative location path. It is an error if the expression
6189 * does not evaluate to a node-set.
6190 * The / operator does composition in the same way as when / is
6191 * used in a location path. As in location paths, // is short for
6192 * /descendant-or-self::node()/.
6193 */
6194
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006195static void
6196xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006197 int lc = 1; /* Should we branch to LocationPath ? */
6198 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6199
6200 SKIP_BLANKS;
6201 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6202 (CUR == '\'') || (CUR == '"')) {
6203 lc = 0;
6204 } else if (CUR == '*') {
6205 /* relative or absolute location path */
6206 lc = 1;
6207 } else if (CUR == '/') {
6208 /* relative or absolute location path */
6209 lc = 1;
6210 } else if (CUR == '@') {
6211 /* relative abbreviated attribute location path */
6212 lc = 1;
6213 } else if (CUR == '.') {
6214 /* relative abbreviated attribute location path */
6215 lc = 1;
6216 } else {
6217 /*
6218 * Problem is finding if we have a name here whether it's:
6219 * - a nodetype
6220 * - a function call in which case it's followed by '('
6221 * - an axis in which case it's followed by ':'
6222 * - a element name
6223 * We do an a priori analysis here rather than having to
6224 * maintain parsed token content through the recursive function
6225 * calls. This looks uglier but makes the code quite easier to
6226 * read/write/debug.
6227 */
6228 SKIP_BLANKS;
6229 name = xmlXPathScanName(ctxt);
6230 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6231#ifdef DEBUG_STEP
6232 xmlGenericError(xmlGenericErrorContext,
6233 "PathExpr: Axis\n");
6234#endif
6235 lc = 1;
6236 xmlFree(name);
6237 } else if (name != NULL) {
6238 int len =xmlStrlen(name);
6239 int blank = 0;
6240
6241
6242 while (NXT(len) != 0) {
6243 if (NXT(len) == '/') {
6244 /* element name */
6245#ifdef DEBUG_STEP
6246 xmlGenericError(xmlGenericErrorContext,
6247 "PathExpr: AbbrRelLocation\n");
6248#endif
6249 lc = 1;
6250 break;
6251 } else if (IS_BLANK(NXT(len))) {
6252 /* skip to next */
6253 blank = 1;
6254 } else if (NXT(len) == ':') {
6255#ifdef DEBUG_STEP
6256 xmlGenericError(xmlGenericErrorContext,
6257 "PathExpr: AbbrRelLocation\n");
6258#endif
6259 lc = 1;
6260 break;
6261 } else if ((NXT(len) == '(')) {
6262 /* Note Type or Function */
6263 if (xmlXPathIsNodeType(name)) {
6264#ifdef DEBUG_STEP
6265 xmlGenericError(xmlGenericErrorContext,
6266 "PathExpr: Type search\n");
6267#endif
6268 lc = 1;
6269 } else {
6270#ifdef DEBUG_STEP
6271 xmlGenericError(xmlGenericErrorContext,
6272 "PathExpr: function call\n");
6273#endif
6274 lc = 0;
6275 }
6276 break;
6277 } else if ((NXT(len) == '[')) {
6278 /* element name */
6279#ifdef DEBUG_STEP
6280 xmlGenericError(xmlGenericErrorContext,
6281 "PathExpr: AbbrRelLocation\n");
6282#endif
6283 lc = 1;
6284 break;
6285 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6286 (NXT(len) == '=')) {
6287 lc = 1;
6288 break;
6289 } else {
6290 lc = 1;
6291 break;
6292 }
6293 len++;
6294 }
6295 if (NXT(len) == 0) {
6296#ifdef DEBUG_STEP
6297 xmlGenericError(xmlGenericErrorContext,
6298 "PathExpr: AbbrRelLocation\n");
6299#endif
6300 /* element name */
6301 lc = 1;
6302 }
6303 xmlFree(name);
6304 } else {
6305 /* make sure all cases are covered explicitely */
6306 XP_ERROR(XPATH_EXPR_ERROR);
6307 }
6308 }
6309
6310 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006311 if (CUR == '/') {
6312 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6313 } else {
6314 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006315 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006316 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006317 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006318 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006319 CHECK_ERROR;
6320 if ((CUR == '/') && (NXT(1) == '/')) {
6321 SKIP(2);
6322 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006323
6324 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6325 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6326 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6327
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006328 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006329 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006330 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006331 }
6332 }
6333 SKIP_BLANKS;
6334}
6335
6336/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006337 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006338 * @ctxt: the XPath Parser context
6339 *
6340 * [18] UnionExpr ::= PathExpr
6341 * | UnionExpr '|' PathExpr
6342 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006343 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006344 */
6345
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006346static void
6347xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6348 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006349 CHECK_ERROR;
6350 SKIP_BLANKS;
6351 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006352 int op1 = ctxt->comp->last;
6353 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006354
6355 NEXT;
6356 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006357 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006358
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006359 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6360
Owen Taylor3473f882001-02-23 17:55:21 +00006361 SKIP_BLANKS;
6362 }
Owen Taylor3473f882001-02-23 17:55:21 +00006363}
6364
6365/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006366 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006367 * @ctxt: the XPath Parser context
6368 *
6369 * [27] UnaryExpr ::= UnionExpr
6370 * | '-' UnaryExpr
6371 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006372 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006373 */
6374
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006375static void
6376xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006377 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006378 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006379
6380 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006381 while (CUR == '-') {
6382 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006383 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006384 NEXT;
6385 SKIP_BLANKS;
6386 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006387
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006388 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006389 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006390 if (found) {
6391 if (minus)
6392 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6393 else
6394 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006395 }
6396}
6397
6398/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006399 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006400 * @ctxt: the XPath Parser context
6401 *
6402 * [26] MultiplicativeExpr ::= UnaryExpr
6403 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6404 * | MultiplicativeExpr 'div' UnaryExpr
6405 * | MultiplicativeExpr 'mod' UnaryExpr
6406 * [34] MultiplyOperator ::= '*'
6407 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006408 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006409 */
6410
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006411static void
6412xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6413 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006414 CHECK_ERROR;
6415 SKIP_BLANKS;
6416 while ((CUR == '*') ||
6417 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6418 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6419 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006420 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006421
6422 if (CUR == '*') {
6423 op = 0;
6424 NEXT;
6425 } else if (CUR == 'd') {
6426 op = 1;
6427 SKIP(3);
6428 } else if (CUR == 'm') {
6429 op = 2;
6430 SKIP(3);
6431 }
6432 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006433 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006434 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006435 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006436 SKIP_BLANKS;
6437 }
6438}
6439
6440/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006441 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006442 * @ctxt: the XPath Parser context
6443 *
6444 * [25] AdditiveExpr ::= MultiplicativeExpr
6445 * | AdditiveExpr '+' MultiplicativeExpr
6446 * | AdditiveExpr '-' MultiplicativeExpr
6447 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006448 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006449 */
6450
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006451static void
6452xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006453
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006454 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006455 CHECK_ERROR;
6456 SKIP_BLANKS;
6457 while ((CUR == '+') || (CUR == '-')) {
6458 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006459 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006460
6461 if (CUR == '+') plus = 1;
6462 else plus = 0;
6463 NEXT;
6464 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006465 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006466 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006467 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006468 SKIP_BLANKS;
6469 }
6470}
6471
6472/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006473 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006474 * @ctxt: the XPath Parser context
6475 *
6476 * [24] RelationalExpr ::= AdditiveExpr
6477 * | RelationalExpr '<' AdditiveExpr
6478 * | RelationalExpr '>' AdditiveExpr
6479 * | RelationalExpr '<=' AdditiveExpr
6480 * | RelationalExpr '>=' AdditiveExpr
6481 *
6482 * A <= B > C is allowed ? Answer from James, yes with
6483 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6484 * which is basically what got implemented.
6485 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006486 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006487 * on the stack
6488 */
6489
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006490static void
6491xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6492 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006493 CHECK_ERROR;
6494 SKIP_BLANKS;
6495 while ((CUR == '<') ||
6496 (CUR == '>') ||
6497 ((CUR == '<') && (NXT(1) == '=')) ||
6498 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006499 int inf, strict;
6500 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006501
6502 if (CUR == '<') inf = 1;
6503 else inf = 0;
6504 if (NXT(1) == '=') strict = 0;
6505 else strict = 1;
6506 NEXT;
6507 if (!strict) NEXT;
6508 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006509 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006510 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006511 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006512 SKIP_BLANKS;
6513 }
6514}
6515
6516/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006517 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006518 * @ctxt: the XPath Parser context
6519 *
6520 * [23] EqualityExpr ::= RelationalExpr
6521 * | EqualityExpr '=' RelationalExpr
6522 * | EqualityExpr '!=' RelationalExpr
6523 *
6524 * A != B != C is allowed ? Answer from James, yes with
6525 * (RelationalExpr = RelationalExpr) = RelationalExpr
6526 * (RelationalExpr != RelationalExpr) != RelationalExpr
6527 * which is basically what got implemented.
6528 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006529 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006530 *
6531 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006532static void
6533xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6534 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006535 CHECK_ERROR;
6536 SKIP_BLANKS;
6537 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006538 int eq;
6539 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006540
6541 if (CUR == '=') eq = 1;
6542 else eq = 0;
6543 NEXT;
6544 if (!eq) NEXT;
6545 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006546 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006547 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006548 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006549 SKIP_BLANKS;
6550 }
6551}
6552
6553/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006554 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006555 * @ctxt: the XPath Parser context
6556 *
6557 * [22] AndExpr ::= EqualityExpr
6558 * | AndExpr 'and' EqualityExpr
6559 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006560 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006561 *
6562 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006563static void
6564xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6565 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006566 CHECK_ERROR;
6567 SKIP_BLANKS;
6568 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006569 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006570 SKIP(3);
6571 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006572 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006573 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006574 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006575 SKIP_BLANKS;
6576 }
6577}
6578
6579/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006580 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006581 * @ctxt: the XPath Parser context
6582 *
6583 * [14] Expr ::= OrExpr
6584 * [21] OrExpr ::= AndExpr
6585 * | OrExpr 'or' AndExpr
6586 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006587 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006588 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006589static void
6590xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6591 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006592 CHECK_ERROR;
6593 SKIP_BLANKS;
6594 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006595 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006596 SKIP(2);
6597 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006598 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006599 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006600 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6601 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006602 SKIP_BLANKS;
6603 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006604 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6605 /* more ops could be optimized too */
6606 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6607 }
Owen Taylor3473f882001-02-23 17:55:21 +00006608}
6609
6610/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006611 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006612 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006613 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006614 *
6615 * [8] Predicate ::= '[' PredicateExpr ']'
6616 * [9] PredicateExpr ::= Expr
6617 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006618 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006619 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006620static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006621xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006622 int op1 = ctxt->comp->last;
6623
6624 SKIP_BLANKS;
6625 if (CUR != '[') {
6626 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6627 }
6628 NEXT;
6629 SKIP_BLANKS;
6630
6631 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006632 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006633 CHECK_ERROR;
6634
6635 if (CUR != ']') {
6636 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6637 }
6638
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006639 if (filter)
6640 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6641 else
6642 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006643
6644 NEXT;
6645 SKIP_BLANKS;
6646}
6647
6648/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006649 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006650 * @ctxt: the XPath Parser context
6651 * @test: pointer to a xmlXPathTestVal
6652 * @type: pointer to a xmlXPathTypeVal
6653 * @prefix: placeholder for a possible name prefix
6654 *
6655 * [7] NodeTest ::= NameTest
6656 * | NodeType '(' ')'
6657 * | 'processing-instruction' '(' Literal ')'
6658 *
6659 * [37] NameTest ::= '*'
6660 * | NCName ':' '*'
6661 * | QName
6662 * [38] NodeType ::= 'comment'
6663 * | 'text'
6664 * | 'processing-instruction'
6665 * | 'node'
6666 *
6667 * Returns the name found and update @test, @type and @prefix appropriately
6668 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006669static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006670xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6671 xmlXPathTypeVal *type, const xmlChar **prefix,
6672 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006673 int blanks;
6674
6675 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6676 STRANGE;
6677 return(NULL);
6678 }
6679 *type = 0;
6680 *test = 0;
6681 *prefix = NULL;
6682 SKIP_BLANKS;
6683
6684 if ((name == NULL) && (CUR == '*')) {
6685 /*
6686 * All elements
6687 */
6688 NEXT;
6689 *test = NODE_TEST_ALL;
6690 return(NULL);
6691 }
6692
6693 if (name == NULL)
6694 name = xmlXPathParseNCName(ctxt);
6695 if (name == NULL) {
6696 XP_ERROR0(XPATH_EXPR_ERROR);
6697 }
6698
6699 blanks = IS_BLANK(CUR);
6700 SKIP_BLANKS;
6701 if (CUR == '(') {
6702 NEXT;
6703 /*
6704 * NodeType or PI search
6705 */
6706 if (xmlStrEqual(name, BAD_CAST "comment"))
6707 *type = NODE_TYPE_COMMENT;
6708 else if (xmlStrEqual(name, BAD_CAST "node"))
6709 *type = NODE_TYPE_NODE;
6710 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6711 *type = NODE_TYPE_PI;
6712 else if (xmlStrEqual(name, BAD_CAST "text"))
6713 *type = NODE_TYPE_TEXT;
6714 else {
6715 if (name != NULL)
6716 xmlFree(name);
6717 XP_ERROR0(XPATH_EXPR_ERROR);
6718 }
6719
6720 *test = NODE_TEST_TYPE;
6721
6722 SKIP_BLANKS;
6723 if (*type == NODE_TYPE_PI) {
6724 /*
6725 * Specific case: search a PI by name.
6726 */
Owen Taylor3473f882001-02-23 17:55:21 +00006727 if (name != NULL)
6728 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006729 name = NULL;
6730 if (CUR != ')') {
6731 name = xmlXPathParseLiteral(ctxt);
6732 CHECK_ERROR 0;
6733 SKIP_BLANKS;
6734 }
Owen Taylor3473f882001-02-23 17:55:21 +00006735 }
6736 if (CUR != ')') {
6737 if (name != NULL)
6738 xmlFree(name);
6739 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6740 }
6741 NEXT;
6742 return(name);
6743 }
6744 *test = NODE_TEST_NAME;
6745 if ((!blanks) && (CUR == ':')) {
6746 NEXT;
6747
6748 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006749 * Since currently the parser context don't have a
6750 * namespace list associated:
6751 * The namespace name for this prefix can be computed
6752 * only at evaluation time. The compilation is done
6753 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006754 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006755#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006756 *prefix = xmlXPathNsLookup(ctxt->context, name);
6757 if (name != NULL)
6758 xmlFree(name);
6759 if (*prefix == NULL) {
6760 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6761 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006762#else
6763 *prefix = name;
6764#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006765
6766 if (CUR == '*') {
6767 /*
6768 * All elements
6769 */
6770 NEXT;
6771 *test = NODE_TEST_ALL;
6772 return(NULL);
6773 }
6774
6775 name = xmlXPathParseNCName(ctxt);
6776 if (name == NULL) {
6777 XP_ERROR0(XPATH_EXPR_ERROR);
6778 }
6779 }
6780 return(name);
6781}
6782
6783/**
6784 * xmlXPathIsAxisName:
6785 * @name: a preparsed name token
6786 *
6787 * [6] AxisName ::= 'ancestor'
6788 * | 'ancestor-or-self'
6789 * | 'attribute'
6790 * | 'child'
6791 * | 'descendant'
6792 * | 'descendant-or-self'
6793 * | 'following'
6794 * | 'following-sibling'
6795 * | 'namespace'
6796 * | 'parent'
6797 * | 'preceding'
6798 * | 'preceding-sibling'
6799 * | 'self'
6800 *
6801 * Returns the axis or 0
6802 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006803static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006804xmlXPathIsAxisName(const xmlChar *name) {
6805 xmlXPathAxisVal ret = 0;
6806 switch (name[0]) {
6807 case 'a':
6808 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6809 ret = AXIS_ANCESTOR;
6810 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6811 ret = AXIS_ANCESTOR_OR_SELF;
6812 if (xmlStrEqual(name, BAD_CAST "attribute"))
6813 ret = AXIS_ATTRIBUTE;
6814 break;
6815 case 'c':
6816 if (xmlStrEqual(name, BAD_CAST "child"))
6817 ret = AXIS_CHILD;
6818 break;
6819 case 'd':
6820 if (xmlStrEqual(name, BAD_CAST "descendant"))
6821 ret = AXIS_DESCENDANT;
6822 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6823 ret = AXIS_DESCENDANT_OR_SELF;
6824 break;
6825 case 'f':
6826 if (xmlStrEqual(name, BAD_CAST "following"))
6827 ret = AXIS_FOLLOWING;
6828 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6829 ret = AXIS_FOLLOWING_SIBLING;
6830 break;
6831 case 'n':
6832 if (xmlStrEqual(name, BAD_CAST "namespace"))
6833 ret = AXIS_NAMESPACE;
6834 break;
6835 case 'p':
6836 if (xmlStrEqual(name, BAD_CAST "parent"))
6837 ret = AXIS_PARENT;
6838 if (xmlStrEqual(name, BAD_CAST "preceding"))
6839 ret = AXIS_PRECEDING;
6840 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6841 ret = AXIS_PRECEDING_SIBLING;
6842 break;
6843 case 's':
6844 if (xmlStrEqual(name, BAD_CAST "self"))
6845 ret = AXIS_SELF;
6846 break;
6847 }
6848 return(ret);
6849}
6850
6851/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006852 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006853 * @ctxt: the XPath Parser context
6854 *
6855 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6856 * | AbbreviatedStep
6857 *
6858 * [12] AbbreviatedStep ::= '.' | '..'
6859 *
6860 * [5] AxisSpecifier ::= AxisName '::'
6861 * | AbbreviatedAxisSpecifier
6862 *
6863 * [13] AbbreviatedAxisSpecifier ::= '@'?
6864 *
6865 * Modified for XPtr range support as:
6866 *
6867 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6868 * | AbbreviatedStep
6869 * | 'range-to' '(' Expr ')' Predicate*
6870 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006871 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006872 * A location step of . is short for self::node(). This is
6873 * particularly useful in conjunction with //. For example, the
6874 * location path .//para is short for
6875 * self::node()/descendant-or-self::node()/child::para
6876 * and so will select all para descendant elements of the context
6877 * node.
6878 * Similarly, a location step of .. is short for parent::node().
6879 * For example, ../title is short for parent::node()/child::title
6880 * and so will select the title children of the parent of the context
6881 * node.
6882 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006883static void
6884xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006885#ifdef LIBXML_XPTR_ENABLED
6886 int rangeto = 0;
6887 int op2 = -1;
6888#endif
6889
Owen Taylor3473f882001-02-23 17:55:21 +00006890 SKIP_BLANKS;
6891 if ((CUR == '.') && (NXT(1) == '.')) {
6892 SKIP(2);
6893 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006894 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6895 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006896 } else if (CUR == '.') {
6897 NEXT;
6898 SKIP_BLANKS;
6899 } else {
6900 xmlChar *name = NULL;
6901 const xmlChar *prefix = NULL;
6902 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006903 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006904 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006905 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006906
6907 /*
6908 * The modification needed for XPointer change to the production
6909 */
6910#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006911 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006912 name = xmlXPathParseNCName(ctxt);
6913 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006914 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006915 xmlFree(name);
6916 SKIP_BLANKS;
6917 if (CUR != '(') {
6918 XP_ERROR(XPATH_EXPR_ERROR);
6919 }
6920 NEXT;
6921 SKIP_BLANKS;
6922
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006923 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006924 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006925 CHECK_ERROR;
6926
6927 SKIP_BLANKS;
6928 if (CUR != ')') {
6929 XP_ERROR(XPATH_EXPR_ERROR);
6930 }
6931 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006932 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006933 goto eval_predicates;
6934 }
6935 }
6936#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006937 if (CUR == '*') {
6938 axis = AXIS_CHILD;
6939 } else {
6940 if (name == NULL)
6941 name = xmlXPathParseNCName(ctxt);
6942 if (name != NULL) {
6943 axis = xmlXPathIsAxisName(name);
6944 if (axis != 0) {
6945 SKIP_BLANKS;
6946 if ((CUR == ':') && (NXT(1) == ':')) {
6947 SKIP(2);
6948 xmlFree(name);
6949 name = NULL;
6950 } else {
6951 /* an element name can conflict with an axis one :-\ */
6952 axis = AXIS_CHILD;
6953 }
Owen Taylor3473f882001-02-23 17:55:21 +00006954 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00006955 axis = AXIS_CHILD;
6956 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006957 } else if (CUR == '@') {
6958 NEXT;
6959 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00006960 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00006961 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00006962 }
Owen Taylor3473f882001-02-23 17:55:21 +00006963 }
6964
6965 CHECK_ERROR;
6966
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006967 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006968 if (test == 0)
6969 return;
6970
6971#ifdef DEBUG_STEP
6972 xmlGenericError(xmlGenericErrorContext,
6973 "Basis : computing new set\n");
6974#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006975
Owen Taylor3473f882001-02-23 17:55:21 +00006976#ifdef DEBUG_STEP
6977 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006978 if (ctxt->value == NULL)
6979 xmlGenericError(xmlGenericErrorContext, "no value\n");
6980 else if (ctxt->value->nodesetval == NULL)
6981 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6982 else
6983 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006984#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006985
6986eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006987 op1 = ctxt->comp->last;
6988 ctxt->comp->last = -1;
6989
Owen Taylor3473f882001-02-23 17:55:21 +00006990 SKIP_BLANKS;
6991 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006992 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006993 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006994
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006995#ifdef LIBXML_XPTR_ENABLED
6996 if (rangeto) {
6997 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
6998 } else
6999#endif
7000 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7001 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007002
Owen Taylor3473f882001-02-23 17:55:21 +00007003 }
7004#ifdef DEBUG_STEP
7005 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007006 if (ctxt->value == NULL)
7007 xmlGenericError(xmlGenericErrorContext, "no value\n");
7008 else if (ctxt->value->nodesetval == NULL)
7009 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7010 else
7011 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7012 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007013#endif
7014}
7015
7016/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007017 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007018 * @ctxt: the XPath Parser context
7019 *
7020 * [3] RelativeLocationPath ::= Step
7021 * | RelativeLocationPath '/' Step
7022 * | AbbreviatedRelativeLocationPath
7023 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7024 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007025 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007026 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007027static void
Owen Taylor3473f882001-02-23 17:55:21 +00007028#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007029xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007030#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007031xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007032#endif
7033(xmlXPathParserContextPtr ctxt) {
7034 SKIP_BLANKS;
7035 if ((CUR == '/') && (NXT(1) == '/')) {
7036 SKIP(2);
7037 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007038 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7039 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007040 } else if (CUR == '/') {
7041 NEXT;
7042 SKIP_BLANKS;
7043 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007044 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007045 SKIP_BLANKS;
7046 while (CUR == '/') {
7047 if ((CUR == '/') && (NXT(1) == '/')) {
7048 SKIP(2);
7049 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007050 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007051 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007052 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007053 } else if (CUR == '/') {
7054 NEXT;
7055 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007056 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007057 }
7058 SKIP_BLANKS;
7059 }
7060}
7061
7062/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007063 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007064 * @ctxt: the XPath Parser context
7065 *
7066 * [1] LocationPath ::= RelativeLocationPath
7067 * | AbsoluteLocationPath
7068 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7069 * | AbbreviatedAbsoluteLocationPath
7070 * [10] AbbreviatedAbsoluteLocationPath ::=
7071 * '//' RelativeLocationPath
7072 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007073 * Compile a location path
7074 *
Owen Taylor3473f882001-02-23 17:55:21 +00007075 * // is short for /descendant-or-self::node()/. For example,
7076 * //para is short for /descendant-or-self::node()/child::para and
7077 * so will select any para element in the document (even a para element
7078 * that is a document element will be selected by //para since the
7079 * document element node is a child of the root node); div//para is
7080 * short for div/descendant-or-self::node()/child::para and so will
7081 * select all para descendants of div children.
7082 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007083static void
7084xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007085 SKIP_BLANKS;
7086 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007087 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007088 } else {
7089 while (CUR == '/') {
7090 if ((CUR == '/') && (NXT(1) == '/')) {
7091 SKIP(2);
7092 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007093 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7094 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007095 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007096 } else if (CUR == '/') {
7097 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007098 SKIP_BLANKS;
7099 if ((CUR != 0 ) &&
7100 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7101 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007102 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007103 }
7104 }
7105 }
7106}
7107
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007108/************************************************************************
7109 * *
7110 * XPath precompiled expression evaluation *
7111 * *
7112 ************************************************************************/
7113
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007114static void
7115xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7116
7117/**
7118 * xmlXPathNodeCollectAndTest:
7119 * @ctxt: the XPath Parser context
7120 * @op: the XPath precompiled step operation
7121 *
7122 * This is the function implementing a step: based on the current list
7123 * of nodes, it builds up a new list, looking at all nodes under that
7124 * axis and selecting them it also do the predicate filtering
7125 *
7126 * Pushes the new NodeSet resulting from the search.
7127 */
7128static void
7129xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
7130 xmlXPathStepOpPtr op) {
7131 xmlXPathAxisVal axis = op->value;
7132 xmlXPathTestVal test = op->value2;
7133 xmlXPathTypeVal type = op->value3;
7134 const xmlChar *prefix = op->value4;
7135 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007136 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007137
7138#ifdef DEBUG_STEP
7139 int n = 0, t = 0;
7140#endif
7141 int i;
7142 xmlNodeSetPtr ret, list;
7143 xmlXPathTraversalFunction next = NULL;
7144 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
7145 xmlNodePtr cur = NULL;
7146 xmlXPathObjectPtr obj;
7147 xmlNodeSetPtr nodelist;
7148 xmlNodePtr tmp;
7149
7150 CHECK_TYPE(XPATH_NODESET);
7151 obj = valuePop(ctxt);
7152 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007153 if (prefix != NULL) {
7154 URI = xmlXPathNsLookup(ctxt->context, prefix);
7155 if (URI == NULL)
7156 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
7157 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007158
7159#ifdef DEBUG_STEP
7160 xmlGenericError(xmlGenericErrorContext,
7161 "new step : ");
7162#endif
7163 switch (axis) {
7164 case AXIS_ANCESTOR:
7165#ifdef DEBUG_STEP
7166 xmlGenericError(xmlGenericErrorContext,
7167 "axis 'ancestors' ");
7168#endif
7169 next = xmlXPathNextAncestor; break;
7170 case AXIS_ANCESTOR_OR_SELF:
7171#ifdef DEBUG_STEP
7172 xmlGenericError(xmlGenericErrorContext,
7173 "axis 'ancestors-or-self' ");
7174#endif
7175 next = xmlXPathNextAncestorOrSelf; break;
7176 case AXIS_ATTRIBUTE:
7177#ifdef DEBUG_STEP
7178 xmlGenericError(xmlGenericErrorContext,
7179 "axis 'attributes' ");
7180#endif
7181 next = xmlXPathNextAttribute; break;
7182 break;
7183 case AXIS_CHILD:
7184#ifdef DEBUG_STEP
7185 xmlGenericError(xmlGenericErrorContext,
7186 "axis 'child' ");
7187#endif
7188 next = xmlXPathNextChild; break;
7189 case AXIS_DESCENDANT:
7190#ifdef DEBUG_STEP
7191 xmlGenericError(xmlGenericErrorContext,
7192 "axis 'descendant' ");
7193#endif
7194 next = xmlXPathNextDescendant; break;
7195 case AXIS_DESCENDANT_OR_SELF:
7196#ifdef DEBUG_STEP
7197 xmlGenericError(xmlGenericErrorContext,
7198 "axis 'descendant-or-self' ");
7199#endif
7200 next = xmlXPathNextDescendantOrSelf; break;
7201 case AXIS_FOLLOWING:
7202#ifdef DEBUG_STEP
7203 xmlGenericError(xmlGenericErrorContext,
7204 "axis 'following' ");
7205#endif
7206 next = xmlXPathNextFollowing; break;
7207 case AXIS_FOLLOWING_SIBLING:
7208#ifdef DEBUG_STEP
7209 xmlGenericError(xmlGenericErrorContext,
7210 "axis 'following-siblings' ");
7211#endif
7212 next = xmlXPathNextFollowingSibling; break;
7213 case AXIS_NAMESPACE:
7214#ifdef DEBUG_STEP
7215 xmlGenericError(xmlGenericErrorContext,
7216 "axis 'namespace' ");
7217#endif
7218 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
7219 break;
7220 case AXIS_PARENT:
7221#ifdef DEBUG_STEP
7222 xmlGenericError(xmlGenericErrorContext,
7223 "axis 'parent' ");
7224#endif
7225 next = xmlXPathNextParent; break;
7226 case AXIS_PRECEDING:
7227#ifdef DEBUG_STEP
7228 xmlGenericError(xmlGenericErrorContext,
7229 "axis 'preceding' ");
7230#endif
7231 next = xmlXPathNextPreceding; break;
7232 case AXIS_PRECEDING_SIBLING:
7233#ifdef DEBUG_STEP
7234 xmlGenericError(xmlGenericErrorContext,
7235 "axis 'preceding-sibling' ");
7236#endif
7237 next = xmlXPathNextPrecedingSibling; break;
7238 case AXIS_SELF:
7239#ifdef DEBUG_STEP
7240 xmlGenericError(xmlGenericErrorContext,
7241 "axis 'self' ");
7242#endif
7243 next = xmlXPathNextSelf; break;
7244 }
7245 if (next == NULL)
7246 return;
7247
7248 nodelist = obj->nodesetval;
7249 if (nodelist == NULL) {
7250 xmlXPathFreeObject(obj);
7251 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7252 return;
7253 }
7254 addNode = xmlXPathNodeSetAddUnique;
7255 ret = NULL;
7256#ifdef DEBUG_STEP
7257 xmlGenericError(xmlGenericErrorContext,
7258 " context contains %d nodes\n",
7259 nodelist->nodeNr);
7260 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007261 case NODE_TEST_NONE:
7262 xmlGenericError(xmlGenericErrorContext,
7263 " searching for none !!!\n");
7264 break;
7265 case NODE_TEST_TYPE:
7266 xmlGenericError(xmlGenericErrorContext,
7267 " searching for type %d\n", type);
7268 break;
7269 case NODE_TEST_PI:
7270 xmlGenericError(xmlGenericErrorContext,
7271 " searching for PI !!!\n");
7272 break;
7273 case NODE_TEST_ALL:
7274 xmlGenericError(xmlGenericErrorContext,
7275 " searching for *\n");
7276 break;
7277 case NODE_TEST_NS:
7278 xmlGenericError(xmlGenericErrorContext,
7279 " searching for namespace %s\n",
7280 prefix);
7281 break;
7282 case NODE_TEST_NAME:
7283 xmlGenericError(xmlGenericErrorContext,
7284 " searching for name %s\n", name);
7285 if (prefix != NULL)
7286 xmlGenericError(xmlGenericErrorContext,
7287 " with namespace %s\n",
7288 prefix);
7289 break;
7290 }
7291 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7292#endif
7293 /*
7294 * 2.3 Node Tests
7295 * - For the attribute axis, the principal node type is attribute.
7296 * - For the namespace axis, the principal node type is namespace.
7297 * - For other axes, the principal node type is element.
7298 *
7299 * A node test * is true for any node of the
7300 * principal node type. For example, child::* willi
7301 * select all element children of the context node
7302 */
7303 tmp = ctxt->context->node;
7304 for (i = 0;i < nodelist->nodeNr; i++) {
7305 ctxt->context->node = nodelist->nodeTab[i];
7306
7307 cur = NULL;
7308 list = xmlXPathNodeSetCreate(NULL);
7309 do {
7310 cur = next(ctxt, cur);
7311 if (cur == NULL) break;
7312#ifdef DEBUG_STEP
7313 t++;
7314 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7315#endif
7316 switch (test) {
7317 case NODE_TEST_NONE:
7318 ctxt->context->node = tmp;
7319 STRANGE
7320 return;
7321 case NODE_TEST_TYPE:
7322 if ((cur->type == type) ||
7323 ((type == NODE_TYPE_NODE) &&
7324 ((cur->type == XML_DOCUMENT_NODE) ||
7325 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7326 (cur->type == XML_ELEMENT_NODE) ||
7327 (cur->type == XML_PI_NODE) ||
7328 (cur->type == XML_COMMENT_NODE) ||
7329 (cur->type == XML_CDATA_SECTION_NODE) ||
7330 (cur->type == XML_TEXT_NODE)))) {
7331#ifdef DEBUG_STEP
7332 n++;
7333#endif
7334 addNode(list, cur);
7335 }
7336 break;
7337 case NODE_TEST_PI:
7338 if (cur->type == XML_PI_NODE) {
7339 if ((name != NULL) &&
7340 (!xmlStrEqual(name, cur->name)))
7341 break;
7342#ifdef DEBUG_STEP
7343 n++;
7344#endif
7345 addNode(list, cur);
7346 }
7347 break;
7348 case NODE_TEST_ALL:
7349 if (axis == AXIS_ATTRIBUTE) {
7350 if (cur->type == XML_ATTRIBUTE_NODE) {
7351#ifdef DEBUG_STEP
7352 n++;
7353#endif
7354 addNode(list, cur);
7355 }
7356 } else if (axis == AXIS_NAMESPACE) {
7357 if (cur->type == XML_NAMESPACE_DECL) {
7358#ifdef DEBUG_STEP
7359 n++;
7360#endif
7361 addNode(list, cur);
7362 }
7363 } else {
Daniel Veillard8cf14d52001-06-23 16:32:46 +00007364 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007365 if (prefix == NULL) {
7366#ifdef DEBUG_STEP
7367 n++;
7368#endif
7369 addNode(list, cur);
7370 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007371 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007372 cur->ns->href))) {
7373#ifdef DEBUG_STEP
7374 n++;
7375#endif
7376 addNode(list, cur);
7377 }
7378 }
7379 }
7380 break;
7381 case NODE_TEST_NS: {
7382 TODO;
7383 break;
7384 }
7385 case NODE_TEST_NAME:
7386 switch (cur->type) {
7387 case XML_ELEMENT_NODE:
7388 if (xmlStrEqual(name, cur->name)) {
7389 if (prefix == NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00007390 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007391#ifdef DEBUG_STEP
7392 n++;
7393#endif
7394 addNode(list, cur);
7395 }
7396 } else {
7397 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007398 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007399 cur->ns->href))) {
7400#ifdef DEBUG_STEP
7401 n++;
7402#endif
7403 addNode(list, cur);
7404 }
7405 }
7406 }
7407 break;
7408 case XML_ATTRIBUTE_NODE: {
7409 xmlAttrPtr attr = (xmlAttrPtr) cur;
7410 if (xmlStrEqual(name, attr->name)) {
7411 if (prefix == NULL) {
7412 if ((attr->ns == NULL) ||
7413 (attr->ns->prefix == NULL)) {
7414#ifdef DEBUG_STEP
7415 n++;
7416#endif
7417 addNode(list, (xmlNodePtr) attr);
7418 }
7419 } else {
7420 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007421 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007422 attr->ns->href))) {
7423#ifdef DEBUG_STEP
7424 n++;
7425#endif
7426 addNode(list, (xmlNodePtr) attr);
7427 }
7428 }
7429 }
7430 break;
7431 }
Daniel Veillard8b8d2252001-06-16 21:24:56 +00007432 case XML_NAMESPACE_DECL:
7433 if (cur->type == XML_NAMESPACE_DECL) {
7434 xmlNsPtr ns = (xmlNsPtr) cur;
7435 if ((ns->prefix != NULL) && (name != NULL) &&
7436 (xmlStrEqual(ns->prefix, name))) {
7437#ifdef DEBUG_STEP
7438 n++;
7439#endif
7440 addNode(list, cur);
7441 }
7442 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007443 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007444 default:
7445 break;
7446 }
7447 break;
7448 }
7449 } while (cur != NULL);
7450
7451 /*
7452 * If there is some predicate filtering do it now
7453 */
7454 if (op->ch2 != -1) {
7455 xmlXPathObjectPtr obj2;
7456
7457 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7458 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7459 CHECK_TYPE(XPATH_NODESET);
7460 obj2 = valuePop(ctxt);
7461 list = obj2->nodesetval;
7462 obj2->nodesetval = NULL;
7463 xmlXPathFreeObject(obj2);
7464 }
7465 if (ret == NULL) {
7466 ret = list;
7467 } else {
7468 ret = xmlXPathNodeSetMerge(ret, list);
7469 xmlXPathFreeNodeSet(list);
7470 }
7471 }
7472 ctxt->context->node = tmp;
7473#ifdef DEBUG_STEP
7474 xmlGenericError(xmlGenericErrorContext,
7475 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7476#endif
7477 xmlXPathFreeObject(obj);
7478 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7479}
7480
Owen Taylor3473f882001-02-23 17:55:21 +00007481/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007482 * xmlXPathCompOpEval:
7483 * @ctxt: the XPath parser context with the compiled expression
7484 * @op: an XPath compiled operation
7485 *
7486 * Evaluate the Precompiled XPath operation
7487 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007488static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007489xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7490 int equal, ret;
7491 xmlXPathCompExprPtr comp;
7492 xmlXPathObjectPtr arg1, arg2;
7493
7494 comp = ctxt->comp;
7495 switch (op->op) {
7496 case XPATH_OP_END:
7497 return;
7498 case XPATH_OP_AND:
7499 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7500 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007501 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007502 return;
7503 arg2 = valuePop(ctxt);
7504 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7505 xmlXPathBooleanFunction(ctxt, 1);
7506 arg1 = valuePop(ctxt);
7507 arg1->boolval &= arg2->boolval;
7508 valuePush(ctxt, arg1);
7509 xmlXPathFreeObject(arg2);
7510 return;
7511 case XPATH_OP_OR:
7512 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7513 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007514 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007515 return;
7516 arg2 = valuePop(ctxt);
7517 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7518 xmlXPathBooleanFunction(ctxt, 1);
7519 arg1 = valuePop(ctxt);
7520 arg1->boolval |= arg2->boolval;
7521 valuePush(ctxt, arg1);
7522 xmlXPathFreeObject(arg2);
7523 return;
7524 case XPATH_OP_EQUAL:
7525 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7526 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7527 equal = xmlXPathEqualValues(ctxt);
7528 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7529 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7530 return;
7531 case XPATH_OP_CMP:
7532 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7533 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7534 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7535 valuePush(ctxt, xmlXPathNewBoolean(ret));
7536 return;
7537 case XPATH_OP_PLUS:
7538 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7539 if (op->ch2 != -1)
7540 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7541 if (op->value == 0) xmlXPathSubValues(ctxt);
7542 else if (op->value == 1) xmlXPathAddValues(ctxt);
7543 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7544 else if (op->value == 3) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007545 CAST_TO_NUMBER;
7546 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007547 }
7548 return;
7549 case XPATH_OP_MULT:
7550 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7551 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7552 if (op->value == 0) xmlXPathMultValues(ctxt);
7553 else if (op->value == 1) xmlXPathDivValues(ctxt);
7554 else if (op->value == 2) xmlXPathModValues(ctxt);
7555 return;
7556 case XPATH_OP_UNION:
7557 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7558 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7559 CHECK_TYPE(XPATH_NODESET);
7560 arg2 = valuePop(ctxt);
7561
7562 CHECK_TYPE(XPATH_NODESET);
7563 arg1 = valuePop(ctxt);
7564
7565 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7566 arg2->nodesetval);
7567 valuePush(ctxt, arg1);
7568 xmlXPathFreeObject(arg2);
7569 return;
7570 case XPATH_OP_ROOT:
7571 xmlXPathRoot(ctxt);
7572 return;
7573 case XPATH_OP_NODE:
7574 if (op->ch1 != -1)
7575 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7576 if (op->ch2 != -1)
7577 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7578 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7579 return;
7580 case XPATH_OP_RESET:
7581 if (op->ch1 != -1)
7582 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7583 if (op->ch2 != -1)
7584 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7585 ctxt->context->node = NULL;
7586 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007587 case XPATH_OP_COLLECT: {
7588 if (op->ch1 == -1)
7589 return;
7590
7591 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7592 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007593 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007594 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007595 case XPATH_OP_VALUE:
7596 valuePush(ctxt,
7597 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7598 return;
7599 case XPATH_OP_VARIABLE: {
7600 if (op->ch1 != -1)
7601 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7602 if (op->value5 == NULL)
7603 valuePush(ctxt,
7604 xmlXPathVariableLookup(ctxt->context, op->value4));
7605 else {
7606 const xmlChar *URI;
7607 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7608 if (URI == NULL) {
7609 xmlGenericError(xmlGenericErrorContext,
7610 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7611 op->value4, op->value5);
7612 return;
7613 }
7614 valuePush(ctxt,
7615 xmlXPathVariableLookupNS(ctxt->context,
7616 op->value4, URI));
7617 }
7618 return;
7619 }
7620 case XPATH_OP_FUNCTION: {
7621 xmlXPathFunction func;
Daniel Veillard42596ad2001-05-22 16:57:14 +00007622 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007623
7624 if (op->ch1 != -1)
7625 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007626 if (op->cache != NULL)
7627 func = (xmlXPathFunction) op->cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007628 else {
Daniel Veillard42596ad2001-05-22 16:57:14 +00007629 const xmlChar *URI = NULL;
7630
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007631 if (op->value5 == NULL)
7632 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7633 else {
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007634 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7635 if (URI == NULL) {
7636 xmlGenericError(xmlGenericErrorContext,
7637 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7638 op->value4, op->value5);
7639 return;
7640 }
7641 func = xmlXPathFunctionLookupNS(ctxt->context,
7642 op->value4, URI);
7643 }
7644 if (func == NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007645 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007646 "xmlXPathRunEval: function %s not found\n",
7647 op->value4);
7648 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007649 return;
7650 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007651 op->cache = (void *) func;
Daniel Veillard42596ad2001-05-22 16:57:14 +00007652 op->cacheURI = (void *) URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007653 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00007654 oldFunc = ctxt->context->function;
7655 oldFuncURI = ctxt->context->functionURI;
7656 ctxt->context->function = op->value4;
7657 ctxt->context->functionURI = op->cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007658 func(ctxt, op->value);
Daniel Veillard42596ad2001-05-22 16:57:14 +00007659 ctxt->context->function = oldFunc;
7660 ctxt->context->functionURI = oldFuncURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007661 return;
7662 }
7663 case XPATH_OP_ARG:
7664 if (op->ch1 != -1)
7665 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7666 if (op->ch2 != -1)
7667 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7668 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007669 case XPATH_OP_PREDICATE:
7670 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007671 xmlXPathObjectPtr res;
7672 xmlXPathObjectPtr obj, tmp;
7673 xmlNodeSetPtr newset = NULL;
7674 xmlNodeSetPtr oldset;
7675 xmlNodePtr oldnode;
7676 int i;
7677
7678 if (op->ch1 != -1)
7679 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7680 if (op->ch2 == -1)
7681 return;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007682 if (ctxt->value == NULL)
7683 return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007684
7685 oldnode = ctxt->context->node;
7686
7687#ifdef LIBXML_XPTR_ENABLED
7688 /*
7689 * Hum are we filtering the result of an XPointer expression
7690 */
7691 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007692 xmlLocationSetPtr newlocset = NULL;
7693 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007694
7695 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007696 * Extract the old locset, and then evaluate the result of the
7697 * expression for all the element in the locset. use it to grow
7698 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007699 */
7700 CHECK_TYPE(XPATH_LOCATIONSET);
7701 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007702 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007703 ctxt->context->node = NULL;
7704
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007705 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007706 ctxt->context->contextSize = 0;
7707 ctxt->context->proximityPosition = 0;
7708 if (op->ch2 != -1)
7709 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7710 res = valuePop(ctxt);
7711 if (res != NULL)
7712 xmlXPathFreeObject(res);
7713 valuePush(ctxt, obj);
7714 CHECK_ERROR;
7715 return;
7716 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007717 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007718
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007719 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007720 /*
7721 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007722 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007723 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007724 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007725 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7726 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007727 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007728 ctxt->context->proximityPosition = i + 1;
7729
7730 if (op->ch2 != -1)
7731 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7732 CHECK_ERROR;
7733
7734 /*
7735 * The result of the evaluation need to be tested to
7736 * decided whether the filter succeeded or not
7737 */
7738 res = valuePop(ctxt);
7739 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007740 xmlXPtrLocationSetAdd(newlocset,
7741 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007742 }
7743
7744 /*
7745 * Cleanup
7746 */
7747 if (res != NULL)
7748 xmlXPathFreeObject(res);
7749 if (ctxt->value == tmp) {
7750 res = valuePop(ctxt);
7751 xmlXPathFreeObject(res);
7752 }
7753
7754 ctxt->context->node = NULL;
7755 }
7756
7757 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007758 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007759 */
7760 xmlXPathFreeObject(obj);
7761 ctxt->context->node = NULL;
7762 ctxt->context->contextSize = -1;
7763 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007764 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007765 ctxt->context->node = oldnode;
7766 return;
7767 }
7768#endif /* LIBXML_XPTR_ENABLED */
7769
7770 /*
7771 * Extract the old set, and then evaluate the result of the
7772 * expression for all the element in the set. use it to grow
7773 * up a new set.
7774 */
7775 CHECK_TYPE(XPATH_NODESET);
7776 obj = valuePop(ctxt);
7777 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007778
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007779 oldnode = ctxt->context->node;
7780 ctxt->context->node = NULL;
7781
7782 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7783 ctxt->context->contextSize = 0;
7784 ctxt->context->proximityPosition = 0;
7785 if (op->ch2 != -1)
7786 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7787 res = valuePop(ctxt);
7788 if (res != NULL)
7789 xmlXPathFreeObject(res);
7790 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007791 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007792 CHECK_ERROR;
7793 } else {
7794 /*
7795 * Initialize the new set.
7796 */
7797 newset = xmlXPathNodeSetCreate(NULL);
7798
7799 for (i = 0; i < oldset->nodeNr; i++) {
7800 /*
7801 * Run the evaluation with a node list made of
7802 * a single item in the nodeset.
7803 */
7804 ctxt->context->node = oldset->nodeTab[i];
7805 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7806 valuePush(ctxt, tmp);
7807 ctxt->context->contextSize = oldset->nodeNr;
7808 ctxt->context->proximityPosition = i + 1;
7809
7810 if (op->ch2 != -1)
7811 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7812 CHECK_ERROR;
7813
7814 /*
7815 * The result of the evaluation need to be tested to
7816 * decided whether the filter succeeded or not
7817 */
7818 res = valuePop(ctxt);
7819 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7820 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7821 }
7822
7823 /*
7824 * Cleanup
7825 */
7826 if (res != NULL)
7827 xmlXPathFreeObject(res);
7828 if (ctxt->value == tmp) {
7829 res = valuePop(ctxt);
7830 xmlXPathFreeObject(res);
7831 }
7832
7833 ctxt->context->node = NULL;
7834 }
7835
7836 /*
7837 * The result is used as the new evaluation set.
7838 */
7839 xmlXPathFreeObject(obj);
7840 ctxt->context->node = NULL;
7841 ctxt->context->contextSize = -1;
7842 ctxt->context->proximityPosition = -1;
7843 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7844 }
7845 ctxt->context->node = oldnode;
7846 return;
7847 }
7848 case XPATH_OP_SORT:
7849 if (op->ch1 != -1)
7850 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7851 if ((ctxt->value != NULL) &&
7852 (ctxt->value->type == XPATH_NODESET) &&
7853 (ctxt->value->nodesetval != NULL))
7854 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7855 return;
7856#ifdef LIBXML_XPTR_ENABLED
7857 case XPATH_OP_RANGETO: {
7858 xmlXPathObjectPtr range;
7859 xmlXPathObjectPtr res, obj;
7860 xmlXPathObjectPtr tmp;
7861 xmlLocationSetPtr newset = NULL;
7862 xmlNodeSetPtr oldset;
7863 int i;
7864
7865 if (op->ch1 != -1)
7866 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7867 if (op->ch2 == -1)
7868 return;
7869
7870 CHECK_TYPE(XPATH_NODESET);
7871 obj = valuePop(ctxt);
7872 oldset = obj->nodesetval;
7873 ctxt->context->node = NULL;
7874
7875 newset = xmlXPtrLocationSetCreate(NULL);
7876
Daniel Veillard911f49a2001-04-07 15:39:35 +00007877 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007878 for (i = 0; i < oldset->nodeNr; i++) {
7879 /*
7880 * Run the evaluation with a node list made of a single item
7881 * in the nodeset.
7882 */
7883 ctxt->context->node = oldset->nodeTab[i];
7884 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7885 valuePush(ctxt, tmp);
7886
7887 if (op->ch2 != -1)
7888 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7889 CHECK_ERROR;
7890
7891 /*
7892 * The result of the evaluation need to be tested to
7893 * decided whether the filter succeeded or not
7894 */
7895 res = valuePop(ctxt);
7896 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7897 if (range != NULL) {
7898 xmlXPtrLocationSetAdd(newset, range);
7899 }
7900
7901 /*
7902 * Cleanup
7903 */
7904 if (res != NULL)
7905 xmlXPathFreeObject(res);
7906 if (ctxt->value == tmp) {
7907 res = valuePop(ctxt);
7908 xmlXPathFreeObject(res);
7909 }
7910
7911 ctxt->context->node = NULL;
7912 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007913 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007914
7915 /*
7916 * The result is used as the new evaluation set.
7917 */
7918 xmlXPathFreeObject(obj);
7919 ctxt->context->node = NULL;
7920 ctxt->context->contextSize = -1;
7921 ctxt->context->proximityPosition = -1;
7922 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7923 return;
7924 }
7925#endif /* LIBXML_XPTR_ENABLED */
7926 }
7927 xmlGenericError(xmlGenericErrorContext,
7928 "XPath: unknown precompiled operation %d\n",
7929 op->op);
7930 return;
7931}
7932
7933/**
7934 * xmlXPathRunEval:
7935 * @ctxt: the XPath parser context with the compiled expression
7936 *
7937 * Evaluate the Precompiled XPath expression in the given context.
7938 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007939static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007940xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7941 xmlXPathCompExprPtr comp;
7942
7943 if ((ctxt == NULL) || (ctxt->comp == NULL))
7944 return;
7945
7946 if (ctxt->valueTab == NULL) {
7947 /* Allocate the value stack */
7948 ctxt->valueTab = (xmlXPathObjectPtr *)
7949 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7950 if (ctxt->valueTab == NULL) {
7951 xmlFree(ctxt);
7952 xmlGenericError(xmlGenericErrorContext,
7953 "xmlXPathRunEval: out of memory\n");
7954 return;
7955 }
7956 ctxt->valueNr = 0;
7957 ctxt->valueMax = 10;
7958 ctxt->value = NULL;
7959 }
7960 comp = ctxt->comp;
7961 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7962}
7963
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007964/************************************************************************
7965 * *
7966 * Public interfaces *
7967 * *
7968 ************************************************************************/
7969
7970/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007971 * xmlXPathEvalPredicate:
7972 * @ctxt: the XPath context
7973 * @res: the Predicate Expression evaluation result
7974 *
7975 * Evaluate a predicate result for the current node.
7976 * A PredicateExpr is evaluated by evaluating the Expr and converting
7977 * the result to a boolean. If the result is a number, the result will
7978 * be converted to true if the number is equal to the position of the
7979 * context node in the context node list (as returned by the position
7980 * function) and will be converted to false otherwise; if the result
7981 * is not a number, then the result will be converted as if by a call
7982 * to the boolean function.
7983 *
7984 * Return 1 if predicate is true, 0 otherwise
7985 */
7986int
7987xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7988 if (res == NULL) return(0);
7989 switch (res->type) {
7990 case XPATH_BOOLEAN:
7991 return(res->boolval);
7992 case XPATH_NUMBER:
7993 return(res->floatval == ctxt->proximityPosition);
7994 case XPATH_NODESET:
7995 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007996 if (res->nodesetval == NULL)
7997 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007998 return(res->nodesetval->nodeNr != 0);
7999 case XPATH_STRING:
8000 return((res->stringval != NULL) &&
8001 (xmlStrlen(res->stringval) != 0));
8002 default:
8003 STRANGE
8004 }
8005 return(0);
8006}
8007
8008/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008009 * xmlXPathEvaluatePredicateResult:
8010 * @ctxt: the XPath Parser context
8011 * @res: the Predicate Expression evaluation result
8012 *
8013 * Evaluate a predicate result for the current node.
8014 * A PredicateExpr is evaluated by evaluating the Expr and converting
8015 * the result to a boolean. If the result is a number, the result will
8016 * be converted to true if the number is equal to the position of the
8017 * context node in the context node list (as returned by the position
8018 * function) and will be converted to false otherwise; if the result
8019 * is not a number, then the result will be converted as if by a call
8020 * to the boolean function.
8021 *
8022 * Return 1 if predicate is true, 0 otherwise
8023 */
8024int
8025xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
8026 xmlXPathObjectPtr res) {
8027 if (res == NULL) return(0);
8028 switch (res->type) {
8029 case XPATH_BOOLEAN:
8030 return(res->boolval);
8031 case XPATH_NUMBER:
8032 return(res->floatval == ctxt->context->proximityPosition);
8033 case XPATH_NODESET:
8034 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00008035 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00008036 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008037 return(res->nodesetval->nodeNr != 0);
8038 case XPATH_STRING:
8039 return((res->stringval != NULL) &&
8040 (xmlStrlen(res->stringval) != 0));
8041 default:
8042 STRANGE
8043 }
8044 return(0);
8045}
8046
8047/**
8048 * xmlXPathCompile:
8049 * @str: the XPath expression
8050 *
8051 * Compile an XPath expression
8052 *
8053 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8054 * the caller has to free the object.
8055 */
8056xmlXPathCompExprPtr
8057xmlXPathCompile(const xmlChar *str) {
8058 xmlXPathParserContextPtr ctxt;
8059 xmlXPathCompExprPtr comp;
8060
8061 xmlXPathInit();
8062
8063 ctxt = xmlXPathNewParserContext(str, NULL);
8064 xmlXPathCompileExpr(ctxt);
8065
Daniel Veillard40af6492001-04-22 08:50:55 +00008066 if (*ctxt->cur != 0) {
8067 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8068 comp = NULL;
8069 } else {
8070 comp = ctxt->comp;
8071 ctxt->comp = NULL;
8072 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008073 xmlXPathFreeParserContext(ctxt);
8074 return(comp);
8075}
8076
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008077/**
8078 * xmlXPathCompiledEval:
8079 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00008080 * @ctx: the XPath context
8081 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008082 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00008083 *
8084 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8085 * the caller has to free the object.
8086 */
8087xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008088xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00008089 xmlXPathParserContextPtr ctxt;
8090 xmlXPathObjectPtr res, tmp, init = NULL;
8091 int stack = 0;
8092
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008093 if ((comp == NULL) || (ctx == NULL))
8094 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008095 xmlXPathInit();
8096
8097 CHECK_CONTEXT(ctx)
8098
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008099 ctxt = xmlXPathCompParserContext(comp, ctx);
8100 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008101
8102 if (ctxt->value == NULL) {
8103 xmlGenericError(xmlGenericErrorContext,
8104 "xmlXPathEval: evaluation failed\n");
8105 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00008106 } else {
8107 res = valuePop(ctxt);
8108 }
8109
8110 do {
8111 tmp = valuePop(ctxt);
8112 if (tmp != NULL) {
8113 if (tmp != init)
8114 stack++;
8115 xmlXPathFreeObject(tmp);
8116 }
8117 } while (tmp != NULL);
8118 if ((stack != 0) && (res != NULL)) {
8119 xmlGenericError(xmlGenericErrorContext,
8120 "xmlXPathEval: %d object left on the stack\n",
8121 stack);
8122 }
8123 if (ctxt->error != XPATH_EXPRESSION_OK) {
8124 xmlXPathFreeObject(res);
8125 res = NULL;
8126 }
8127
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008128
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008129 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008130 xmlXPathFreeParserContext(ctxt);
8131 return(res);
8132}
8133
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008134/**
8135 * xmlXPathEvalExpr:
8136 * @ctxt: the XPath Parser context
8137 *
8138 * Parse and evaluate an XPath expression in the given context,
8139 * then push the result on the context stack
8140 */
8141void
8142xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
8143 xmlXPathCompileExpr(ctxt);
8144 xmlXPathRunEval(ctxt);
8145}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008146
8147/**
8148 * xmlXPathEval:
8149 * @str: the XPath expression
8150 * @ctx: the XPath context
8151 *
8152 * Evaluate the XPath Location Path in the given context.
8153 *
8154 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8155 * the caller has to free the object.
8156 */
8157xmlXPathObjectPtr
8158xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
8159 xmlXPathParserContextPtr ctxt;
8160 xmlXPathObjectPtr res, tmp, init = NULL;
8161 int stack = 0;
8162
8163 xmlXPathInit();
8164
8165 CHECK_CONTEXT(ctx)
8166
8167 ctxt = xmlXPathNewParserContext(str, ctx);
8168 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008169
8170 if (ctxt->value == NULL) {
8171 xmlGenericError(xmlGenericErrorContext,
8172 "xmlXPathEval: evaluation failed\n");
8173 res = NULL;
8174 } else if (*ctxt->cur != 0) {
8175 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8176 res = NULL;
8177 } else {
8178 res = valuePop(ctxt);
8179 }
8180
8181 do {
8182 tmp = valuePop(ctxt);
8183 if (tmp != NULL) {
8184 if (tmp != init)
8185 stack++;
8186 xmlXPathFreeObject(tmp);
8187 }
8188 } while (tmp != NULL);
8189 if ((stack != 0) && (res != NULL)) {
8190 xmlGenericError(xmlGenericErrorContext,
8191 "xmlXPathEval: %d object left on the stack\n",
8192 stack);
8193 }
8194 if (ctxt->error != XPATH_EXPRESSION_OK) {
8195 xmlXPathFreeObject(res);
8196 res = NULL;
8197 }
8198
Owen Taylor3473f882001-02-23 17:55:21 +00008199 xmlXPathFreeParserContext(ctxt);
8200 return(res);
8201}
8202
8203/**
8204 * xmlXPathEvalExpression:
8205 * @str: the XPath expression
8206 * @ctxt: the XPath context
8207 *
8208 * Evaluate the XPath expression in the given context.
8209 *
8210 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
8211 * the caller has to free the object.
8212 */
8213xmlXPathObjectPtr
8214xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
8215 xmlXPathParserContextPtr pctxt;
8216 xmlXPathObjectPtr res, tmp;
8217 int stack = 0;
8218
8219 xmlXPathInit();
8220
8221 CHECK_CONTEXT(ctxt)
8222
8223 pctxt = xmlXPathNewParserContext(str, ctxt);
8224 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008225
8226 if (*pctxt->cur != 0) {
8227 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8228 res = NULL;
8229 } else {
8230 res = valuePop(pctxt);
8231 }
8232 do {
8233 tmp = valuePop(pctxt);
8234 if (tmp != NULL) {
8235 xmlXPathFreeObject(tmp);
8236 stack++;
8237 }
8238 } while (tmp != NULL);
8239 if ((stack != 0) && (res != NULL)) {
8240 xmlGenericError(xmlGenericErrorContext,
8241 "xmlXPathEvalExpression: %d object left on the stack\n",
8242 stack);
8243 }
8244 xmlXPathFreeParserContext(pctxt);
8245 return(res);
8246}
8247
8248/**
8249 * xmlXPathRegisterAllFunctions:
8250 * @ctxt: the XPath context
8251 *
8252 * Registers all default XPath functions in this context
8253 */
8254void
8255xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
8256{
8257 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
8258 xmlXPathBooleanFunction);
8259 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
8260 xmlXPathCeilingFunction);
8261 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
8262 xmlXPathCountFunction);
8263 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
8264 xmlXPathConcatFunction);
8265 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
8266 xmlXPathContainsFunction);
8267 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
8268 xmlXPathIdFunction);
8269 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
8270 xmlXPathFalseFunction);
8271 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
8272 xmlXPathFloorFunction);
8273 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
8274 xmlXPathLastFunction);
8275 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
8276 xmlXPathLangFunction);
8277 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
8278 xmlXPathLocalNameFunction);
8279 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
8280 xmlXPathNotFunction);
8281 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
8282 xmlXPathNameFunction);
8283 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
8284 xmlXPathNamespaceURIFunction);
8285 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
8286 xmlXPathNormalizeFunction);
8287 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
8288 xmlXPathNumberFunction);
8289 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
8290 xmlXPathPositionFunction);
8291 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
8292 xmlXPathRoundFunction);
8293 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
8294 xmlXPathStringFunction);
8295 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
8296 xmlXPathStringLengthFunction);
8297 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
8298 xmlXPathStartsWithFunction);
8299 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
8300 xmlXPathSubstringFunction);
8301 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
8302 xmlXPathSubstringBeforeFunction);
8303 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
8304 xmlXPathSubstringAfterFunction);
8305 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
8306 xmlXPathSumFunction);
8307 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
8308 xmlXPathTrueFunction);
8309 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
8310 xmlXPathTranslateFunction);
8311}
8312
8313#endif /* LIBXML_XPATH_ENABLED */