blob: d2229434f71a03b50a3bad99fa18d7f58e1b6801 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020#ifdef LIBXML_XPATH_ENABLED
21
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_MATH_H
28#include <math.h>
29#endif
30#ifdef HAVE_FLOAT_H
31#include <float.h>
32#endif
33#ifdef HAVE_IEEEFP_H
34#include <ieeefp.h>
35#endif
36#ifdef HAVE_NAN_H
37#include <nan.h>
38#endif
39#ifdef HAVE_CTYPE_H
40#include <ctype.h>
41#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000042#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000043#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000044#endif
Owen Taylor3473f882001-02-23 17:55:21 +000045
46#include <libxml/xmlmemory.h>
47#include <libxml/tree.h>
48#include <libxml/valid.h>
49#include <libxml/xpath.h>
50#include <libxml/xpathInternals.h>
51#include <libxml/parserInternals.h>
52#include <libxml/hash.h>
53#ifdef LIBXML_XPTR_ENABLED
54#include <libxml/xpointer.h>
55#endif
56#ifdef LIBXML_DEBUG_ENABLED
57#include <libxml/debugXML.h>
58#endif
59#include <libxml/xmlerror.h>
60
61/* #define DEBUG */
62/* #define DEBUG_STEP */
63/* #define DEBUG_EXPR */
64
65void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
66double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000067double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000068
Daniel Veillard9e7160d2001-03-18 23:17:47 +000069/************************************************************************
70 * *
71 * Floating point stuff *
72 * *
73 ************************************************************************/
74
Owen Taylor3473f882001-02-23 17:55:21 +000075/*
Owen Taylor3473f882001-02-23 17:55:21 +000076 * The lack of portability of this section of the libc is annoying !
77 */
78double xmlXPathNAN = 0;
79double xmlXPathPINF = 1;
80double xmlXPathNINF = -1;
81
82#ifndef isinf
83#ifndef HAVE_ISINF
84
85#if HAVE_FPCLASS
86
87int isinf(double d) {
88 fpclass_t type = fpclass(d);
89 switch (type) {
90 case FP_NINF:
91 return(-1);
92 case FP_PINF:
93 return(1);
94 }
95 return(0);
96}
97
98#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
99
100#if HAVE_FP_CLASS_H
101#include <fp_class.h>
102#endif
103
104int isinf(double d) {
105#if HAVE_FP_CLASS
106 int fpclass = fp_class(d);
107#else
108 int fpclass = fp_class_d(d);
109#endif
110 if (fpclass == FP_POS_INF)
111 return(1);
112 if (fpclass == FP_NEG_INF)
113 return(-1);
114 return(0);
115}
116
117#elif defined(HAVE_CLASS)
118
119int isinf(double d) {
120 int fpclass = class(d);
121 if (fpclass == FP_PLUS_INF)
122 return(1);
123 if (fpclass == FP_MINUS_INF)
124 return(-1);
125 return(0);
126}
127#elif defined(finite) || defined(HAVE_FINITE)
128int isinf(double x) { return !finite(x) && x==x; }
129#elif defined(HUGE_VAL)
130int isinf(double x)
131{
132 if (x == HUGE_VAL)
133 return(1);
134 if (x == -HUGE_VAL)
135 return(-1);
136 return(0);
137}
138#endif
139
140#endif /* ! HAVE_ISINF */
141#endif /* ! defined(isinf) */
142
143#ifndef isnan
144#ifndef HAVE_ISNAN
145
146#ifdef HAVE_ISNAND
147#define isnan(f) isnand(f)
148#endif /* HAVE_iSNAND */
149
150#endif /* ! HAVE_iSNAN */
151#endif /* ! defined(isnan) */
152
Daniel Veillard5792e162001-04-30 17:44:45 +0000153
154/**
155 * xmlXPathDivideBy:
156 *
157 * The best way found so far to generate the NAN, +-INF
158 * without hitting a compiler bug or optimization :-\
159 *
160 * Returns the double resulting from the division
161 */
162double
163xmlXPathDivideBy(double f, double fzero) {
164 float ret;
165#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);
197 xmlXPathPINF = 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 Veillard9e7160d2001-03-18 23:17:47 +0000282};
283
284struct _xmlXPathCompExpr {
285 int nbStep;
286 int maxStep;
287 xmlXPathStepOp *steps; /* ops for computation */
288 int last;
289};
290
291/************************************************************************
292 * *
293 * Parser Type functions *
294 * *
295 ************************************************************************/
296
297/**
298 * xmlXPathNewCompExpr:
299 *
300 * Create a new Xpath component
301 *
302 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
303 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000304static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000305xmlXPathNewCompExpr(void) {
306 xmlXPathCompExprPtr cur;
307
308 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
309 if (cur == NULL) {
310 xmlGenericError(xmlGenericErrorContext,
311 "xmlXPathNewCompExpr : malloc failed\n");
312 return(NULL);
313 }
314 memset(cur, 0, sizeof(xmlXPathCompExpr));
315 cur->maxStep = 10;
316 cur->nbStep = 0;
317 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
318 sizeof(xmlXPathStepOp));
319 if (cur->steps == NULL) {
320 xmlGenericError(xmlGenericErrorContext,
321 "xmlXPathNewCompExpr : malloc failed\n");
322 xmlFree(cur);
323 return(NULL);
324 }
325 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
326 cur->last = -1;
327 return(cur);
328}
329
330/**
331 * xmlXPathFreeCompExpr:
332 * @comp: an XPATH comp
333 *
334 * Free up the memory allocated by @comp
335 */
336void
337xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) {
338 xmlXPathStepOpPtr op;
339 int i;
340
341 if (comp == NULL)
342 return;
343 for (i = 0;i < comp->nbStep;i++) {
344 op = &comp->steps[i];
345 if (op->value4 != NULL) {
346 if (op->op == XPATH_OP_VALUE)
347 xmlXPathFreeObject(op->value4);
348 else
349 xmlFree(op->value4);
350 }
351 if (op->value5 != NULL)
352 xmlFree(op->value5);
353 }
354 if (comp->steps != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000355 xmlFree(comp->steps);
356 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000357 xmlFree(comp);
358}
359
360/**
361 * xmlXPathCompExprAdd:
362 * @comp: the compiled expression
363 * @ch1: first child index
364 * @ch2: second child index
365 * @op: an op
366 * @value: the first int value
367 * @value2: the second int value
368 * @value3: the third int value
369 * @value4: the first string value
370 * @value5: the second string value
371 *
372 * Add an step to an XPath Compiled Expression
373 *
374 * Returns -1 in case of failure, the index otherwise
375 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000376static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000377xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
378 xmlXPathOp op, int value,
379 int value2, int value3, void *value4, void *value5) {
380 if (comp->nbStep >= comp->maxStep) {
381 xmlXPathStepOp *real;
382
383 comp->maxStep *= 2;
384 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
385 comp->maxStep * sizeof(xmlXPathStepOp));
386 if (real == NULL) {
387 comp->maxStep /= 2;
388 xmlGenericError(xmlGenericErrorContext,
389 "xmlXPathCompExprAdd : realloc failed\n");
390 return(-1);
391 }
392 comp->steps = real;
393 }
394 comp->last = comp->nbStep;
395 comp->steps[comp->nbStep].ch1 = ch1;
396 comp->steps[comp->nbStep].ch2 = ch2;
397 comp->steps[comp->nbStep].op = op;
398 comp->steps[comp->nbStep].value = value;
399 comp->steps[comp->nbStep].value2 = value2;
400 comp->steps[comp->nbStep].value3 = value3;
401 comp->steps[comp->nbStep].value4 = value4;
402 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000403 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000404 return(comp->nbStep++);
405}
406
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000407#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
408 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
409 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000410#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
411 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
412 (op), (val), (val2), (val3), (val4), (val5))
413
414#define PUSH_LEAVE_EXPR(op, val, val2) \
415xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
416
417#define PUSH_UNARY_EXPR(op, ch, val, val2) \
418xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
419
420#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
421xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
422
423/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000424 * *
425 * Debugging related functions *
426 * *
427 ************************************************************************/
428
429#define TODO \
430 xmlGenericError(xmlGenericErrorContext, \
431 "Unimplemented block at %s:%d\n", \
432 __FILE__, __LINE__);
433
434#define STRANGE \
435 xmlGenericError(xmlGenericErrorContext, \
436 "Internal error at %s:%d\n", \
437 __FILE__, __LINE__);
438
439#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000440static void
441xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000442 int i;
443 char shift[100];
444
445 for (i = 0;((i < depth) && (i < 25));i++)
446 shift[2 * i] = shift[2 * i + 1] = ' ';
447 shift[2 * i] = shift[2 * i + 1] = 0;
448 if (cur == NULL) {
449 fprintf(output, shift);
450 fprintf(output, "Node is NULL !\n");
451 return;
452
453 }
454
455 if ((cur->type == XML_DOCUMENT_NODE) ||
456 (cur->type == XML_HTML_DOCUMENT_NODE)) {
457 fprintf(output, shift);
458 fprintf(output, " /\n");
459 } else if (cur->type == XML_ATTRIBUTE_NODE)
460 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
461 else
462 xmlDebugDumpOneNode(output, cur, depth);
463}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000464static void
465xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000466 xmlNodePtr tmp;
467 int i;
468 char shift[100];
469
470 for (i = 0;((i < depth) && (i < 25));i++)
471 shift[2 * i] = shift[2 * i + 1] = ' ';
472 shift[2 * i] = shift[2 * i + 1] = 0;
473 if (cur == NULL) {
474 fprintf(output, shift);
475 fprintf(output, "Node is NULL !\n");
476 return;
477
478 }
479
480 while (cur != NULL) {
481 tmp = cur;
482 cur = cur->next;
483 xmlDebugDumpOneNode(output, tmp, depth);
484 }
485}
Owen Taylor3473f882001-02-23 17:55:21 +0000486
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000487static void
488xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000489 int i;
490 char shift[100];
491
492 for (i = 0;((i < depth) && (i < 25));i++)
493 shift[2 * i] = shift[2 * i + 1] = ' ';
494 shift[2 * i] = shift[2 * i + 1] = 0;
495
496 if (cur == NULL) {
497 fprintf(output, shift);
498 fprintf(output, "NodeSet is NULL !\n");
499 return;
500
501 }
502
Daniel Veillard911f49a2001-04-07 15:39:35 +0000503 if (cur != NULL) {
504 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
505 for (i = 0;i < cur->nodeNr;i++) {
506 fprintf(output, shift);
507 fprintf(output, "%d", i + 1);
508 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
509 }
Owen Taylor3473f882001-02-23 17:55:21 +0000510 }
511}
512
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000513static void
514xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000515 int i;
516 char shift[100];
517
518 for (i = 0;((i < depth) && (i < 25));i++)
519 shift[2 * i] = shift[2 * i + 1] = ' ';
520 shift[2 * i] = shift[2 * i + 1] = 0;
521
522 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
523 fprintf(output, shift);
524 fprintf(output, "Value Tree is NULL !\n");
525 return;
526
527 }
528
529 fprintf(output, shift);
530 fprintf(output, "%d", i + 1);
531 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
532}
Owen Taylor3473f882001-02-23 17:55:21 +0000533#if defined(LIBXML_XPTR_ENABLED)
534void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000535static void
536xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000537 int i;
538 char shift[100];
539
540 for (i = 0;((i < depth) && (i < 25));i++)
541 shift[2 * i] = shift[2 * i + 1] = ' ';
542 shift[2 * i] = shift[2 * i + 1] = 0;
543
544 if (cur == NULL) {
545 fprintf(output, shift);
546 fprintf(output, "LocationSet is NULL !\n");
547 return;
548
549 }
550
551 for (i = 0;i < cur->locNr;i++) {
552 fprintf(output, shift);
553 fprintf(output, "%d : ", i + 1);
554 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
555 }
556}
557#endif
558
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000559/**
560 * xmlXPathDebugDumpObject:
561 * @output: the FILE * to dump the output
562 * @cur: the object to inspect
563 * @depth: indentation level
564 *
565 * Dump the content of the object for debugging purposes
566 */
567void
568xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000569 int i;
570 char shift[100];
571
572 for (i = 0;((i < depth) && (i < 25));i++)
573 shift[2 * i] = shift[2 * i + 1] = ' ';
574 shift[2 * i] = shift[2 * i + 1] = 0;
575
576 fprintf(output, shift);
577
578 if (cur == NULL) {
579 fprintf(output, "Object is empty (NULL)\n");
580 return;
581 }
582 switch(cur->type) {
583 case XPATH_UNDEFINED:
584 fprintf(output, "Object is uninitialized\n");
585 break;
586 case XPATH_NODESET:
587 fprintf(output, "Object is a Node Set :\n");
588 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
589 break;
590 case XPATH_XSLT_TREE:
591 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000592 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000593 break;
594 case XPATH_BOOLEAN:
595 fprintf(output, "Object is a Boolean : ");
596 if (cur->boolval) fprintf(output, "true\n");
597 else fprintf(output, "false\n");
598 break;
599 case XPATH_NUMBER:
Daniel Veillard357c9602001-05-03 10:49:20 +0000600 switch (isinf(cur->floatval)) {
601 case 1:
602 fprintf(output, "Object is a number : +Infinity\n");
603 break;
604 case -1:
605 fprintf(output, "Object is a number : -Infinity\n");
606 break;
607 default:
608 if (isnan(cur->floatval)) {
609 fprintf(output, "Object is a number : NaN\n");
610 } else {
611 fprintf(output, "Object is a number : %0g\n", cur->floatval);
612 }
613 }
Owen Taylor3473f882001-02-23 17:55:21 +0000614 break;
615 case XPATH_STRING:
616 fprintf(output, "Object is a string : ");
617 xmlDebugDumpString(output, cur->stringval);
618 fprintf(output, "\n");
619 break;
620 case XPATH_POINT:
621 fprintf(output, "Object is a point : index %d in node", cur->index);
622 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
623 fprintf(output, "\n");
624 break;
625 case XPATH_RANGE:
626 if ((cur->user2 == NULL) ||
627 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
628 fprintf(output, "Object is a collapsed range :\n");
629 fprintf(output, shift);
630 if (cur->index >= 0)
631 fprintf(output, "index %d in ", cur->index);
632 fprintf(output, "node\n");
633 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
634 depth + 1);
635 } else {
636 fprintf(output, "Object is a range :\n");
637 fprintf(output, shift);
638 fprintf(output, "From ");
639 if (cur->index >= 0)
640 fprintf(output, "index %d in ", cur->index);
641 fprintf(output, "node\n");
642 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
643 depth + 1);
644 fprintf(output, shift);
645 fprintf(output, "To ");
646 if (cur->index2 >= 0)
647 fprintf(output, "index %d in ", cur->index2);
648 fprintf(output, "node\n");
649 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
650 depth + 1);
651 fprintf(output, "\n");
652 }
653 break;
654 case XPATH_LOCATIONSET:
655#if defined(LIBXML_XPTR_ENABLED)
656 fprintf(output, "Object is a Location Set:\n");
657 xmlXPathDebugDumpLocationSet(output,
658 (xmlLocationSetPtr) cur->user, depth);
659#endif
660 break;
661 case XPATH_USERS:
662 fprintf(output, "Object is user defined\n");
663 break;
664 }
665}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000666
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000667static void
668xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000669 xmlXPathStepOpPtr op, int depth) {
670 int i;
671 char shift[100];
672
673 for (i = 0;((i < depth) && (i < 25));i++)
674 shift[2 * i] = shift[2 * i + 1] = ' ';
675 shift[2 * i] = shift[2 * i + 1] = 0;
676
677 fprintf(output, shift);
678 if (op == NULL) {
679 fprintf(output, "Step is NULL\n");
680 return;
681 }
682 switch (op->op) {
683 case XPATH_OP_END:
684 fprintf(output, "END"); break;
685 case XPATH_OP_AND:
686 fprintf(output, "AND"); break;
687 case XPATH_OP_OR:
688 fprintf(output, "OR"); break;
689 case XPATH_OP_EQUAL:
690 if (op->value)
691 fprintf(output, "EQUAL =");
692 else
693 fprintf(output, "EQUAL !=");
694 break;
695 case XPATH_OP_CMP:
696 if (op->value)
697 fprintf(output, "CMP <");
698 else
699 fprintf(output, "CMP >");
700 if (!op->value2)
701 fprintf(output, "=");
702 break;
703 case XPATH_OP_PLUS:
704 if (op->value == 0)
705 fprintf(output, "PLUS -");
706 else if (op->value == 1)
707 fprintf(output, "PLUS +");
708 else if (op->value == 2)
709 fprintf(output, "PLUS unary -");
710 else if (op->value == 3)
711 fprintf(output, "PLUS unary - -");
712 break;
713 case XPATH_OP_MULT:
714 if (op->value == 0)
715 fprintf(output, "MULT *");
716 else if (op->value == 1)
717 fprintf(output, "MULT div");
718 else
719 fprintf(output, "MULT mod");
720 break;
721 case XPATH_OP_UNION:
722 fprintf(output, "UNION"); break;
723 case XPATH_OP_ROOT:
724 fprintf(output, "ROOT"); break;
725 case XPATH_OP_NODE:
726 fprintf(output, "NODE"); break;
727 case XPATH_OP_RESET:
728 fprintf(output, "RESET"); break;
729 case XPATH_OP_SORT:
730 fprintf(output, "SORT"); break;
731 case XPATH_OP_COLLECT: {
732 xmlXPathAxisVal axis = op->value;
733 xmlXPathTestVal test = op->value2;
734 xmlXPathTypeVal type = op->value3;
735 const xmlChar *prefix = op->value4;
736 const xmlChar *name = op->value5;
737
738 fprintf(output, "COLLECT ");
739 switch (axis) {
740 case AXIS_ANCESTOR:
741 fprintf(output, " 'ancestors' "); break;
742 case AXIS_ANCESTOR_OR_SELF:
743 fprintf(output, " 'ancestors-or-self' "); break;
744 case AXIS_ATTRIBUTE:
745 fprintf(output, " 'attributes' "); break;
746 case AXIS_CHILD:
747 fprintf(output, " 'child' "); break;
748 case AXIS_DESCENDANT:
749 fprintf(output, " 'descendant' "); break;
750 case AXIS_DESCENDANT_OR_SELF:
751 fprintf(output, " 'descendant-or-self' "); break;
752 case AXIS_FOLLOWING:
753 fprintf(output, " 'following' "); break;
754 case AXIS_FOLLOWING_SIBLING:
755 fprintf(output, " 'following-siblings' "); break;
756 case AXIS_NAMESPACE:
757 fprintf(output, " 'namespace' "); break;
758 case AXIS_PARENT:
759 fprintf(output, " 'parent' "); break;
760 case AXIS_PRECEDING:
761 fprintf(output, " 'preceding' "); break;
762 case AXIS_PRECEDING_SIBLING:
763 fprintf(output, " 'preceding-sibling' "); break;
764 case AXIS_SELF:
765 fprintf(output, " 'self' "); break;
766 }
767 switch (test) {
768 case NODE_TEST_NONE:
769 fprintf(output, "'none' "); break;
770 case NODE_TEST_TYPE:
771 fprintf(output, "'type' "); break;
772 case NODE_TEST_PI:
773 fprintf(output, "'PI' "); break;
774 case NODE_TEST_ALL:
775 fprintf(output, "'all' "); break;
776 case NODE_TEST_NS:
777 fprintf(output, "'namespace' "); break;
778 case NODE_TEST_NAME:
779 fprintf(output, "'name' "); break;
780 }
781 switch (type) {
782 case NODE_TYPE_NODE:
783 fprintf(output, "'node' "); break;
784 case NODE_TYPE_COMMENT:
785 fprintf(output, "'comment' "); break;
786 case NODE_TYPE_TEXT:
787 fprintf(output, "'text' "); break;
788 case NODE_TYPE_PI:
789 fprintf(output, "'PI' "); break;
790 }
791 if (prefix != NULL)
792 fprintf(output, "%s:", prefix);
793 if (name != NULL)
794 fprintf(output, "%s", name);
795 break;
796
797 }
798 case XPATH_OP_VALUE: {
799 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
800
801 fprintf(output, "ELEM ");
802 xmlXPathDebugDumpObject(output, object, 0);
803 goto finish;
804 }
805 case XPATH_OP_VARIABLE: {
806 const xmlChar *prefix = op->value5;
807 const xmlChar *name = op->value4;
808
809 if (prefix != NULL)
810 fprintf(output, "VARIABLE %s:%s", prefix, name);
811 else
812 fprintf(output, "VARIABLE %s", name);
813 break;
814 }
815 case XPATH_OP_FUNCTION: {
816 int nbargs = op->value;
817 const xmlChar *prefix = op->value5;
818 const xmlChar *name = op->value4;
819
820 if (prefix != NULL)
821 fprintf(output, "FUNCTION %s:%s(%d args)",
822 prefix, name, nbargs);
823 else
824 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
825 break;
826 }
827 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
828 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000829 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000830#ifdef LIBXML_XPTR_ENABLED
831 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
832#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000833 default:
834 fprintf(output, "UNKNOWN %d\n", op->op); return;
835 }
836 fprintf(output, "\n");
837finish:
838 if (op->ch1 >= 0)
839 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
840 if (op->ch2 >= 0)
841 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
842}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000843
844void
845xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
846 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000847 int i;
848 char shift[100];
849
850 for (i = 0;((i < depth) && (i < 25));i++)
851 shift[2 * i] = shift[2 * i + 1] = ' ';
852 shift[2 * i] = shift[2 * i + 1] = 0;
853
854 fprintf(output, shift);
855
856 if (comp == NULL) {
857 fprintf(output, "Compiled Expression is NULL\n");
858 return;
859 }
860 fprintf(output, "Compiled Expression : %d elements\n",
861 comp->nbStep);
862 i = comp->last;
863 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
864}
Owen Taylor3473f882001-02-23 17:55:21 +0000865#endif
866
867/************************************************************************
868 * *
869 * Parser stacks related functions and macros *
870 * *
871 ************************************************************************/
872
873/*
874 * Generic function for accessing stacks in the Parser Context
875 */
876
877#define PUSH_AND_POP(type, name) \
878extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
879 if (ctxt->name##Nr >= ctxt->name##Max) { \
880 ctxt->name##Max *= 2; \
881 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
882 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
883 if (ctxt->name##Tab == NULL) { \
884 xmlGenericError(xmlGenericErrorContext, \
885 "realloc failed !\n"); \
886 return(0); \
887 } \
888 } \
889 ctxt->name##Tab[ctxt->name##Nr] = value; \
890 ctxt->name = value; \
891 return(ctxt->name##Nr++); \
892} \
893extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
894 type ret; \
895 if (ctxt->name##Nr <= 0) return(0); \
896 ctxt->name##Nr--; \
897 if (ctxt->name##Nr > 0) \
898 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
899 else \
900 ctxt->name = NULL; \
901 ret = ctxt->name##Tab[ctxt->name##Nr]; \
902 ctxt->name##Tab[ctxt->name##Nr] = 0; \
903 return(ret); \
904} \
905
906PUSH_AND_POP(xmlXPathObjectPtr, value)
907
908/*
909 * Macros for accessing the content. Those should be used only by the parser,
910 * and not exported.
911 *
912 * Dirty macros, i.e. one need to make assumption on the context to use them
913 *
914 * CUR_PTR return the current pointer to the xmlChar to be parsed.
915 * CUR returns the current xmlChar value, i.e. a 8 bit value
916 * in ISO-Latin or UTF-8.
917 * This should be used internally by the parser
918 * only to compare to ASCII values otherwise it would break when
919 * running with UTF-8 encoding.
920 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
921 * to compare on ASCII based substring.
922 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
923 * strings within the parser.
924 * CURRENT Returns the current char value, with the full decoding of
925 * UTF-8 if we are using this mode. It returns an int.
926 * NEXT Skip to the next character, this does the proper decoding
927 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
928 * It returns the pointer to the current xmlChar.
929 */
930
931#define CUR (*ctxt->cur)
932#define SKIP(val) ctxt->cur += (val)
933#define NXT(val) ctxt->cur[(val)]
934#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +0000935#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
936
937#define COPY_BUF(l,b,i,v) \
938 if (l == 1) b[i++] = (xmlChar) v; \
939 else i += xmlCopyChar(l,&b[i],v)
940
941#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +0000942
943#define SKIP_BLANKS \
944 while (IS_BLANK(*(ctxt->cur))) NEXT
945
946#define CURRENT (*ctxt->cur)
947#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
948
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000949
950#ifndef DBL_DIG
951#define DBL_DIG 16
952#endif
953#ifndef DBL_EPSILON
954#define DBL_EPSILON 1E-9
955#endif
956
957#define UPPER_DOUBLE 1E9
958#define LOWER_DOUBLE 1E-5
959
960#define INTEGER_DIGITS DBL_DIG
961#define FRACTION_DIGITS (DBL_DIG + 1)
962#define EXPONENT_DIGITS (3 + 2)
963
964/**
965 * xmlXPathFormatNumber:
966 * @number: number to format
967 * @buffer: output buffer
968 * @buffersize: size of output buffer
969 *
970 * Convert the number into a string representation.
971 */
972static void
973xmlXPathFormatNumber(double number, char buffer[], int buffersize)
974{
975 switch (isinf(number)) {
976 case 1:
977 if (buffersize > (int)sizeof("+Infinity"))
978 sprintf(buffer, "+Infinity");
979 break;
980 case -1:
981 if (buffersize > (int)sizeof("-Infinity"))
982 sprintf(buffer, "-Infinity");
983 break;
984 default:
985 if (isnan(number)) {
986 if (buffersize > (int)sizeof("NaN"))
987 sprintf(buffer, "NaN");
988 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000989 /* 3 is sign, decimal point, and terminating zero */
990 char work[DBL_DIG + EXPONENT_DIGITS + 3];
991 int integer_place, fraction_place;
992 char *ptr;
993 char *after_fraction;
994 double absolute_value;
995 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000996
Bjorn Reese70a9da52001-04-21 16:57:29 +0000997 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000998
Bjorn Reese70a9da52001-04-21 16:57:29 +0000999 /*
1000 * First choose format - scientific or regular floating point.
1001 * In either case, result is in work, and after_fraction points
1002 * just past the fractional part.
1003 */
1004 if ( ((absolute_value > UPPER_DOUBLE) ||
1005 (absolute_value < LOWER_DOUBLE)) &&
1006 (absolute_value != 0.0) ) {
1007 /* Use scientific notation */
1008 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1009 fraction_place = DBL_DIG - 1;
1010 snprintf(work, sizeof(work),"%*.*e",
1011 integer_place, fraction_place, number);
1012 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001013 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001014 else {
1015 /* Use regular notation */
1016 integer_place = 1 + (int)log10(absolute_value);
1017 fraction_place = (integer_place > 0)
1018 ? DBL_DIG - integer_place
1019 : DBL_DIG;
1020 size = snprintf(work, sizeof(work), "%0.*f",
1021 fraction_place, number);
1022 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001023 }
1024
Bjorn Reese70a9da52001-04-21 16:57:29 +00001025 /* Remove fractional trailing zeroes */
1026 ptr = after_fraction;
1027 while (*(--ptr) == '0')
1028 ;
1029 if (*ptr != '.')
1030 ptr++;
1031 strcpy(ptr, after_fraction);
1032
1033 /* Finally copy result back to caller */
1034 size = strlen(work) + 1;
1035 if (size > buffersize) {
1036 work[buffersize - 1] = 0;
1037 size = buffersize;
1038 }
1039 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001040 }
1041 break;
1042 }
1043}
1044
Owen Taylor3473f882001-02-23 17:55:21 +00001045/************************************************************************
1046 * *
1047 * Error handling routines *
1048 * *
1049 ************************************************************************/
1050
1051
1052const char *xmlXPathErrorMessages[] = {
1053 "Ok",
1054 "Number encoding",
1055 "Unfinished litteral",
1056 "Start of litteral",
1057 "Expected $ for variable reference",
1058 "Undefined variable",
1059 "Invalid predicate",
1060 "Invalid expression",
1061 "Missing closing curly brace",
1062 "Unregistered function",
1063 "Invalid operand",
1064 "Invalid type",
1065 "Invalid number of arguments",
1066 "Invalid context size",
1067 "Invalid context position",
1068 "Memory allocation error",
1069 "Syntax error",
1070 "Resource error",
1071 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001072 "Undefined namespace prefix",
1073 "Encoding error",
1074 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001075};
1076
1077/**
1078 * xmlXPathError:
1079 * @ctxt: the XPath Parser context
1080 * @file: the file name
1081 * @line: the line number
1082 * @no: the error number
1083 *
1084 * Create a new xmlNodeSetPtr of type double and of value @val
1085 *
1086 * Returns the newly created object.
1087 */
1088void
1089xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1090 int line, int no) {
1091 int n;
1092 const xmlChar *cur;
1093 const xmlChar *base;
1094
1095 xmlGenericError(xmlGenericErrorContext,
1096 "Error %s:%d: %s\n", file, line,
1097 xmlXPathErrorMessages[no]);
1098
1099 cur = ctxt->cur;
1100 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001101 if ((cur == NULL) || (base == NULL))
1102 return;
1103
Owen Taylor3473f882001-02-23 17:55:21 +00001104 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1105 cur--;
1106 }
1107 n = 0;
1108 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1109 cur--;
1110 if ((*cur == '\n') || (*cur == '\r')) cur++;
1111 base = cur;
1112 n = 0;
1113 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1114 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1115 n++;
1116 }
1117 xmlGenericError(xmlGenericErrorContext, "\n");
1118 cur = ctxt->cur;
1119 while ((*cur == '\n') || (*cur == '\r'))
1120 cur--;
1121 n = 0;
1122 while ((cur != base) && (n++ < 80)) {
1123 xmlGenericError(xmlGenericErrorContext, " ");
1124 base++;
1125 }
1126 xmlGenericError(xmlGenericErrorContext,"^\n");
1127}
1128
1129
1130/************************************************************************
1131 * *
1132 * Routines to handle NodeSets *
1133 * *
1134 ************************************************************************/
1135
1136/**
1137 * xmlXPathCmpNodes:
1138 * @node1: the first node
1139 * @node2: the second node
1140 *
1141 * Compare two nodes w.r.t document order
1142 *
1143 * Returns -2 in case of error 1 if first point < second point, 0 if
1144 * that's the same node, -1 otherwise
1145 */
1146int
1147xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1148 int depth1, depth2;
1149 xmlNodePtr cur, root;
1150
1151 if ((node1 == NULL) || (node2 == NULL))
1152 return(-2);
1153 /*
1154 * a couple of optimizations which will avoid computations in most cases
1155 */
1156 if (node1 == node2)
1157 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001158 if ((node1->type == XML_NAMESPACE_DECL) ||
1159 (node2->type == XML_NAMESPACE_DECL))
1160 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001161 if (node1 == node2->prev)
1162 return(1);
1163 if (node1 == node2->next)
1164 return(-1);
1165
1166 /*
1167 * compute depth to root
1168 */
1169 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1170 if (cur == node1)
1171 return(1);
1172 depth2++;
1173 }
1174 root = cur;
1175 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1176 if (cur == node2)
1177 return(-1);
1178 depth1++;
1179 }
1180 /*
1181 * Distinct document (or distinct entities :-( ) case.
1182 */
1183 if (root != cur) {
1184 return(-2);
1185 }
1186 /*
1187 * get the nearest common ancestor.
1188 */
1189 while (depth1 > depth2) {
1190 depth1--;
1191 node1 = node1->parent;
1192 }
1193 while (depth2 > depth1) {
1194 depth2--;
1195 node2 = node2->parent;
1196 }
1197 while (node1->parent != node2->parent) {
1198 node1 = node1->parent;
1199 node2 = node2->parent;
1200 /* should not happen but just in case ... */
1201 if ((node1 == NULL) || (node2 == NULL))
1202 return(-2);
1203 }
1204 /*
1205 * Find who's first.
1206 */
1207 if (node1 == node2->next)
1208 return(-1);
1209 for (cur = node1->next;cur != NULL;cur = cur->next)
1210 if (cur == node2)
1211 return(1);
1212 return(-1); /* assume there is no sibling list corruption */
1213}
1214
1215/**
1216 * xmlXPathNodeSetSort:
1217 * @set: the node set
1218 *
1219 * Sort the node set in document order
1220 */
1221void
1222xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001223 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001224 xmlNodePtr tmp;
1225
1226 if (set == NULL)
1227 return;
1228
1229 /* Use Shell's sort to sort the node-set */
1230 len = set->nodeNr;
1231 for (incr = len / 2; incr > 0; incr /= 2) {
1232 for (i = incr; i < len; i++) {
1233 j = i - incr;
1234 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001235 if (xmlXPathCmpNodes(set->nodeTab[j],
1236 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001237 tmp = set->nodeTab[j];
1238 set->nodeTab[j] = set->nodeTab[j + incr];
1239 set->nodeTab[j + incr] = tmp;
1240 j -= incr;
1241 } else
1242 break;
1243 }
1244 }
1245 }
1246}
1247
1248#define XML_NODESET_DEFAULT 10
1249/**
1250 * xmlXPathNodeSetCreate:
1251 * @val: an initial xmlNodePtr, or NULL
1252 *
1253 * Create a new xmlNodeSetPtr of type double and of value @val
1254 *
1255 * Returns the newly created object.
1256 */
1257xmlNodeSetPtr
1258xmlXPathNodeSetCreate(xmlNodePtr val) {
1259 xmlNodeSetPtr ret;
1260
1261 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1262 if (ret == NULL) {
1263 xmlGenericError(xmlGenericErrorContext,
1264 "xmlXPathNewNodeSet: out of memory\n");
1265 return(NULL);
1266 }
1267 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1268 if (val != NULL) {
1269 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1270 sizeof(xmlNodePtr));
1271 if (ret->nodeTab == NULL) {
1272 xmlGenericError(xmlGenericErrorContext,
1273 "xmlXPathNewNodeSet: out of memory\n");
1274 return(NULL);
1275 }
1276 memset(ret->nodeTab, 0 ,
1277 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1278 ret->nodeMax = XML_NODESET_DEFAULT;
1279 ret->nodeTab[ret->nodeNr++] = val;
1280 }
1281 return(ret);
1282}
1283
1284/**
1285 * xmlXPathNodeSetAdd:
1286 * @cur: the initial node set
1287 * @val: a new xmlNodePtr
1288 *
1289 * add a new xmlNodePtr ot an existing NodeSet
1290 */
1291void
1292xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1293 int i;
1294
1295 if (val == NULL) return;
1296
1297 /*
1298 * check against doublons
1299 */
1300 for (i = 0;i < cur->nodeNr;i++)
1301 if (cur->nodeTab[i] == val) return;
1302
1303 /*
1304 * grow the nodeTab if needed
1305 */
1306 if (cur->nodeMax == 0) {
1307 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1308 sizeof(xmlNodePtr));
1309 if (cur->nodeTab == NULL) {
1310 xmlGenericError(xmlGenericErrorContext,
1311 "xmlXPathNodeSetAdd: out of memory\n");
1312 return;
1313 }
1314 memset(cur->nodeTab, 0 ,
1315 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1316 cur->nodeMax = XML_NODESET_DEFAULT;
1317 } else if (cur->nodeNr == cur->nodeMax) {
1318 xmlNodePtr *temp;
1319
1320 cur->nodeMax *= 2;
1321 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1322 sizeof(xmlNodePtr));
1323 if (temp == NULL) {
1324 xmlGenericError(xmlGenericErrorContext,
1325 "xmlXPathNodeSetAdd: out of memory\n");
1326 return;
1327 }
1328 cur->nodeTab = temp;
1329 }
1330 cur->nodeTab[cur->nodeNr++] = val;
1331}
1332
1333/**
1334 * xmlXPathNodeSetAddUnique:
1335 * @cur: the initial node set
1336 * @val: a new xmlNodePtr
1337 *
1338 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1339 * when we are sure the node is not already in the set.
1340 */
1341void
1342xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1343 if (val == NULL) return;
1344
1345 /*
1346 * grow the nodeTab if needed
1347 */
1348 if (cur->nodeMax == 0) {
1349 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1350 sizeof(xmlNodePtr));
1351 if (cur->nodeTab == NULL) {
1352 xmlGenericError(xmlGenericErrorContext,
1353 "xmlXPathNodeSetAddUnique: out of memory\n");
1354 return;
1355 }
1356 memset(cur->nodeTab, 0 ,
1357 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1358 cur->nodeMax = XML_NODESET_DEFAULT;
1359 } else if (cur->nodeNr == cur->nodeMax) {
1360 xmlNodePtr *temp;
1361
1362 cur->nodeMax *= 2;
1363 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1364 sizeof(xmlNodePtr));
1365 if (temp == NULL) {
1366 xmlGenericError(xmlGenericErrorContext,
1367 "xmlXPathNodeSetAddUnique: out of memory\n");
1368 return;
1369 }
1370 cur->nodeTab = temp;
1371 }
1372 cur->nodeTab[cur->nodeNr++] = val;
1373}
1374
1375/**
1376 * xmlXPathNodeSetMerge:
1377 * @val1: the first NodeSet or NULL
1378 * @val2: the second NodeSet
1379 *
1380 * Merges two nodesets, all nodes from @val2 are added to @val1
1381 * if @val1 is NULL, a new set is created and copied from @val2
1382 *
1383 * Returns val1 once extended or NULL in case of error.
1384 */
1385xmlNodeSetPtr
1386xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001387 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001388
1389 if (val2 == NULL) return(val1);
1390 if (val1 == NULL) {
1391 val1 = xmlXPathNodeSetCreate(NULL);
1392 }
1393
1394 initNr = val1->nodeNr;
1395
1396 for (i = 0;i < val2->nodeNr;i++) {
1397 /*
1398 * check against doublons
1399 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001400 skip = 0;
1401 for (j = 0; j < initNr; j++) {
1402 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1403 skip = 1;
1404 break;
1405 }
1406 }
1407 if (skip)
1408 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001409
1410 /*
1411 * grow the nodeTab if needed
1412 */
1413 if (val1->nodeMax == 0) {
1414 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1415 sizeof(xmlNodePtr));
1416 if (val1->nodeTab == NULL) {
1417 xmlGenericError(xmlGenericErrorContext,
1418 "xmlXPathNodeSetMerge: out of memory\n");
1419 return(NULL);
1420 }
1421 memset(val1->nodeTab, 0 ,
1422 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1423 val1->nodeMax = XML_NODESET_DEFAULT;
1424 } else if (val1->nodeNr == val1->nodeMax) {
1425 xmlNodePtr *temp;
1426
1427 val1->nodeMax *= 2;
1428 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1429 sizeof(xmlNodePtr));
1430 if (temp == NULL) {
1431 xmlGenericError(xmlGenericErrorContext,
1432 "xmlXPathNodeSetMerge: out of memory\n");
1433 return(NULL);
1434 }
1435 val1->nodeTab = temp;
1436 }
1437 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1438 }
1439
1440 return(val1);
1441}
1442
1443/**
1444 * xmlXPathNodeSetDel:
1445 * @cur: the initial node set
1446 * @val: an xmlNodePtr
1447 *
1448 * Removes an xmlNodePtr from an existing NodeSet
1449 */
1450void
1451xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1452 int i;
1453
1454 if (cur == NULL) return;
1455 if (val == NULL) return;
1456
1457 /*
1458 * check against doublons
1459 */
1460 for (i = 0;i < cur->nodeNr;i++)
1461 if (cur->nodeTab[i] == val) break;
1462
1463 if (i >= cur->nodeNr) {
1464#ifdef DEBUG
1465 xmlGenericError(xmlGenericErrorContext,
1466 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1467 val->name);
1468#endif
1469 return;
1470 }
1471 cur->nodeNr--;
1472 for (;i < cur->nodeNr;i++)
1473 cur->nodeTab[i] = cur->nodeTab[i + 1];
1474 cur->nodeTab[cur->nodeNr] = NULL;
1475}
1476
1477/**
1478 * xmlXPathNodeSetRemove:
1479 * @cur: the initial node set
1480 * @val: the index to remove
1481 *
1482 * Removes an entry from an existing NodeSet list.
1483 */
1484void
1485xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1486 if (cur == NULL) return;
1487 if (val >= cur->nodeNr) return;
1488 cur->nodeNr--;
1489 for (;val < cur->nodeNr;val++)
1490 cur->nodeTab[val] = cur->nodeTab[val + 1];
1491 cur->nodeTab[cur->nodeNr] = NULL;
1492}
1493
1494/**
1495 * xmlXPathFreeNodeSet:
1496 * @obj: the xmlNodeSetPtr to free
1497 *
1498 * Free the NodeSet compound (not the actual nodes !).
1499 */
1500void
1501xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1502 if (obj == NULL) return;
1503 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001504 xmlFree(obj->nodeTab);
1505 }
Owen Taylor3473f882001-02-23 17:55:21 +00001506 xmlFree(obj);
1507}
1508
1509/**
1510 * xmlXPathFreeValueTree:
1511 * @obj: the xmlNodeSetPtr to free
1512 *
1513 * Free the NodeSet compound and the actual tree, this is different
1514 * from xmlXPathFreeNodeSet()
1515 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001516static void
Owen Taylor3473f882001-02-23 17:55:21 +00001517xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1518 int i;
1519
1520 if (obj == NULL) return;
1521 for (i = 0;i < obj->nodeNr;i++)
1522 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001523 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001524
1525 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001526 xmlFree(obj->nodeTab);
1527 }
Owen Taylor3473f882001-02-23 17:55:21 +00001528 xmlFree(obj);
1529}
1530
1531#if defined(DEBUG) || defined(DEBUG_STEP)
1532/**
1533 * xmlGenericErrorContextNodeSet:
1534 * @output: a FILE * for the output
1535 * @obj: the xmlNodeSetPtr to free
1536 *
1537 * Quick display of a NodeSet
1538 */
1539void
1540xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1541 int i;
1542
1543 if (output == NULL) output = xmlGenericErrorContext;
1544 if (obj == NULL) {
1545 fprintf(output, "NodeSet == NULL !\n");
1546 return;
1547 }
1548 if (obj->nodeNr == 0) {
1549 fprintf(output, "NodeSet is empty\n");
1550 return;
1551 }
1552 if (obj->nodeTab == NULL) {
1553 fprintf(output, " nodeTab == NULL !\n");
1554 return;
1555 }
1556 for (i = 0; i < obj->nodeNr; i++) {
1557 if (obj->nodeTab[i] == NULL) {
1558 fprintf(output, " NULL !\n");
1559 return;
1560 }
1561 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1562 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1563 fprintf(output, " /");
1564 else if (obj->nodeTab[i]->name == NULL)
1565 fprintf(output, " noname!");
1566 else fprintf(output, " %s", obj->nodeTab[i]->name);
1567 }
1568 fprintf(output, "\n");
1569}
1570#endif
1571
1572/**
1573 * xmlXPathNewNodeSet:
1574 * @val: the NodePtr value
1575 *
1576 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1577 * it with the single Node @val
1578 *
1579 * Returns the newly created object.
1580 */
1581xmlXPathObjectPtr
1582xmlXPathNewNodeSet(xmlNodePtr val) {
1583 xmlXPathObjectPtr ret;
1584
1585 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1586 if (ret == NULL) {
1587 xmlGenericError(xmlGenericErrorContext,
1588 "xmlXPathNewNodeSet: out of memory\n");
1589 return(NULL);
1590 }
1591 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1592 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001593 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001594 ret->nodesetval = xmlXPathNodeSetCreate(val);
1595 return(ret);
1596}
1597
1598/**
1599 * xmlXPathNewValueTree:
1600 * @val: the NodePtr value
1601 *
1602 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1603 * it with the tree root @val
1604 *
1605 * Returns the newly created object.
1606 */
1607xmlXPathObjectPtr
1608xmlXPathNewValueTree(xmlNodePtr val) {
1609 xmlXPathObjectPtr ret;
1610
1611 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1612 if (ret == NULL) {
1613 xmlGenericError(xmlGenericErrorContext,
1614 "xmlXPathNewNodeSet: out of memory\n");
1615 return(NULL);
1616 }
1617 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1618 ret->type = XPATH_XSLT_TREE;
1619 ret->nodesetval = xmlXPathNodeSetCreate(val);
1620 return(ret);
1621}
1622
1623/**
1624 * xmlXPathNewNodeSetList:
1625 * @val: an existing NodeSet
1626 *
1627 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1628 * it with the Nodeset @val
1629 *
1630 * Returns the newly created object.
1631 */
1632xmlXPathObjectPtr
1633xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1634 xmlXPathObjectPtr ret;
1635 int i;
1636
1637 if (val == NULL)
1638 ret = NULL;
1639 else if (val->nodeTab == NULL)
1640 ret = xmlXPathNewNodeSet(NULL);
1641 else
1642 {
1643 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1644 for (i = 1; i < val->nodeNr; ++i)
1645 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1646 }
1647
1648 return(ret);
1649}
1650
1651/**
1652 * xmlXPathWrapNodeSet:
1653 * @val: the NodePtr value
1654 *
1655 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1656 *
1657 * Returns the newly created object.
1658 */
1659xmlXPathObjectPtr
1660xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1661 xmlXPathObjectPtr ret;
1662
1663 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1664 if (ret == NULL) {
1665 xmlGenericError(xmlGenericErrorContext,
1666 "xmlXPathWrapNodeSet: out of memory\n");
1667 return(NULL);
1668 }
1669 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1670 ret->type = XPATH_NODESET;
1671 ret->nodesetval = val;
1672 return(ret);
1673}
1674
1675/**
1676 * xmlXPathFreeNodeSetList:
1677 * @obj: an existing NodeSetList object
1678 *
1679 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1680 * the list contrary to xmlXPathFreeObject().
1681 */
1682void
1683xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1684 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001685 xmlFree(obj);
1686}
1687
1688/************************************************************************
1689 * *
1690 * Routines to handle extra functions *
1691 * *
1692 ************************************************************************/
1693
1694/**
1695 * xmlXPathRegisterFunc:
1696 * @ctxt: the XPath context
1697 * @name: the function name
1698 * @f: the function implementation or NULL
1699 *
1700 * Register a new function. If @f is NULL it unregisters the function
1701 *
1702 * Returns 0 in case of success, -1 in case of error
1703 */
1704int
1705xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1706 xmlXPathFunction f) {
1707 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1708}
1709
1710/**
1711 * xmlXPathRegisterFuncNS:
1712 * @ctxt: the XPath context
1713 * @name: the function name
1714 * @ns_uri: the function namespace URI
1715 * @f: the function implementation or NULL
1716 *
1717 * Register a new function. If @f is NULL it unregisters the function
1718 *
1719 * Returns 0 in case of success, -1 in case of error
1720 */
1721int
1722xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1723 const xmlChar *ns_uri, xmlXPathFunction f) {
1724 if (ctxt == NULL)
1725 return(-1);
1726 if (name == NULL)
1727 return(-1);
1728
1729 if (ctxt->funcHash == NULL)
1730 ctxt->funcHash = xmlHashCreate(0);
1731 if (ctxt->funcHash == NULL)
1732 return(-1);
1733 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1734}
1735
1736/**
1737 * xmlXPathFunctionLookup:
1738 * @ctxt: the XPath context
1739 * @name: the function name
1740 *
1741 * Search in the Function array of the context for the given
1742 * function.
1743 *
1744 * Returns the xmlXPathFunction or NULL if not found
1745 */
1746xmlXPathFunction
1747xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1748 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1749}
1750
1751/**
1752 * xmlXPathFunctionLookupNS:
1753 * @ctxt: the XPath context
1754 * @name: the function name
1755 * @ns_uri: the function namespace URI
1756 *
1757 * Search in the Function array of the context for the given
1758 * function.
1759 *
1760 * Returns the xmlXPathFunction or NULL if not found
1761 */
1762xmlXPathFunction
1763xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1764 const xmlChar *ns_uri) {
1765 if (ctxt == NULL)
1766 return(NULL);
1767 if (ctxt->funcHash == NULL)
1768 return(NULL);
1769 if (name == NULL)
1770 return(NULL);
1771
1772 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1773}
1774
1775/**
1776 * xmlXPathRegisteredFuncsCleanup:
1777 * @ctxt: the XPath context
1778 *
1779 * Cleanup the XPath context data associated to registered functions
1780 */
1781void
1782xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1783 if (ctxt == NULL)
1784 return;
1785
1786 xmlHashFree(ctxt->funcHash, NULL);
1787 ctxt->funcHash = NULL;
1788}
1789
1790/************************************************************************
1791 * *
1792 * Routines to handle Variable *
1793 * *
1794 ************************************************************************/
1795
1796/**
1797 * xmlXPathRegisterVariable:
1798 * @ctxt: the XPath context
1799 * @name: the variable name
1800 * @value: the variable value or NULL
1801 *
1802 * Register a new variable value. If @value is NULL it unregisters
1803 * the variable
1804 *
1805 * Returns 0 in case of success, -1 in case of error
1806 */
1807int
1808xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1809 xmlXPathObjectPtr value) {
1810 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1811}
1812
1813/**
1814 * xmlXPathRegisterVariableNS:
1815 * @ctxt: the XPath context
1816 * @name: the variable name
1817 * @ns_uri: the variable namespace URI
1818 * @value: the variable value or NULL
1819 *
1820 * Register a new variable value. If @value is NULL it unregisters
1821 * the variable
1822 *
1823 * Returns 0 in case of success, -1 in case of error
1824 */
1825int
1826xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1827 const xmlChar *ns_uri,
1828 xmlXPathObjectPtr value) {
1829 if (ctxt == NULL)
1830 return(-1);
1831 if (name == NULL)
1832 return(-1);
1833
1834 if (ctxt->varHash == NULL)
1835 ctxt->varHash = xmlHashCreate(0);
1836 if (ctxt->varHash == NULL)
1837 return(-1);
1838 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1839 (void *) value,
1840 (xmlHashDeallocator)xmlXPathFreeObject));
1841}
1842
1843/**
1844 * xmlXPathRegisterVariableLookup:
1845 * @ctxt: the XPath context
1846 * @f: the lookup function
1847 * @data: the lookup data
1848 *
1849 * register an external mechanism to do variable lookup
1850 */
1851void
1852xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1853 xmlXPathVariableLookupFunc f, void *data) {
1854 if (ctxt == NULL)
1855 return;
1856 ctxt->varLookupFunc = (void *) f;
1857 ctxt->varLookupData = data;
1858}
1859
1860/**
1861 * xmlXPathVariableLookup:
1862 * @ctxt: the XPath context
1863 * @name: the variable name
1864 *
1865 * Search in the Variable array of the context for the given
1866 * variable value.
1867 *
1868 * Returns the value or NULL if not found
1869 */
1870xmlXPathObjectPtr
1871xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1872 if (ctxt == NULL)
1873 return(NULL);
1874
1875 if (ctxt->varLookupFunc != NULL) {
1876 xmlXPathObjectPtr ret;
1877
1878 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1879 (ctxt->varLookupData, name, NULL);
1880 if (ret != NULL) return(ret);
1881 }
1882 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1883}
1884
1885/**
1886 * xmlXPathVariableLookupNS:
1887 * @ctxt: the XPath context
1888 * @name: the variable name
1889 * @ns_uri: the variable namespace URI
1890 *
1891 * Search in the Variable array of the context for the given
1892 * variable value.
1893 *
1894 * Returns the value or NULL if not found
1895 */
1896xmlXPathObjectPtr
1897xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1898 const xmlChar *ns_uri) {
1899 if (ctxt == NULL)
1900 return(NULL);
1901
1902 if (ctxt->varLookupFunc != NULL) {
1903 xmlXPathObjectPtr ret;
1904
1905 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1906 (ctxt->varLookupData, name, ns_uri);
1907 if (ret != NULL) return(ret);
1908 }
1909
1910 if (ctxt->varHash == NULL)
1911 return(NULL);
1912 if (name == NULL)
1913 return(NULL);
1914
1915 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1916}
1917
1918/**
1919 * xmlXPathRegisteredVariablesCleanup:
1920 * @ctxt: the XPath context
1921 *
1922 * Cleanup the XPath context data associated to registered variables
1923 */
1924void
1925xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1926 if (ctxt == NULL)
1927 return;
1928
Daniel Veillard76d66f42001-05-16 21:05:17 +00001929 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00001930 ctxt->varHash = NULL;
1931}
1932
1933/**
1934 * xmlXPathRegisterNs:
1935 * @ctxt: the XPath context
1936 * @prefix: the namespace prefix
1937 * @ns_uri: the namespace name
1938 *
1939 * Register a new namespace. If @ns_uri is NULL it unregisters
1940 * the namespace
1941 *
1942 * Returns 0 in case of success, -1 in case of error
1943 */
1944int
1945xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1946 const xmlChar *ns_uri) {
1947 if (ctxt == NULL)
1948 return(-1);
1949 if (prefix == NULL)
1950 return(-1);
1951
1952 if (ctxt->nsHash == NULL)
1953 ctxt->nsHash = xmlHashCreate(10);
1954 if (ctxt->nsHash == NULL)
1955 return(-1);
1956 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1957 (xmlHashDeallocator)xmlFree));
1958}
1959
1960/**
1961 * xmlXPathNsLookup:
1962 * @ctxt: the XPath context
1963 * @prefix: the namespace prefix value
1964 *
1965 * Search in the namespace declaration array of the context for the given
1966 * namespace name associated to the given prefix
1967 *
1968 * Returns the value or NULL if not found
1969 */
1970const xmlChar *
1971xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1972 if (ctxt == NULL)
1973 return(NULL);
1974 if (prefix == NULL)
1975 return(NULL);
1976
1977#ifdef XML_XML_NAMESPACE
1978 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1979 return(XML_XML_NAMESPACE);
1980#endif
1981
Daniel Veillardc8f620b2001-04-30 20:31:33 +00001982 if (ctxt->namespaces != NULL) {
1983 int i;
1984
1985 for (i = 0;i < ctxt->nsNr;i++) {
1986 if ((ctxt->namespaces[i] != NULL) &&
1987 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
1988 return(ctxt->namespaces[i]->href);
1989 }
1990 }
Owen Taylor3473f882001-02-23 17:55:21 +00001991
1992 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1993}
1994
1995/**
1996 * xmlXPathRegisteredVariablesCleanup:
1997 * @ctxt: the XPath context
1998 *
1999 * Cleanup the XPath context data associated to registered variables
2000 */
2001void
2002xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2003 if (ctxt == NULL)
2004 return;
2005
2006 xmlHashFree(ctxt->nsHash, NULL);
2007 ctxt->nsHash = NULL;
2008}
2009
2010/************************************************************************
2011 * *
2012 * Routines to handle Values *
2013 * *
2014 ************************************************************************/
2015
2016/* Allocations are terrible, one need to optimize all this !!! */
2017
2018/**
2019 * xmlXPathNewFloat:
2020 * @val: the double value
2021 *
2022 * Create a new xmlXPathObjectPtr of type double and of value @val
2023 *
2024 * Returns the newly created object.
2025 */
2026xmlXPathObjectPtr
2027xmlXPathNewFloat(double val) {
2028 xmlXPathObjectPtr ret;
2029
2030 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2031 if (ret == NULL) {
2032 xmlGenericError(xmlGenericErrorContext,
2033 "xmlXPathNewFloat: out of memory\n");
2034 return(NULL);
2035 }
2036 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2037 ret->type = XPATH_NUMBER;
2038 ret->floatval = val;
2039 return(ret);
2040}
2041
2042/**
2043 * xmlXPathNewBoolean:
2044 * @val: the boolean value
2045 *
2046 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2047 *
2048 * Returns the newly created object.
2049 */
2050xmlXPathObjectPtr
2051xmlXPathNewBoolean(int val) {
2052 xmlXPathObjectPtr ret;
2053
2054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2055 if (ret == NULL) {
2056 xmlGenericError(xmlGenericErrorContext,
2057 "xmlXPathNewBoolean: out of memory\n");
2058 return(NULL);
2059 }
2060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2061 ret->type = XPATH_BOOLEAN;
2062 ret->boolval = (val != 0);
2063 return(ret);
2064}
2065
2066/**
2067 * xmlXPathNewString:
2068 * @val: the xmlChar * value
2069 *
2070 * Create a new xmlXPathObjectPtr of type string and of value @val
2071 *
2072 * Returns the newly created object.
2073 */
2074xmlXPathObjectPtr
2075xmlXPathNewString(const xmlChar *val) {
2076 xmlXPathObjectPtr ret;
2077
2078 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2079 if (ret == NULL) {
2080 xmlGenericError(xmlGenericErrorContext,
2081 "xmlXPathNewString: out of memory\n");
2082 return(NULL);
2083 }
2084 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2085 ret->type = XPATH_STRING;
2086 if (val != NULL)
2087 ret->stringval = xmlStrdup(val);
2088 else
2089 ret->stringval = xmlStrdup((const xmlChar *)"");
2090 return(ret);
2091}
2092
2093/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002094 * xmlXPathWrapString:
2095 * @val: the xmlChar * value
2096 *
2097 * Wraps the @val string into an XPath object.
2098 *
2099 * Returns the newly created object.
2100 */
2101xmlXPathObjectPtr
2102xmlXPathWrapString (xmlChar *val) {
2103 xmlXPathObjectPtr ret;
2104
2105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2106 if (ret == NULL) {
2107 xmlGenericError(xmlGenericErrorContext,
2108 "xmlXPathWrapString: out of memory\n");
2109 return(NULL);
2110 }
2111 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2112 ret->type = XPATH_STRING;
2113 ret->stringval = val;
2114 return(ret);
2115}
2116
2117/**
Owen Taylor3473f882001-02-23 17:55:21 +00002118 * xmlXPathNewCString:
2119 * @val: the char * value
2120 *
2121 * Create a new xmlXPathObjectPtr of type string and of value @val
2122 *
2123 * Returns the newly created object.
2124 */
2125xmlXPathObjectPtr
2126xmlXPathNewCString(const char *val) {
2127 xmlXPathObjectPtr ret;
2128
2129 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2130 if (ret == NULL) {
2131 xmlGenericError(xmlGenericErrorContext,
2132 "xmlXPathNewCString: out of memory\n");
2133 return(NULL);
2134 }
2135 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2136 ret->type = XPATH_STRING;
2137 ret->stringval = xmlStrdup(BAD_CAST val);
2138 return(ret);
2139}
2140
2141/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002142 * xmlXPathWrapCString:
2143 * @val: the char * value
2144 *
2145 * Wraps a string into an XPath object.
2146 *
2147 * Returns the newly created object.
2148 */
2149xmlXPathObjectPtr
2150xmlXPathWrapCString (char * val) {
2151 return(xmlXPathWrapString((xmlChar *)(val)));
2152}
2153
2154/**
Owen Taylor3473f882001-02-23 17:55:21 +00002155 * xmlXPathObjectCopy:
2156 * @val: the original object
2157 *
2158 * allocate a new copy of a given object
2159 *
2160 * Returns the newly created object.
2161 */
2162xmlXPathObjectPtr
2163xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2164 xmlXPathObjectPtr ret;
2165
2166 if (val == NULL)
2167 return(NULL);
2168
2169 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2170 if (ret == NULL) {
2171 xmlGenericError(xmlGenericErrorContext,
2172 "xmlXPathObjectCopy: out of memory\n");
2173 return(NULL);
2174 }
2175 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2176 switch (val->type) {
2177 case XPATH_BOOLEAN:
2178 case XPATH_NUMBER:
2179 case XPATH_POINT:
2180 case XPATH_RANGE:
2181 break;
2182 case XPATH_STRING:
2183 ret->stringval = xmlStrdup(val->stringval);
2184 break;
2185 case XPATH_XSLT_TREE:
2186 if ((val->nodesetval != NULL) &&
2187 (val->nodesetval->nodeTab != NULL))
2188 ret->nodesetval = xmlXPathNodeSetCreate(
2189 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2190 else
2191 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2192 break;
2193 case XPATH_NODESET:
2194 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2195 break;
2196 case XPATH_LOCATIONSET:
2197#ifdef LIBXML_XPTR_ENABLED
2198 {
2199 xmlLocationSetPtr loc = val->user;
2200 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2201 break;
2202 }
2203#endif
2204 case XPATH_UNDEFINED:
2205 case XPATH_USERS:
2206 xmlGenericError(xmlGenericErrorContext,
2207 "xmlXPathObjectCopy: unsupported type %d\n",
2208 val->type);
2209 break;
2210 }
2211 return(ret);
2212}
2213
2214/**
2215 * xmlXPathFreeObject:
2216 * @obj: the object to free
2217 *
2218 * Free up an xmlXPathObjectPtr object.
2219 */
2220void
2221xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2222 if (obj == NULL) return;
2223 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002224 if (obj->boolval) {
2225 obj->type = XPATH_XSLT_TREE;
2226 if (obj->nodesetval != NULL)
2227 xmlXPathFreeValueTree(obj->nodesetval);
2228 } else {
2229 if (obj->nodesetval != NULL)
2230 xmlXPathFreeNodeSet(obj->nodesetval);
2231 }
Owen Taylor3473f882001-02-23 17:55:21 +00002232#ifdef LIBXML_XPTR_ENABLED
2233 } else if (obj->type == XPATH_LOCATIONSET) {
2234 if (obj->user != NULL)
2235 xmlXPtrFreeLocationSet(obj->user);
2236#endif
2237 } else if (obj->type == XPATH_STRING) {
2238 if (obj->stringval != NULL)
2239 xmlFree(obj->stringval);
2240 } else if (obj->type == XPATH_XSLT_TREE) {
2241 if (obj->nodesetval != NULL)
2242 xmlXPathFreeValueTree(obj->nodesetval);
2243 }
2244
Owen Taylor3473f882001-02-23 17:55:21 +00002245 xmlFree(obj);
2246}
2247
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002248
2249/************************************************************************
2250 * *
2251 * Type Casting Routines *
2252 * *
2253 ************************************************************************/
2254
2255/**
2256 * xmlXPathCastBooleanToString:
2257 * @val: a boolean
2258 *
2259 * Converts a boolean to its string value.
2260 *
2261 * Returns a newly allocated string.
2262 */
2263xmlChar *
2264xmlXPathCastBooleanToString (int val) {
2265 xmlChar *ret;
2266 if (val)
2267 ret = xmlStrdup((const xmlChar *) "true");
2268 else
2269 ret = xmlStrdup((const xmlChar *) "false");
2270 return(ret);
2271}
2272
2273/**
2274 * xmlXPathCastNumberToString:
2275 * @val: a number
2276 *
2277 * Converts a number to its string value.
2278 *
2279 * Returns a newly allocated string.
2280 */
2281xmlChar *
2282xmlXPathCastNumberToString (double val) {
2283 xmlChar *ret;
2284 switch (isinf(val)) {
2285 case 1:
2286 ret = xmlStrdup((const xmlChar *) "+Infinity");
2287 break;
2288 case -1:
2289 ret = xmlStrdup((const xmlChar *) "-Infinity");
2290 break;
2291 default:
2292 if (isnan(val)) {
2293 ret = xmlStrdup((const xmlChar *) "NaN");
2294 } else {
2295 /* could be improved */
2296 char buf[100];
2297 xmlXPathFormatNumber(val, buf, 100);
2298 ret = xmlStrdup((const xmlChar *) buf);
2299 }
2300 }
2301 return(ret);
2302}
2303
2304/**
2305 * xmlXPathCastNodeToString:
2306 * @node: a node
2307 *
2308 * Converts a node to its string value.
2309 *
2310 * Returns a newly allocated string.
2311 */
2312xmlChar *
2313xmlXPathCastNodeToString (xmlNodePtr node) {
2314 return(xmlNodeGetContent(node));
2315}
2316
2317/**
2318 * xmlXPathCastNodeSetToString:
2319 * @ns: a node-set
2320 *
2321 * Converts a node-set to its string value.
2322 *
2323 * Returns a newly allocated string.
2324 */
2325xmlChar *
2326xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2327 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2328 return(xmlStrdup((const xmlChar *) ""));
2329
2330 xmlXPathNodeSetSort(ns);
2331 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2332}
2333
2334/**
2335 * xmlXPathCastToString:
2336 * @val: an XPath object
2337 *
2338 * Converts an existing object to its string() equivalent
2339 *
2340 * Returns the string value of the object, NULL in case of error.
2341 * A new string is allocated only if needed (val isn't a
2342 * string object).
2343 */
2344xmlChar *
2345xmlXPathCastToString(xmlXPathObjectPtr val) {
2346 xmlChar *ret = NULL;
2347
2348 if (val == NULL)
2349 return(xmlStrdup((const xmlChar *) ""));
2350 switch (val->type) {
2351 case XPATH_UNDEFINED:
2352#ifdef DEBUG_EXPR
2353 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2354#endif
2355 ret = xmlStrdup((const xmlChar *) "");
2356 break;
2357 case XPATH_XSLT_TREE:
2358 case XPATH_NODESET:
2359 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2360 break;
2361 case XPATH_STRING:
2362 return(val->stringval);
2363 case XPATH_BOOLEAN:
2364 ret = xmlXPathCastBooleanToString(val->boolval);
2365 break;
2366 case XPATH_NUMBER: {
2367 ret = xmlXPathCastNumberToString(val->floatval);
2368 break;
2369 }
2370 case XPATH_USERS:
2371 case XPATH_POINT:
2372 case XPATH_RANGE:
2373 case XPATH_LOCATIONSET:
2374 TODO
2375 ret = xmlStrdup((const xmlChar *) "");
2376 break;
2377 }
2378 return(ret);
2379}
2380
2381/**
2382 * xmlXPathConvertString:
2383 * @val: an XPath object
2384 *
2385 * Converts an existing object to its string() equivalent
2386 *
2387 * Returns the new object, the old one is freed (or the operation
2388 * is done directly on @val)
2389 */
2390xmlXPathObjectPtr
2391xmlXPathConvertString(xmlXPathObjectPtr val) {
2392 xmlChar *res = NULL;
2393
2394 if (val == NULL)
2395 return(xmlXPathNewCString(""));
2396
2397 switch (val->type) {
2398 case XPATH_UNDEFINED:
2399#ifdef DEBUG_EXPR
2400 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2401#endif
2402 break;
2403 case XPATH_XSLT_TREE:
2404 case XPATH_NODESET:
2405 res = xmlXPathCastNodeSetToString(val->nodesetval);
2406 break;
2407 case XPATH_STRING:
2408 return(val);
2409 case XPATH_BOOLEAN:
2410 res = xmlXPathCastBooleanToString(val->boolval);
2411 break;
2412 case XPATH_NUMBER:
2413 res = xmlXPathCastNumberToString(val->floatval);
2414 break;
2415 case XPATH_USERS:
2416 case XPATH_POINT:
2417 case XPATH_RANGE:
2418 case XPATH_LOCATIONSET:
2419 TODO;
2420 break;
2421 }
2422 xmlXPathFreeObject(val);
2423 if (res == NULL)
2424 return(xmlXPathNewCString(""));
2425 return(xmlXPathWrapString(res));
2426}
2427
2428/**
2429 * xmlXPathCastBooleanToNumber:
2430 * @val: a boolean
2431 *
2432 * Converts a boolean to its number value
2433 *
2434 * Returns the number value
2435 */
2436double
2437xmlXPathCastBooleanToNumber(int val) {
2438 if (val)
2439 return(1.0);
2440 return(0.0);
2441}
2442
2443/**
2444 * xmlXPathCastStringToNumber:
2445 * @val: a string
2446 *
2447 * Converts a string to its number value
2448 *
2449 * Returns the number value
2450 */
2451double
2452xmlXPathCastStringToNumber(const xmlChar * val) {
2453 return(xmlXPathStringEvalNumber(val));
2454}
2455
2456/**
2457 * xmlXPathCastNodeToNumber:
2458 * @node: a node
2459 *
2460 * Converts a node to its number value
2461 *
2462 * Returns the number value
2463 */
2464double
2465xmlXPathCastNodeToNumber (xmlNodePtr node) {
2466 xmlChar *strval;
2467 double ret;
2468
2469 if (node == NULL)
2470 return(xmlXPathNAN);
2471 strval = xmlXPathCastNodeToString(node);
2472 if (strval == NULL)
2473 return(xmlXPathNAN);
2474 ret = xmlXPathCastStringToNumber(strval);
2475 xmlFree(strval);
2476
2477 return(ret);
2478}
2479
2480/**
2481 * xmlXPathCastNodeSetToNumber:
2482 * @ns: a node-set
2483 *
2484 * Converts a node-set to its number value
2485 *
2486 * Returns the number value
2487 */
2488double
2489xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
2490 xmlChar *str;
2491 double ret;
2492
2493 if (ns == NULL)
2494 return(xmlXPathNAN);
2495 str = xmlXPathCastNodeSetToString(ns);
2496 ret = xmlXPathCastStringToNumber(str);
2497 xmlFree(str);
2498 return(ret);
2499}
2500
2501/**
2502 * xmlXPathCastToNumber:
2503 * @val: an XPath object
2504 *
2505 * Converts an XPath object to its number value
2506 *
2507 * Returns the number value
2508 */
2509double
2510xmlXPathCastToNumber(xmlXPathObjectPtr val) {
2511 double ret = 0.0;
2512
2513 if (val == NULL)
2514 return(xmlXPathNAN);
2515 switch (val->type) {
2516 case XPATH_UNDEFINED:
2517#ifdef DEGUB_EXPR
2518 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
2519#endif
2520 ret = xmlXPathNAN;
2521 break;
2522 case XPATH_XSLT_TREE:
2523 case XPATH_NODESET:
2524 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
2525 break;
2526 case XPATH_STRING:
2527 ret = xmlXPathCastStringToNumber(val->stringval);
2528 break;
2529 case XPATH_NUMBER:
2530 ret = val->floatval;
2531 break;
2532 case XPATH_BOOLEAN:
2533 ret = xmlXPathCastBooleanToNumber(val->boolval);
2534 break;
2535 case XPATH_USERS:
2536 case XPATH_POINT:
2537 case XPATH_RANGE:
2538 case XPATH_LOCATIONSET:
2539 TODO;
2540 ret = xmlXPathNAN;
2541 break;
2542 }
2543 return(ret);
2544}
2545
2546/**
2547 * xmlXPathConvertNumber:
2548 * @val: an XPath object
2549 *
2550 * Converts an existing object to its number() equivalent
2551 *
2552 * Returns the new object, the old one is freed (or the operation
2553 * is done directly on @val)
2554 */
2555xmlXPathObjectPtr
2556xmlXPathConvertNumber(xmlXPathObjectPtr val) {
2557 xmlXPathObjectPtr ret;
2558
2559 if (val == NULL)
2560 return(xmlXPathNewFloat(0.0));
2561 if (val->type == XPATH_NUMBER)
2562 return(val);
2563 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
2564 xmlXPathFreeObject(val);
2565 return(ret);
2566}
2567
2568/**
2569 * xmlXPathCastNumberToBoolean:
2570 * @val: a number
2571 *
2572 * Converts a number to its boolean value
2573 *
2574 * Returns the boolean value
2575 */
2576int
2577xmlXPathCastNumberToBoolean (double val) {
2578 if (isnan(val) || (val == 0.0))
2579 return(0);
2580 return(1);
2581}
2582
2583/**
2584 * xmlXPathCastStringToBoolean:
2585 * @val: a string
2586 *
2587 * Converts a string to its boolean value
2588 *
2589 * Returns the boolean value
2590 */
2591int
2592xmlXPathCastStringToBoolean (const xmlChar *val) {
2593 if ((val == NULL) || (xmlStrlen(val) == 0))
2594 return(0);
2595 return(1);
2596}
2597
2598/**
2599 * xmlXPathCastNodeSetToBoolean:
2600 * @ns: a node-set
2601 *
2602 * Converts a node-set to its boolean value
2603 *
2604 * Returns the boolean value
2605 */
2606int
2607xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
2608 if ((ns == NULL) || (ns->nodeNr == 0))
2609 return(0);
2610 return(1);
2611}
2612
2613/**
2614 * xmlXpathCastToBoolean:
2615 * @val: an XPath object
2616 *
2617 * Converts an XPath object to its boolean value
2618 *
2619 * Returns the boolean value
2620 */
2621int
2622xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
2623 int ret = 0;
2624
2625 if (val == NULL)
2626 return(0);
2627 switch (val->type) {
2628 case XPATH_UNDEFINED:
2629#ifdef DEBUG_EXPR
2630 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
2631#endif
2632 ret = 0;
2633 break;
2634 case XPATH_XSLT_TREE:
2635 case XPATH_NODESET:
2636 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
2637 break;
2638 case XPATH_STRING:
2639 ret = xmlXPathCastStringToBoolean(val->stringval);
2640 break;
2641 case XPATH_NUMBER:
2642 ret = xmlXPathCastNumberToBoolean(val->floatval);
2643 break;
2644 case XPATH_BOOLEAN:
2645 ret = val->boolval;
2646 break;
2647 case XPATH_USERS:
2648 case XPATH_POINT:
2649 case XPATH_RANGE:
2650 case XPATH_LOCATIONSET:
2651 TODO;
2652 ret = 0;
2653 break;
2654 }
2655 return(ret);
2656}
2657
2658
2659/**
2660 * xmlXPathConvertBoolean:
2661 * @val: an XPath object
2662 *
2663 * Converts an existing object to its boolean() equivalent
2664 *
2665 * Returns the new object, the old one is freed (or the operation
2666 * is done directly on @val)
2667 */
2668xmlXPathObjectPtr
2669xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
2670 xmlXPathObjectPtr ret;
2671
2672 if (val == NULL)
2673 return(xmlXPathNewBoolean(0));
2674 if (val->type == XPATH_BOOLEAN)
2675 return(val);
2676 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
2677 xmlXPathFreeObject(val);
2678 return(ret);
2679}
2680
Owen Taylor3473f882001-02-23 17:55:21 +00002681/************************************************************************
2682 * *
2683 * Routines to handle XPath contexts *
2684 * *
2685 ************************************************************************/
2686
2687/**
2688 * xmlXPathNewContext:
2689 * @doc: the XML document
2690 *
2691 * Create a new xmlXPathContext
2692 *
2693 * Returns the xmlXPathContext just allocated.
2694 */
2695xmlXPathContextPtr
2696xmlXPathNewContext(xmlDocPtr doc) {
2697 xmlXPathContextPtr ret;
2698
2699 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2700 if (ret == NULL) {
2701 xmlGenericError(xmlGenericErrorContext,
2702 "xmlXPathNewContext: out of memory\n");
2703 return(NULL);
2704 }
2705 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2706 ret->doc = doc;
2707 ret->node = NULL;
2708
2709 ret->varHash = NULL;
2710
2711 ret->nb_types = 0;
2712 ret->max_types = 0;
2713 ret->types = NULL;
2714
2715 ret->funcHash = xmlHashCreate(0);
2716
2717 ret->nb_axis = 0;
2718 ret->max_axis = 0;
2719 ret->axis = NULL;
2720
2721 ret->nsHash = NULL;
2722 ret->user = NULL;
2723
2724 ret->contextSize = -1;
2725 ret->proximityPosition = -1;
2726
2727 xmlXPathRegisterAllFunctions(ret);
2728
2729 return(ret);
2730}
2731
2732/**
2733 * xmlXPathFreeContext:
2734 * @ctxt: the context to free
2735 *
2736 * Free up an xmlXPathContext
2737 */
2738void
2739xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2740 xmlXPathRegisteredNsCleanup(ctxt);
2741 xmlXPathRegisteredFuncsCleanup(ctxt);
2742 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002743 xmlFree(ctxt);
2744}
2745
2746/************************************************************************
2747 * *
2748 * Routines to handle XPath parser contexts *
2749 * *
2750 ************************************************************************/
2751
2752#define CHECK_CTXT(ctxt) \
2753 if (ctxt == NULL) { \
2754 xmlGenericError(xmlGenericErrorContext, \
2755 "%s:%d Internal error: ctxt == NULL\n", \
2756 __FILE__, __LINE__); \
2757 } \
2758
2759
2760#define CHECK_CONTEXT(ctxt) \
2761 if (ctxt == NULL) { \
2762 xmlGenericError(xmlGenericErrorContext, \
2763 "%s:%d Internal error: no context\n", \
2764 __FILE__, __LINE__); \
2765 } \
2766 else if (ctxt->doc == NULL) { \
2767 xmlGenericError(xmlGenericErrorContext, \
2768 "%s:%d Internal error: no document\n", \
2769 __FILE__, __LINE__); \
2770 } \
2771 else if (ctxt->doc->children == NULL) { \
2772 xmlGenericError(xmlGenericErrorContext, \
2773 "%s:%d Internal error: document without root\n", \
2774 __FILE__, __LINE__); \
2775 } \
2776
2777
2778/**
2779 * xmlXPathNewParserContext:
2780 * @str: the XPath expression
2781 * @ctxt: the XPath context
2782 *
2783 * Create a new xmlXPathParserContext
2784 *
2785 * Returns the xmlXPathParserContext just allocated.
2786 */
2787xmlXPathParserContextPtr
2788xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2789 xmlXPathParserContextPtr ret;
2790
2791 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2792 if (ret == NULL) {
2793 xmlGenericError(xmlGenericErrorContext,
2794 "xmlXPathNewParserContext: out of memory\n");
2795 return(NULL);
2796 }
2797 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2798 ret->cur = ret->base = str;
2799 ret->context = ctxt;
2800
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002801 ret->comp = xmlXPathNewCompExpr();
2802 if (ret->comp == NULL) {
2803 xmlFree(ret->valueTab);
2804 xmlFree(ret);
2805 return(NULL);
2806 }
2807
2808 return(ret);
2809}
2810
2811/**
2812 * xmlXPathCompParserContext:
2813 * @comp: the XPath compiled expression
2814 * @ctxt: the XPath context
2815 *
2816 * Create a new xmlXPathParserContext when processing a compiled expression
2817 *
2818 * Returns the xmlXPathParserContext just allocated.
2819 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002820static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002821xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2822 xmlXPathParserContextPtr ret;
2823
2824 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2825 if (ret == NULL) {
2826 xmlGenericError(xmlGenericErrorContext,
2827 "xmlXPathNewParserContext: out of memory\n");
2828 return(NULL);
2829 }
2830 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2831
Owen Taylor3473f882001-02-23 17:55:21 +00002832 /* Allocate the value stack */
2833 ret->valueTab = (xmlXPathObjectPtr *)
2834 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002835 if (ret->valueTab == NULL) {
2836 xmlFree(ret);
2837 xmlGenericError(xmlGenericErrorContext,
2838 "xmlXPathNewParserContext: out of memory\n");
2839 return(NULL);
2840 }
Owen Taylor3473f882001-02-23 17:55:21 +00002841 ret->valueNr = 0;
2842 ret->valueMax = 10;
2843 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002844
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002845 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002846 ret->comp = comp;
2847
Owen Taylor3473f882001-02-23 17:55:21 +00002848 return(ret);
2849}
2850
2851/**
2852 * xmlXPathFreeParserContext:
2853 * @ctxt: the context to free
2854 *
2855 * Free up an xmlXPathParserContext
2856 */
2857void
2858xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2859 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002860 xmlFree(ctxt->valueTab);
2861 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002862 if (ctxt->comp)
2863 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002864 xmlFree(ctxt);
2865}
2866
2867/************************************************************************
2868 * *
2869 * The implicit core function library *
2870 * *
2871 ************************************************************************/
2872
Owen Taylor3473f882001-02-23 17:55:21 +00002873/**
2874 * xmlXPathCompareNodeSetFloat:
2875 * @ctxt: the XPath Parser context
2876 * @inf: less than (1) or greater than (0)
2877 * @strict: is the comparison strict
2878 * @arg: the node set
2879 * @f: the value
2880 *
2881 * Implement the compare operation between a nodeset and a number
2882 * @ns < @val (1, 1, ...
2883 * @ns <= @val (1, 0, ...
2884 * @ns > @val (0, 1, ...
2885 * @ns >= @val (0, 0, ...
2886 *
2887 * If one object to be compared is a node-set and the other is a number,
2888 * then the comparison will be true if and only if there is a node in the
2889 * node-set such that the result of performing the comparison on the number
2890 * to be compared and on the result of converting the string-value of that
2891 * node to a number using the number function is true.
2892 *
2893 * Returns 0 or 1 depending on the results of the test.
2894 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002895static int
Owen Taylor3473f882001-02-23 17:55:21 +00002896xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2897 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2898 int i, ret = 0;
2899 xmlNodeSetPtr ns;
2900 xmlChar *str2;
2901
2902 if ((f == NULL) || (arg == NULL) ||
2903 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2904 xmlXPathFreeObject(arg);
2905 xmlXPathFreeObject(f);
2906 return(0);
2907 }
2908 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002909 if (ns != NULL) {
2910 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002911 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002912 if (str2 != NULL) {
2913 valuePush(ctxt,
2914 xmlXPathNewString(str2));
2915 xmlFree(str2);
2916 xmlXPathNumberFunction(ctxt, 1);
2917 valuePush(ctxt, xmlXPathObjectCopy(f));
2918 ret = xmlXPathCompareValues(ctxt, inf, strict);
2919 if (ret)
2920 break;
2921 }
2922 }
Owen Taylor3473f882001-02-23 17:55:21 +00002923 }
2924 xmlXPathFreeObject(arg);
2925 xmlXPathFreeObject(f);
2926 return(ret);
2927}
2928
2929/**
2930 * xmlXPathCompareNodeSetString:
2931 * @ctxt: the XPath Parser context
2932 * @inf: less than (1) or greater than (0)
2933 * @strict: is the comparison strict
2934 * @arg: the node set
2935 * @s: the value
2936 *
2937 * Implement the compare operation between a nodeset and a string
2938 * @ns < @val (1, 1, ...
2939 * @ns <= @val (1, 0, ...
2940 * @ns > @val (0, 1, ...
2941 * @ns >= @val (0, 0, ...
2942 *
2943 * If one object to be compared is a node-set and the other is a string,
2944 * then the comparison will be true if and only if there is a node in
2945 * the node-set such that the result of performing the comparison on the
2946 * string-value of the node and the other string is true.
2947 *
2948 * Returns 0 or 1 depending on the results of the test.
2949 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002950static int
Owen Taylor3473f882001-02-23 17:55:21 +00002951xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2952 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2953 int i, ret = 0;
2954 xmlNodeSetPtr ns;
2955 xmlChar *str2;
2956
2957 if ((s == NULL) || (arg == NULL) ||
2958 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2959 xmlXPathFreeObject(arg);
2960 xmlXPathFreeObject(s);
2961 return(0);
2962 }
2963 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002964 if (ns != NULL) {
2965 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002966 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002967 if (str2 != NULL) {
2968 valuePush(ctxt,
2969 xmlXPathNewString(str2));
2970 xmlFree(str2);
2971 valuePush(ctxt, xmlXPathObjectCopy(s));
2972 ret = xmlXPathCompareValues(ctxt, inf, strict);
2973 if (ret)
2974 break;
2975 }
2976 }
Owen Taylor3473f882001-02-23 17:55:21 +00002977 }
2978 xmlXPathFreeObject(arg);
2979 xmlXPathFreeObject(s);
2980 return(ret);
2981}
2982
2983/**
2984 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002985 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00002986 * @strict: is the comparison strict
2987 * @arg1: the fist node set object
2988 * @arg2: the second node set object
2989 *
2990 * Implement the compare operation on nodesets:
2991 *
2992 * If both objects to be compared are node-sets, then the comparison
2993 * will be true if and only if there is a node in the first node-set
2994 * and a node in the second node-set such that the result of performing
2995 * the comparison on the string-values of the two nodes is true.
2996 * ....
2997 * When neither object to be compared is a node-set and the operator
2998 * is <=, <, >= or >, then the objects are compared by converting both
2999 * objects to numbers and comparing the numbers according to IEEE 754.
3000 * ....
3001 * The number function converts its argument to a number as follows:
3002 * - a string that consists of optional whitespace followed by an
3003 * optional minus sign followed by a Number followed by whitespace
3004 * is converted to the IEEE 754 number that is nearest (according
3005 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3006 * represented by the string; any other string is converted to NaN
3007 *
3008 * Conclusion all nodes need to be converted first to their string value
3009 * and then the comparison must be done when possible
3010 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003011static int
3012xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003013 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3014 int i, j, init = 0;
3015 double val1;
3016 double *values2;
3017 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003018 xmlNodeSetPtr ns1;
3019 xmlNodeSetPtr ns2;
3020
3021 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003022 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3023 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003024 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003025 }
Owen Taylor3473f882001-02-23 17:55:21 +00003026 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003027 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3028 xmlXPathFreeObject(arg1);
3029 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003030 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003031 }
Owen Taylor3473f882001-02-23 17:55:21 +00003032
3033 ns1 = arg1->nodesetval;
3034 ns2 = arg2->nodesetval;
3035
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003036 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003037 xmlXPathFreeObject(arg1);
3038 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003039 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003040 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003041 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003042 xmlXPathFreeObject(arg1);
3043 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003044 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003045 }
Owen Taylor3473f882001-02-23 17:55:21 +00003046
3047 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3048 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003049 xmlXPathFreeObject(arg1);
3050 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003051 return(0);
3052 }
3053 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003054 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003055 if (isnan(val1))
3056 continue;
3057 for (j = 0;j < ns2->nodeNr;j++) {
3058 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003059 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003060 }
3061 if (isnan(values2[j]))
3062 continue;
3063 if (inf && strict)
3064 ret = (val1 < values2[j]);
3065 else if (inf && !strict)
3066 ret = (val1 <= values2[j]);
3067 else if (!inf && strict)
3068 ret = (val1 > values2[j]);
3069 else if (!inf && !strict)
3070 ret = (val1 >= values2[j]);
3071 if (ret)
3072 break;
3073 }
3074 if (ret)
3075 break;
3076 init = 1;
3077 }
3078 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003079 xmlXPathFreeObject(arg1);
3080 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003081 return(ret);
3082 return(0);
3083}
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;
4843 double le, in;
4844 int i, l;
4845 xmlChar *ret;
4846
4847 /*
Daniel Veillarde043ee12001-04-16 14:08:07 +00004848 * TODO: need to be converted to UTF8 strings
Owen Taylor3473f882001-02-23 17:55:21 +00004849 */
4850 if (nargs < 2) {
4851 CHECK_ARITY(2);
4852 }
4853 if (nargs > 3) {
4854 CHECK_ARITY(3);
4855 }
4856 if (nargs == 3) {
4857 CAST_TO_NUMBER;
4858 CHECK_TYPE(XPATH_NUMBER);
4859 len = valuePop(ctxt);
4860 le = len->floatval;
4861 xmlXPathFreeObject(len);
4862 } else {
4863 le = 2000000000;
4864 }
4865 CAST_TO_NUMBER;
4866 CHECK_TYPE(XPATH_NUMBER);
4867 start = valuePop(ctxt);
4868 in = start->floatval;
4869 xmlXPathFreeObject(start);
4870 CAST_TO_STRING;
4871 CHECK_TYPE(XPATH_STRING);
4872 str = valuePop(ctxt);
4873 le += in;
4874
4875 /* integer index of the first char */
4876 i = (int) in;
4877 if (((double)i) != in) i++;
4878
4879 /* integer index of the last char */
4880 l = (int) le;
4881 if (((double)l) != le) l++;
4882
4883 /* back to a zero based len */
4884 i--;
4885 l--;
4886
4887 /* check against the string len */
4888 if (l > 1024) {
4889 l = xmlStrlen(str->stringval);
4890 }
4891 if (i < 0) {
4892 i = 0;
4893 }
4894
4895 /* number of chars to copy */
4896 l -= i;
4897
4898 ret = xmlStrsub(str->stringval, i, l);
4899 if (ret == NULL)
4900 valuePush(ctxt, xmlXPathNewCString(""));
4901 else {
4902 valuePush(ctxt, xmlXPathNewString(ret));
4903 xmlFree(ret);
4904 }
4905 xmlXPathFreeObject(str);
4906}
4907
4908/**
4909 * xmlXPathSubstringBeforeFunction:
4910 * @ctxt: the XPath Parser context
4911 * @nargs: the number of arguments
4912 *
4913 * Implement the substring-before() XPath function
4914 * string substring-before(string, string)
4915 * The substring-before function returns the substring of the first
4916 * argument string that precedes the first occurrence of the second
4917 * argument string in the first argument string, or the empty string
4918 * if the first argument string does not contain the second argument
4919 * string. For example, substring-before("1999/04/01","/") returns 1999.
4920 */
4921void
4922xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4923 xmlXPathObjectPtr str;
4924 xmlXPathObjectPtr find;
4925 xmlBufferPtr target;
4926 const xmlChar *point;
4927 int offset;
4928
4929 CHECK_ARITY(2);
4930 CAST_TO_STRING;
4931 find = valuePop(ctxt);
4932 CAST_TO_STRING;
4933 str = valuePop(ctxt);
4934
4935 target = xmlBufferCreate();
4936 if (target) {
4937 point = xmlStrstr(str->stringval, find->stringval);
4938 if (point) {
4939 offset = (int)(point - str->stringval);
4940 xmlBufferAdd(target, str->stringval, offset);
4941 }
4942 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4943 xmlBufferFree(target);
4944 }
4945
4946 xmlXPathFreeObject(str);
4947 xmlXPathFreeObject(find);
4948}
4949
4950/**
4951 * xmlXPathSubstringAfterFunction:
4952 * @ctxt: the XPath Parser context
4953 * @nargs: the number of arguments
4954 *
4955 * Implement the substring-after() XPath function
4956 * string substring-after(string, string)
4957 * The substring-after function returns the substring of the first
4958 * argument string that follows the first occurrence of the second
4959 * argument string in the first argument string, or the empty stringi
4960 * if the first argument string does not contain the second argument
4961 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4962 * and substring-after("1999/04/01","19") returns 99/04/01.
4963 */
4964void
4965xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4966 xmlXPathObjectPtr str;
4967 xmlXPathObjectPtr find;
4968 xmlBufferPtr target;
4969 const xmlChar *point;
4970 int offset;
4971
4972 CHECK_ARITY(2);
4973 CAST_TO_STRING;
4974 find = valuePop(ctxt);
4975 CAST_TO_STRING;
4976 str = valuePop(ctxt);
4977
4978 target = xmlBufferCreate();
4979 if (target) {
4980 point = xmlStrstr(str->stringval, find->stringval);
4981 if (point) {
4982 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4983 xmlBufferAdd(target, &str->stringval[offset],
4984 xmlStrlen(str->stringval) - offset);
4985 }
4986 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4987 xmlBufferFree(target);
4988 }
4989
4990 xmlXPathFreeObject(str);
4991 xmlXPathFreeObject(find);
4992}
4993
4994/**
4995 * xmlXPathNormalizeFunction:
4996 * @ctxt: the XPath Parser context
4997 * @nargs: the number of arguments
4998 *
4999 * Implement the normalize-space() XPath function
5000 * string normalize-space(string?)
5001 * The normalize-space function returns the argument string with white
5002 * space normalized by stripping leading and trailing whitespace
5003 * and replacing sequences of whitespace characters by a single
5004 * space. Whitespace characters are the same allowed by the S production
5005 * in XML. If the argument is omitted, it defaults to the context
5006 * node converted to a string, in other words the value of the context node.
5007 */
5008void
5009xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5010 xmlXPathObjectPtr obj = NULL;
5011 xmlChar *source = NULL;
5012 xmlBufferPtr target;
5013 xmlChar blank;
5014
5015 if (nargs == 0) {
5016 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005017 valuePush(ctxt,
5018 xmlXPathWrapString(
5019 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005020 nargs = 1;
5021 }
5022
5023 CHECK_ARITY(1);
5024 CAST_TO_STRING;
5025 CHECK_TYPE(XPATH_STRING);
5026 obj = valuePop(ctxt);
5027 source = obj->stringval;
5028
5029 target = xmlBufferCreate();
5030 if (target && source) {
5031
5032 /* Skip leading whitespaces */
5033 while (IS_BLANK(*source))
5034 source++;
5035
5036 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5037 blank = 0;
5038 while (*source) {
5039 if (IS_BLANK(*source)) {
5040 blank = *source;
5041 } else {
5042 if (blank) {
5043 xmlBufferAdd(target, &blank, 1);
5044 blank = 0;
5045 }
5046 xmlBufferAdd(target, source, 1);
5047 }
5048 source++;
5049 }
5050
5051 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5052 xmlBufferFree(target);
5053 }
5054 xmlXPathFreeObject(obj);
5055}
5056
5057/**
5058 * xmlXPathTranslateFunction:
5059 * @ctxt: the XPath Parser context
5060 * @nargs: the number of arguments
5061 *
5062 * Implement the translate() XPath function
5063 * string translate(string, string, string)
5064 * The translate function returns the first argument string with
5065 * occurrences of characters in the second argument string replaced
5066 * by the character at the corresponding position in the third argument
5067 * string. For example, translate("bar","abc","ABC") returns the string
5068 * BAr. If there is a character in the second argument string with no
5069 * character at a corresponding position in the third argument string
5070 * (because the second argument string is longer than the third argument
5071 * string), then occurrences of that character in the first argument
5072 * string are removed. For example, translate("--aaa--","abc-","ABC")
5073 * returns "AAA". If a character occurs more than once in second
5074 * argument string, then the first occurrence determines the replacement
5075 * character. If the third argument string is longer than the second
5076 * argument string, then excess characters are ignored.
5077 */
5078void
5079xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005080 xmlXPathObjectPtr str;
5081 xmlXPathObjectPtr from;
5082 xmlXPathObjectPtr to;
5083 xmlBufferPtr target;
5084 int i, offset, max;
5085 xmlChar ch;
5086 const xmlChar *point;
Owen Taylor3473f882001-02-23 17:55:21 +00005087
Daniel Veillarde043ee12001-04-16 14:08:07 +00005088 /*
5089 * TODO: need to be converted to UTF8 strings
5090 */
5091 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005092
Daniel Veillarde043ee12001-04-16 14:08:07 +00005093 CAST_TO_STRING;
5094 to = valuePop(ctxt);
5095 CAST_TO_STRING;
5096 from = valuePop(ctxt);
5097 CAST_TO_STRING;
5098 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005099
Daniel Veillarde043ee12001-04-16 14:08:07 +00005100 target = xmlBufferCreate();
5101 if (target) {
5102 max = xmlStrlen(to->stringval);
5103 for (i = 0; (ch = str->stringval[i]); i++) {
5104 point = xmlStrchr(from->stringval, ch);
5105 if (point) {
5106 offset = (int)(point - from->stringval);
5107 if (offset < max)
5108 xmlBufferAdd(target, &to->stringval[offset], 1);
5109 } else
5110 xmlBufferAdd(target, &ch, 1);
5111 }
Owen Taylor3473f882001-02-23 17:55:21 +00005112 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005113 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5114 xmlBufferFree(target);
5115 xmlXPathFreeObject(str);
5116 xmlXPathFreeObject(from);
5117 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005118}
5119
5120/**
5121 * xmlXPathBooleanFunction:
5122 * @ctxt: the XPath Parser context
5123 * @nargs: the number of arguments
5124 *
5125 * Implement the boolean() XPath function
5126 * boolean boolean(object)
5127 * he boolean function converts its argument to a boolean as follows:
5128 * - a number is true if and only if it is neither positive or
5129 * negative zero nor NaN
5130 * - a node-set is true if and only if it is non-empty
5131 * - a string is true if and only if its length is non-zero
5132 */
5133void
5134xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5135 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005136
5137 CHECK_ARITY(1);
5138 cur = valuePop(ctxt);
5139 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005140 cur = xmlXPathConvertBoolean(cur);
5141 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005142}
5143
5144/**
5145 * xmlXPathNotFunction:
5146 * @ctxt: the XPath Parser context
5147 * @nargs: the number of arguments
5148 *
5149 * Implement the not() XPath function
5150 * boolean not(boolean)
5151 * The not function returns true if its argument is false,
5152 * and false otherwise.
5153 */
5154void
5155xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5156 CHECK_ARITY(1);
5157 CAST_TO_BOOLEAN;
5158 CHECK_TYPE(XPATH_BOOLEAN);
5159 ctxt->value->boolval = ! ctxt->value->boolval;
5160}
5161
5162/**
5163 * xmlXPathTrueFunction:
5164 * @ctxt: the XPath Parser context
5165 * @nargs: the number of arguments
5166 *
5167 * Implement the true() XPath function
5168 * boolean true()
5169 */
5170void
5171xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5172 CHECK_ARITY(0);
5173 valuePush(ctxt, xmlXPathNewBoolean(1));
5174}
5175
5176/**
5177 * xmlXPathFalseFunction:
5178 * @ctxt: the XPath Parser context
5179 * @nargs: the number of arguments
5180 *
5181 * Implement the false() XPath function
5182 * boolean false()
5183 */
5184void
5185xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5186 CHECK_ARITY(0);
5187 valuePush(ctxt, xmlXPathNewBoolean(0));
5188}
5189
5190/**
5191 * xmlXPathLangFunction:
5192 * @ctxt: the XPath Parser context
5193 * @nargs: the number of arguments
5194 *
5195 * Implement the lang() XPath function
5196 * boolean lang(string)
5197 * The lang function returns true or false depending on whether the
5198 * language of the context node as specified by xml:lang attributes
5199 * is the same as or is a sublanguage of the language specified by
5200 * the argument string. The language of the context node is determined
5201 * by the value of the xml:lang attribute on the context node, or, if
5202 * the context node has no xml:lang attribute, by the value of the
5203 * xml:lang attribute on the nearest ancestor of the context node that
5204 * has an xml:lang attribute. If there is no such attribute, then lang
5205 * returns false. If there is such an attribute, then lang returns
5206 * true if the attribute value is equal to the argument ignoring case,
5207 * or if there is some suffix starting with - such that the attribute
5208 * value is equal to the argument ignoring that suffix of the attribute
5209 * value and ignoring case.
5210 */
5211void
5212xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5213 xmlXPathObjectPtr val;
5214 const xmlChar *theLang;
5215 const xmlChar *lang;
5216 int ret = 0;
5217 int i;
5218
5219 CHECK_ARITY(1);
5220 CAST_TO_STRING;
5221 CHECK_TYPE(XPATH_STRING);
5222 val = valuePop(ctxt);
5223 lang = val->stringval;
5224 theLang = xmlNodeGetLang(ctxt->context->node);
5225 if ((theLang != NULL) && (lang != NULL)) {
5226 for (i = 0;lang[i] != 0;i++)
5227 if (toupper(lang[i]) != toupper(theLang[i]))
5228 goto not_equal;
5229 ret = 1;
5230 }
5231not_equal:
5232 xmlXPathFreeObject(val);
5233 valuePush(ctxt, xmlXPathNewBoolean(ret));
5234}
5235
5236/**
5237 * xmlXPathNumberFunction:
5238 * @ctxt: the XPath Parser context
5239 * @nargs: the number of arguments
5240 *
5241 * Implement the number() XPath function
5242 * number number(object?)
5243 */
5244void
5245xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5246 xmlXPathObjectPtr cur;
5247 double res;
5248
5249 if (nargs == 0) {
5250 if (ctxt->context->node == NULL) {
5251 valuePush(ctxt, xmlXPathNewFloat(0.0));
5252 } else {
5253 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
5254
5255 res = xmlXPathStringEvalNumber(content);
5256 valuePush(ctxt, xmlXPathNewFloat(res));
5257 xmlFree(content);
5258 }
5259 return;
5260 }
5261
5262 CHECK_ARITY(1);
5263 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005264 cur = xmlXPathConvertNumber(cur);
5265 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005266}
5267
5268/**
5269 * xmlXPathSumFunction:
5270 * @ctxt: the XPath Parser context
5271 * @nargs: the number of arguments
5272 *
5273 * Implement the sum() XPath function
5274 * number sum(node-set)
5275 * The sum function returns the sum of the values of the nodes in
5276 * the argument node-set.
5277 */
5278void
5279xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5280 xmlXPathObjectPtr cur;
5281 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005282 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00005283
5284 CHECK_ARITY(1);
5285 if ((ctxt->value == NULL) ||
5286 ((ctxt->value->type != XPATH_NODESET) &&
5287 (ctxt->value->type != XPATH_XSLT_TREE)))
5288 XP_ERROR(XPATH_INVALID_TYPE);
5289 cur = valuePop(ctxt);
5290
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005291 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005292 valuePush(ctxt, xmlXPathNewFloat(0.0));
5293 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005294 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
5295 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00005296 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005297 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00005298 }
5299 xmlXPathFreeObject(cur);
5300}
5301
5302/**
5303 * xmlXPathFloorFunction:
5304 * @ctxt: the XPath Parser context
5305 * @nargs: the number of arguments
5306 *
5307 * Implement the floor() XPath function
5308 * number floor(number)
5309 * The floor function returns the largest (closest to positive infinity)
5310 * number that is not greater than the argument and that is an integer.
5311 */
5312void
5313xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5314 CHECK_ARITY(1);
5315 CAST_TO_NUMBER;
5316 CHECK_TYPE(XPATH_NUMBER);
5317#if 0
5318 ctxt->value->floatval = floor(ctxt->value->floatval);
5319#else
5320 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5321 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5322#endif
5323}
5324
5325/**
5326 * xmlXPathCeilingFunction:
5327 * @ctxt: the XPath Parser context
5328 * @nargs: the number of arguments
5329 *
5330 * Implement the ceiling() XPath function
5331 * number ceiling(number)
5332 * The ceiling function returns the smallest (closest to negative infinity)
5333 * number that is not less than the argument and that is an integer.
5334 */
5335void
5336xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5337 double f;
5338
5339 CHECK_ARITY(1);
5340 CAST_TO_NUMBER;
5341 CHECK_TYPE(XPATH_NUMBER);
5342
5343#if 0
5344 ctxt->value->floatval = ceil(ctxt->value->floatval);
5345#else
5346 f = (double)((int) ctxt->value->floatval);
5347 if (f != ctxt->value->floatval)
5348 ctxt->value->floatval = f + 1;
5349#endif
5350}
5351
5352/**
5353 * xmlXPathRoundFunction:
5354 * @ctxt: the XPath Parser context
5355 * @nargs: the number of arguments
5356 *
5357 * Implement the round() XPath function
5358 * number round(number)
5359 * The round function returns the number that is closest to the
5360 * argument and that is an integer. If there are two such numbers,
5361 * then the one that is even is returned.
5362 */
5363void
5364xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5365 double f;
5366
5367 CHECK_ARITY(1);
5368 CAST_TO_NUMBER;
5369 CHECK_TYPE(XPATH_NUMBER);
5370
5371 if ((ctxt->value->floatval == xmlXPathNAN) ||
5372 (ctxt->value->floatval == xmlXPathPINF) ||
5373 (ctxt->value->floatval == xmlXPathNINF) ||
5374 (ctxt->value->floatval == 0.0))
5375 return;
5376
5377#if 0
5378 f = floor(ctxt->value->floatval);
5379#else
5380 f = (double)((int) ctxt->value->floatval);
5381#endif
5382 if (ctxt->value->floatval < f + 0.5)
5383 ctxt->value->floatval = f;
5384 else
5385 ctxt->value->floatval = f + 1;
5386}
5387
5388/************************************************************************
5389 * *
5390 * The Parser *
5391 * *
5392 ************************************************************************/
5393
5394/*
5395 * a couple of forward declarations since we use a recursive call based
5396 * implementation.
5397 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005398static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005399static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005400static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005401#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005402static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5403#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005404#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005405static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005406#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005407static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5408 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005409
5410/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005411 * xmlXPathCurrentChar:
5412 * @ctxt: the XPath parser context
5413 * @cur: pointer to the beginning of the char
5414 * @len: pointer to the length of the char read
5415 *
5416 * The current char value, if using UTF-8 this may actaully span multiple
5417 * bytes in the input buffer.
5418 *
5419 * Returns the current char value and its lenght
5420 */
5421
5422static int
5423xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5424 unsigned char c;
5425 unsigned int val;
5426 const xmlChar *cur;
5427
5428 if (ctxt == NULL)
5429 return(0);
5430 cur = ctxt->cur;
5431
5432 /*
5433 * We are supposed to handle UTF8, check it's valid
5434 * From rfc2044: encoding of the Unicode values on UTF-8:
5435 *
5436 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5437 * 0000 0000-0000 007F 0xxxxxxx
5438 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5439 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5440 *
5441 * Check for the 0x110000 limit too
5442 */
5443 c = *cur;
5444 if (c & 0x80) {
5445 if ((cur[1] & 0xc0) != 0x80)
5446 goto encoding_error;
5447 if ((c & 0xe0) == 0xe0) {
5448
5449 if ((cur[2] & 0xc0) != 0x80)
5450 goto encoding_error;
5451 if ((c & 0xf0) == 0xf0) {
5452 if (((c & 0xf8) != 0xf0) ||
5453 ((cur[3] & 0xc0) != 0x80))
5454 goto encoding_error;
5455 /* 4-byte code */
5456 *len = 4;
5457 val = (cur[0] & 0x7) << 18;
5458 val |= (cur[1] & 0x3f) << 12;
5459 val |= (cur[2] & 0x3f) << 6;
5460 val |= cur[3] & 0x3f;
5461 } else {
5462 /* 3-byte code */
5463 *len = 3;
5464 val = (cur[0] & 0xf) << 12;
5465 val |= (cur[1] & 0x3f) << 6;
5466 val |= cur[2] & 0x3f;
5467 }
5468 } else {
5469 /* 2-byte code */
5470 *len = 2;
5471 val = (cur[0] & 0x1f) << 6;
5472 val |= cur[1] & 0x3f;
5473 }
5474 if (!IS_CHAR(val)) {
5475 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5476 }
5477 return(val);
5478 } else {
5479 /* 1-byte code */
5480 *len = 1;
5481 return((int) *cur);
5482 }
5483encoding_error:
5484 /*
5485 * If we detect an UTF8 error that probably mean that the
5486 * input encoding didn't get properly advertized in the
5487 * declaration header. Report the error and switch the encoding
5488 * to ISO-Latin-1 (if you don't like this policy, just declare the
5489 * encoding !)
5490 */
5491 XP_ERROR0(XPATH_ENCODING_ERROR);
5492 *len = 1;
5493 return((int) *cur);
5494}
5495
5496/**
Owen Taylor3473f882001-02-23 17:55:21 +00005497 * xmlXPathParseNCName:
5498 * @ctxt: the XPath Parser context
5499 *
5500 * parse an XML namespace non qualified name.
5501 *
5502 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5503 *
5504 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5505 * CombiningChar | Extender
5506 *
5507 * Returns the namespace name or NULL
5508 */
5509
5510xmlChar *
5511xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005512 const xmlChar *in;
5513 xmlChar *ret;
5514 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005515
Daniel Veillard2156a562001-04-28 12:24:34 +00005516 /*
5517 * Accelerator for simple ASCII names
5518 */
5519 in = ctxt->cur;
5520 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5521 ((*in >= 0x41) && (*in <= 0x5A)) ||
5522 (*in == '_')) {
5523 in++;
5524 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5525 ((*in >= 0x41) && (*in <= 0x5A)) ||
5526 ((*in >= 0x30) && (*in <= 0x39)) ||
5527 (*in == '_'))
5528 in++;
5529 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5530 (*in == '[') || (*in == ']') || (*in == ':') ||
5531 (*in == '@') || (*in == '*')) {
5532 count = in - ctxt->cur;
5533 if (count == 0)
5534 return(NULL);
5535 ret = xmlStrndup(ctxt->cur, count);
5536 ctxt->cur = in;
5537 return(ret);
5538 }
5539 }
5540 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005541}
5542
Daniel Veillard2156a562001-04-28 12:24:34 +00005543
Owen Taylor3473f882001-02-23 17:55:21 +00005544/**
5545 * xmlXPathParseQName:
5546 * @ctxt: the XPath Parser context
5547 * @prefix: a xmlChar **
5548 *
5549 * parse an XML qualified name
5550 *
5551 * [NS 5] QName ::= (Prefix ':')? LocalPart
5552 *
5553 * [NS 6] Prefix ::= NCName
5554 *
5555 * [NS 7] LocalPart ::= NCName
5556 *
5557 * Returns the function returns the local part, and prefix is updated
5558 * to get the Prefix if any.
5559 */
5560
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005561static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005562xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5563 xmlChar *ret = NULL;
5564
5565 *prefix = NULL;
5566 ret = xmlXPathParseNCName(ctxt);
5567 if (CUR == ':') {
5568 *prefix = ret;
5569 NEXT;
5570 ret = xmlXPathParseNCName(ctxt);
5571 }
5572 return(ret);
5573}
5574
5575/**
5576 * xmlXPathParseName:
5577 * @ctxt: the XPath Parser context
5578 *
5579 * parse an XML name
5580 *
5581 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5582 * CombiningChar | Extender
5583 *
5584 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5585 *
5586 * Returns the namespace name or NULL
5587 */
5588
5589xmlChar *
5590xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005591 const xmlChar *in;
5592 xmlChar *ret;
5593 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005594
Daniel Veillard61d80a22001-04-27 17:13:01 +00005595 /*
5596 * Accelerator for simple ASCII names
5597 */
5598 in = ctxt->cur;
5599 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5600 ((*in >= 0x41) && (*in <= 0x5A)) ||
5601 (*in == '_') || (*in == ':')) {
5602 in++;
5603 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5604 ((*in >= 0x41) && (*in <= 0x5A)) ||
5605 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00005606 (*in == '_') || (*in == '-') ||
5607 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00005608 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00005609 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005610 count = in - ctxt->cur;
5611 ret = xmlStrndup(ctxt->cur, count);
5612 ctxt->cur = in;
5613 return(ret);
5614 }
5615 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005616 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005617}
5618
Daniel Veillard61d80a22001-04-27 17:13:01 +00005619static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005620xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005621 xmlChar buf[XML_MAX_NAMELEN + 5];
5622 int len = 0, l;
5623 int c;
5624
5625 /*
5626 * Handler for more complex cases
5627 */
5628 c = CUR_CHAR(l);
5629 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005630 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5631 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005632 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005633 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005634 return(NULL);
5635 }
5636
5637 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5638 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5639 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005640 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005641 (IS_COMBINING(c)) ||
5642 (IS_EXTENDER(c)))) {
5643 COPY_BUF(l,buf,len,c);
5644 NEXTL(l);
5645 c = CUR_CHAR(l);
5646 if (len >= XML_MAX_NAMELEN) {
5647 /*
5648 * Okay someone managed to make a huge name, so he's ready to pay
5649 * for the processing speed.
5650 */
5651 xmlChar *buffer;
5652 int max = len * 2;
5653
5654 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5655 if (buffer == NULL) {
5656 XP_ERROR0(XPATH_MEMORY_ERROR);
5657 }
5658 memcpy(buffer, buf, len);
5659 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5660 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005661 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005662 (IS_COMBINING(c)) ||
5663 (IS_EXTENDER(c))) {
5664 if (len + 10 > max) {
5665 max *= 2;
5666 buffer = (xmlChar *) xmlRealloc(buffer,
5667 max * sizeof(xmlChar));
5668 XP_ERROR0(XPATH_MEMORY_ERROR);
5669 if (buffer == NULL) {
5670 XP_ERROR0(XPATH_MEMORY_ERROR);
5671 }
5672 }
5673 COPY_BUF(l,buffer,len,c);
5674 NEXTL(l);
5675 c = CUR_CHAR(l);
5676 }
5677 buffer[len] = 0;
5678 return(buffer);
5679 }
5680 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005681 if (len == 0)
5682 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005683 return(xmlStrndup(buf, len));
5684}
Owen Taylor3473f882001-02-23 17:55:21 +00005685/**
5686 * xmlXPathStringEvalNumber:
5687 * @str: A string to scan
5688 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005689 * [30a] Float ::= Number ('e' Digits?)?
5690 *
Owen Taylor3473f882001-02-23 17:55:21 +00005691 * [30] Number ::= Digits ('.' Digits?)?
5692 * | '.' Digits
5693 * [31] Digits ::= [0-9]+
5694 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005695 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005696 * In complement of the Number expression, this function also handles
5697 * negative values : '-' Number.
5698 *
5699 * Returns the double value.
5700 */
5701double
5702xmlXPathStringEvalNumber(const xmlChar *str) {
5703 const xmlChar *cur = str;
5704 double ret = 0.0;
5705 double mult = 1;
5706 int ok = 0;
5707 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005708 int exponent = 0;
5709 int is_exponent_negative = 0;
5710
Owen Taylor3473f882001-02-23 17:55:21 +00005711 while (IS_BLANK(*cur)) cur++;
5712 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5713 return(xmlXPathNAN);
5714 }
5715 if (*cur == '-') {
5716 isneg = 1;
5717 cur++;
5718 }
5719 while ((*cur >= '0') && (*cur <= '9')) {
5720 ret = ret * 10 + (*cur - '0');
5721 ok = 1;
5722 cur++;
5723 }
5724 if (*cur == '.') {
5725 cur++;
5726 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5727 return(xmlXPathNAN);
5728 }
5729 while ((*cur >= '0') && (*cur <= '9')) {
5730 mult /= 10;
5731 ret = ret + (*cur - '0') * mult;
5732 cur++;
5733 }
5734 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005735 if ((*cur == 'e') || (*cur == 'E')) {
5736 cur++;
5737 if (*cur == '-') {
5738 is_exponent_negative = 1;
5739 cur++;
5740 }
5741 while ((*cur >= '0') && (*cur <= '9')) {
5742 exponent = exponent * 10 + (*cur - '0');
5743 cur++;
5744 }
5745 }
Owen Taylor3473f882001-02-23 17:55:21 +00005746 while (IS_BLANK(*cur)) cur++;
5747 if (*cur != 0) return(xmlXPathNAN);
5748 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005749 if (is_exponent_negative) exponent = -exponent;
5750 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005751 return(ret);
5752}
5753
5754/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005755 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005756 * @ctxt: the XPath Parser context
5757 *
5758 * [30] Number ::= Digits ('.' Digits?)?
5759 * | '.' Digits
5760 * [31] Digits ::= [0-9]+
5761 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005762 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005763 *
5764 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005765static void
5766xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005767 double ret = 0.0;
5768 double mult = 1;
5769 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005770 int exponent = 0;
5771 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005772
5773 CHECK_ERROR;
5774 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5775 XP_ERROR(XPATH_NUMBER_ERROR);
5776 }
5777 while ((CUR >= '0') && (CUR <= '9')) {
5778 ret = ret * 10 + (CUR - '0');
5779 ok = 1;
5780 NEXT;
5781 }
5782 if (CUR == '.') {
5783 NEXT;
5784 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5785 XP_ERROR(XPATH_NUMBER_ERROR);
5786 }
5787 while ((CUR >= '0') && (CUR <= '9')) {
5788 mult /= 10;
5789 ret = ret + (CUR - '0') * mult;
5790 NEXT;
5791 }
5792 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005793 if ((CUR == 'e') || (CUR == 'E')) {
5794 NEXT;
5795 if (CUR == '-') {
5796 is_exponent_negative = 1;
5797 NEXT;
5798 }
5799 while ((CUR >= '0') && (CUR <= '9')) {
5800 exponent = exponent * 10 + (CUR - '0');
5801 NEXT;
5802 }
5803 }
5804 if (is_exponent_negative)
5805 exponent = -exponent;
5806 ret *= pow(10.0, (double)exponent);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005807 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5808 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005809}
5810
5811/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005812 * xmlXPathParseLiteral:
5813 * @ctxt: the XPath Parser context
5814 *
5815 * Parse a Literal
5816 *
5817 * [29] Literal ::= '"' [^"]* '"'
5818 * | "'" [^']* "'"
5819 *
5820 * Returns the value found or NULL in case of error
5821 */
5822static xmlChar *
5823xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5824 const xmlChar *q;
5825 xmlChar *ret = NULL;
5826
5827 if (CUR == '"') {
5828 NEXT;
5829 q = CUR_PTR;
5830 while ((IS_CHAR(CUR)) && (CUR != '"'))
5831 NEXT;
5832 if (!IS_CHAR(CUR)) {
5833 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5834 } else {
5835 ret = xmlStrndup(q, CUR_PTR - q);
5836 NEXT;
5837 }
5838 } else if (CUR == '\'') {
5839 NEXT;
5840 q = CUR_PTR;
5841 while ((IS_CHAR(CUR)) && (CUR != '\''))
5842 NEXT;
5843 if (!IS_CHAR(CUR)) {
5844 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5845 } else {
5846 ret = xmlStrndup(q, CUR_PTR - q);
5847 NEXT;
5848 }
5849 } else {
5850 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5851 }
5852 return(ret);
5853}
5854
5855/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005856 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005857 * @ctxt: the XPath Parser context
5858 *
5859 * Parse a Literal and push it on the stack.
5860 *
5861 * [29] Literal ::= '"' [^"]* '"'
5862 * | "'" [^']* "'"
5863 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005864 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005865 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005866static void
5867xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005868 const xmlChar *q;
5869 xmlChar *ret = NULL;
5870
5871 if (CUR == '"') {
5872 NEXT;
5873 q = CUR_PTR;
5874 while ((IS_CHAR(CUR)) && (CUR != '"'))
5875 NEXT;
5876 if (!IS_CHAR(CUR)) {
5877 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5878 } else {
5879 ret = xmlStrndup(q, CUR_PTR - q);
5880 NEXT;
5881 }
5882 } else if (CUR == '\'') {
5883 NEXT;
5884 q = CUR_PTR;
5885 while ((IS_CHAR(CUR)) && (CUR != '\''))
5886 NEXT;
5887 if (!IS_CHAR(CUR)) {
5888 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5889 } else {
5890 ret = xmlStrndup(q, CUR_PTR - q);
5891 NEXT;
5892 }
5893 } else {
5894 XP_ERROR(XPATH_START_LITERAL_ERROR);
5895 }
5896 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005897 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5898 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005899 xmlFree(ret);
5900}
5901
5902/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005903 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005904 * @ctxt: the XPath Parser context
5905 *
5906 * Parse a VariableReference, evaluate it and push it on the stack.
5907 *
5908 * The variable bindings consist of a mapping from variable names
5909 * to variable values. The value of a variable is an object, which
5910 * of any of the types that are possible for the value of an expression,
5911 * and may also be of additional types not specified here.
5912 *
5913 * Early evaluation is possible since:
5914 * The variable bindings [...] used to evaluate a subexpression are
5915 * always the same as those used to evaluate the containing expression.
5916 *
5917 * [36] VariableReference ::= '$' QName
5918 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005919static void
5920xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005921 xmlChar *name;
5922 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005923
5924 SKIP_BLANKS;
5925 if (CUR != '$') {
5926 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5927 }
5928 NEXT;
5929 name = xmlXPathParseQName(ctxt, &prefix);
5930 if (name == NULL) {
5931 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5932 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005933 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005934 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5935 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005936 SKIP_BLANKS;
5937}
5938
5939/**
5940 * xmlXPathIsNodeType:
5941 * @ctxt: the XPath Parser context
5942 * @name: a name string
5943 *
5944 * Is the name given a NodeType one.
5945 *
5946 * [38] NodeType ::= 'comment'
5947 * | 'text'
5948 * | 'processing-instruction'
5949 * | 'node'
5950 *
5951 * Returns 1 if true 0 otherwise
5952 */
5953int
5954xmlXPathIsNodeType(const xmlChar *name) {
5955 if (name == NULL)
5956 return(0);
5957
5958 if (xmlStrEqual(name, BAD_CAST "comment"))
5959 return(1);
5960 if (xmlStrEqual(name, BAD_CAST "text"))
5961 return(1);
5962 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5963 return(1);
5964 if (xmlStrEqual(name, BAD_CAST "node"))
5965 return(1);
5966 return(0);
5967}
5968
5969/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005970 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005971 * @ctxt: the XPath Parser context
5972 *
5973 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5974 * [17] Argument ::= Expr
5975 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005976 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00005977 * pushed on the stack
5978 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005979static void
5980xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005981 xmlChar *name;
5982 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005983 int nbargs = 0;
5984
5985 name = xmlXPathParseQName(ctxt, &prefix);
5986 if (name == NULL) {
5987 XP_ERROR(XPATH_EXPR_ERROR);
5988 }
5989 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005990#ifdef DEBUG_EXPR
5991 if (prefix == NULL)
5992 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5993 name);
5994 else
5995 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5996 prefix, name);
5997#endif
5998
Owen Taylor3473f882001-02-23 17:55:21 +00005999 if (CUR != '(') {
6000 XP_ERROR(XPATH_EXPR_ERROR);
6001 }
6002 NEXT;
6003 SKIP_BLANKS;
6004
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006005 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006006 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006007 int op1 = ctxt->comp->last;
6008 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006009 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006010 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006011 nbargs++;
6012 if (CUR == ')') break;
6013 if (CUR != ',') {
6014 XP_ERROR(XPATH_EXPR_ERROR);
6015 }
6016 NEXT;
6017 SKIP_BLANKS;
6018 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006019 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6020 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006021 NEXT;
6022 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006023}
6024
6025/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006026 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006027 * @ctxt: the XPath Parser context
6028 *
6029 * [15] PrimaryExpr ::= VariableReference
6030 * | '(' Expr ')'
6031 * | Literal
6032 * | Number
6033 * | FunctionCall
6034 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006035 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006036 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006037static void
6038xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006039 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006040 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006041 else if (CUR == '(') {
6042 NEXT;
6043 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006044 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006045 if (CUR != ')') {
6046 XP_ERROR(XPATH_EXPR_ERROR);
6047 }
6048 NEXT;
6049 SKIP_BLANKS;
6050 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006051 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006052 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006053 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006054 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006055 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006056 }
6057 SKIP_BLANKS;
6058}
6059
6060/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006061 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006062 * @ctxt: the XPath Parser context
6063 *
6064 * [20] FilterExpr ::= PrimaryExpr
6065 * | FilterExpr Predicate
6066 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006067 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006068 * Square brackets are used to filter expressions in the same way that
6069 * they are used in location paths. It is an error if the expression to
6070 * be filtered does not evaluate to a node-set. The context node list
6071 * used for evaluating the expression in square brackets is the node-set
6072 * to be filtered listed in document order.
6073 */
6074
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006075static void
6076xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6077 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006078 CHECK_ERROR;
6079 SKIP_BLANKS;
6080
6081 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006082 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006083 SKIP_BLANKS;
6084 }
6085
6086
6087}
6088
6089/**
6090 * xmlXPathScanName:
6091 * @ctxt: the XPath Parser context
6092 *
6093 * Trickery: parse an XML name but without consuming the input flow
6094 * Needed to avoid insanity in the parser state.
6095 *
6096 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6097 * CombiningChar | Extender
6098 *
6099 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6100 *
6101 * [6] Names ::= Name (S Name)*
6102 *
6103 * Returns the Name parsed or NULL
6104 */
6105
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006106static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006107xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6108 xmlChar buf[XML_MAX_NAMELEN];
6109 int len = 0;
6110
6111 SKIP_BLANKS;
6112 if (!IS_LETTER(CUR) && (CUR != '_') &&
6113 (CUR != ':')) {
6114 return(NULL);
6115 }
6116
6117 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6118 (NXT(len) == '.') || (NXT(len) == '-') ||
6119 (NXT(len) == '_') || (NXT(len) == ':') ||
6120 (IS_COMBINING(NXT(len))) ||
6121 (IS_EXTENDER(NXT(len)))) {
6122 buf[len] = NXT(len);
6123 len++;
6124 if (len >= XML_MAX_NAMELEN) {
6125 xmlGenericError(xmlGenericErrorContext,
6126 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6127 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6128 (NXT(len) == '.') || (NXT(len) == '-') ||
6129 (NXT(len) == '_') || (NXT(len) == ':') ||
6130 (IS_COMBINING(NXT(len))) ||
6131 (IS_EXTENDER(NXT(len))))
6132 len++;
6133 break;
6134 }
6135 }
6136 return(xmlStrndup(buf, len));
6137}
6138
6139/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006140 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006141 * @ctxt: the XPath Parser context
6142 *
6143 * [19] PathExpr ::= LocationPath
6144 * | FilterExpr
6145 * | FilterExpr '/' RelativeLocationPath
6146 * | FilterExpr '//' RelativeLocationPath
6147 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006148 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006149 * The / operator and // operators combine an arbitrary expression
6150 * and a relative location path. It is an error if the expression
6151 * does not evaluate to a node-set.
6152 * The / operator does composition in the same way as when / is
6153 * used in a location path. As in location paths, // is short for
6154 * /descendant-or-self::node()/.
6155 */
6156
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006157static void
6158xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006159 int lc = 1; /* Should we branch to LocationPath ? */
6160 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6161
6162 SKIP_BLANKS;
6163 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6164 (CUR == '\'') || (CUR == '"')) {
6165 lc = 0;
6166 } else if (CUR == '*') {
6167 /* relative or absolute location path */
6168 lc = 1;
6169 } else if (CUR == '/') {
6170 /* relative or absolute location path */
6171 lc = 1;
6172 } else if (CUR == '@') {
6173 /* relative abbreviated attribute location path */
6174 lc = 1;
6175 } else if (CUR == '.') {
6176 /* relative abbreviated attribute location path */
6177 lc = 1;
6178 } else {
6179 /*
6180 * Problem is finding if we have a name here whether it's:
6181 * - a nodetype
6182 * - a function call in which case it's followed by '('
6183 * - an axis in which case it's followed by ':'
6184 * - a element name
6185 * We do an a priori analysis here rather than having to
6186 * maintain parsed token content through the recursive function
6187 * calls. This looks uglier but makes the code quite easier to
6188 * read/write/debug.
6189 */
6190 SKIP_BLANKS;
6191 name = xmlXPathScanName(ctxt);
6192 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6193#ifdef DEBUG_STEP
6194 xmlGenericError(xmlGenericErrorContext,
6195 "PathExpr: Axis\n");
6196#endif
6197 lc = 1;
6198 xmlFree(name);
6199 } else if (name != NULL) {
6200 int len =xmlStrlen(name);
6201 int blank = 0;
6202
6203
6204 while (NXT(len) != 0) {
6205 if (NXT(len) == '/') {
6206 /* element name */
6207#ifdef DEBUG_STEP
6208 xmlGenericError(xmlGenericErrorContext,
6209 "PathExpr: AbbrRelLocation\n");
6210#endif
6211 lc = 1;
6212 break;
6213 } else if (IS_BLANK(NXT(len))) {
6214 /* skip to next */
6215 blank = 1;
6216 } else if (NXT(len) == ':') {
6217#ifdef DEBUG_STEP
6218 xmlGenericError(xmlGenericErrorContext,
6219 "PathExpr: AbbrRelLocation\n");
6220#endif
6221 lc = 1;
6222 break;
6223 } else if ((NXT(len) == '(')) {
6224 /* Note Type or Function */
6225 if (xmlXPathIsNodeType(name)) {
6226#ifdef DEBUG_STEP
6227 xmlGenericError(xmlGenericErrorContext,
6228 "PathExpr: Type search\n");
6229#endif
6230 lc = 1;
6231 } else {
6232#ifdef DEBUG_STEP
6233 xmlGenericError(xmlGenericErrorContext,
6234 "PathExpr: function call\n");
6235#endif
6236 lc = 0;
6237 }
6238 break;
6239 } else if ((NXT(len) == '[')) {
6240 /* element name */
6241#ifdef DEBUG_STEP
6242 xmlGenericError(xmlGenericErrorContext,
6243 "PathExpr: AbbrRelLocation\n");
6244#endif
6245 lc = 1;
6246 break;
6247 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6248 (NXT(len) == '=')) {
6249 lc = 1;
6250 break;
6251 } else {
6252 lc = 1;
6253 break;
6254 }
6255 len++;
6256 }
6257 if (NXT(len) == 0) {
6258#ifdef DEBUG_STEP
6259 xmlGenericError(xmlGenericErrorContext,
6260 "PathExpr: AbbrRelLocation\n");
6261#endif
6262 /* element name */
6263 lc = 1;
6264 }
6265 xmlFree(name);
6266 } else {
6267 /* make sure all cases are covered explicitely */
6268 XP_ERROR(XPATH_EXPR_ERROR);
6269 }
6270 }
6271
6272 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006273 if (CUR == '/') {
6274 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6275 } else {
6276 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006277 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006278 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006279 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006280 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006281 CHECK_ERROR;
6282 if ((CUR == '/') && (NXT(1) == '/')) {
6283 SKIP(2);
6284 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006285
6286 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6287 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6288 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6289
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006290 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006291 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006292 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006293 }
6294 }
6295 SKIP_BLANKS;
6296}
6297
6298/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006299 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006300 * @ctxt: the XPath Parser context
6301 *
6302 * [18] UnionExpr ::= PathExpr
6303 * | UnionExpr '|' PathExpr
6304 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006305 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006306 */
6307
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006308static void
6309xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6310 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006311 CHECK_ERROR;
6312 SKIP_BLANKS;
6313 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006314 int op1 = ctxt->comp->last;
6315 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006316
6317 NEXT;
6318 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006319 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006320
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006321 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6322
Owen Taylor3473f882001-02-23 17:55:21 +00006323 SKIP_BLANKS;
6324 }
Owen Taylor3473f882001-02-23 17:55:21 +00006325}
6326
6327/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006328 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006329 * @ctxt: the XPath Parser context
6330 *
6331 * [27] UnaryExpr ::= UnionExpr
6332 * | '-' UnaryExpr
6333 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006334 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006335 */
6336
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006337static void
6338xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006339 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006340 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006341
6342 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006343 while (CUR == '-') {
6344 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006345 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006346 NEXT;
6347 SKIP_BLANKS;
6348 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006349
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006350 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006351 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006352 if (found) {
6353 if (minus)
6354 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6355 else
6356 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006357 }
6358}
6359
6360/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006361 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006362 * @ctxt: the XPath Parser context
6363 *
6364 * [26] MultiplicativeExpr ::= UnaryExpr
6365 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6366 * | MultiplicativeExpr 'div' UnaryExpr
6367 * | MultiplicativeExpr 'mod' UnaryExpr
6368 * [34] MultiplyOperator ::= '*'
6369 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006370 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006371 */
6372
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006373static void
6374xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6375 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006376 CHECK_ERROR;
6377 SKIP_BLANKS;
6378 while ((CUR == '*') ||
6379 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6380 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6381 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006382 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006383
6384 if (CUR == '*') {
6385 op = 0;
6386 NEXT;
6387 } else if (CUR == 'd') {
6388 op = 1;
6389 SKIP(3);
6390 } else if (CUR == 'm') {
6391 op = 2;
6392 SKIP(3);
6393 }
6394 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006395 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006396 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006397 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006398 SKIP_BLANKS;
6399 }
6400}
6401
6402/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006403 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006404 * @ctxt: the XPath Parser context
6405 *
6406 * [25] AdditiveExpr ::= MultiplicativeExpr
6407 * | AdditiveExpr '+' MultiplicativeExpr
6408 * | AdditiveExpr '-' MultiplicativeExpr
6409 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006410 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006411 */
6412
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006413static void
6414xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006415
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006416 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006417 CHECK_ERROR;
6418 SKIP_BLANKS;
6419 while ((CUR == '+') || (CUR == '-')) {
6420 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006421 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006422
6423 if (CUR == '+') plus = 1;
6424 else plus = 0;
6425 NEXT;
6426 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006427 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006428 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006429 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006430 SKIP_BLANKS;
6431 }
6432}
6433
6434/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006435 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006436 * @ctxt: the XPath Parser context
6437 *
6438 * [24] RelationalExpr ::= AdditiveExpr
6439 * | RelationalExpr '<' AdditiveExpr
6440 * | RelationalExpr '>' AdditiveExpr
6441 * | RelationalExpr '<=' AdditiveExpr
6442 * | RelationalExpr '>=' AdditiveExpr
6443 *
6444 * A <= B > C is allowed ? Answer from James, yes with
6445 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6446 * which is basically what got implemented.
6447 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006448 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006449 * on the stack
6450 */
6451
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006452static void
6453xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6454 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006455 CHECK_ERROR;
6456 SKIP_BLANKS;
6457 while ((CUR == '<') ||
6458 (CUR == '>') ||
6459 ((CUR == '<') && (NXT(1) == '=')) ||
6460 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006461 int inf, strict;
6462 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006463
6464 if (CUR == '<') inf = 1;
6465 else inf = 0;
6466 if (NXT(1) == '=') strict = 0;
6467 else strict = 1;
6468 NEXT;
6469 if (!strict) NEXT;
6470 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006471 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006472 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006473 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006474 SKIP_BLANKS;
6475 }
6476}
6477
6478/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006479 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006480 * @ctxt: the XPath Parser context
6481 *
6482 * [23] EqualityExpr ::= RelationalExpr
6483 * | EqualityExpr '=' RelationalExpr
6484 * | EqualityExpr '!=' RelationalExpr
6485 *
6486 * A != B != C is allowed ? Answer from James, yes with
6487 * (RelationalExpr = RelationalExpr) = RelationalExpr
6488 * (RelationalExpr != RelationalExpr) != RelationalExpr
6489 * which is basically what got implemented.
6490 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006491 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006492 *
6493 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006494static void
6495xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6496 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006497 CHECK_ERROR;
6498 SKIP_BLANKS;
6499 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006500 int eq;
6501 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006502
6503 if (CUR == '=') eq = 1;
6504 else eq = 0;
6505 NEXT;
6506 if (!eq) NEXT;
6507 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006508 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006509 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006510 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006511 SKIP_BLANKS;
6512 }
6513}
6514
6515/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006516 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006517 * @ctxt: the XPath Parser context
6518 *
6519 * [22] AndExpr ::= EqualityExpr
6520 * | AndExpr 'and' EqualityExpr
6521 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006522 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006523 *
6524 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006525static void
6526xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6527 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006528 CHECK_ERROR;
6529 SKIP_BLANKS;
6530 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006531 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006532 SKIP(3);
6533 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006534 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006535 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006536 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006537 SKIP_BLANKS;
6538 }
6539}
6540
6541/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006542 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006543 * @ctxt: the XPath Parser context
6544 *
6545 * [14] Expr ::= OrExpr
6546 * [21] OrExpr ::= AndExpr
6547 * | OrExpr 'or' AndExpr
6548 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006549 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006550 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006551static void
6552xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6553 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006554 CHECK_ERROR;
6555 SKIP_BLANKS;
6556 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006557 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006558 SKIP(2);
6559 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006560 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006561 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006562 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6563 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006564 SKIP_BLANKS;
6565 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006566 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6567 /* more ops could be optimized too */
6568 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6569 }
Owen Taylor3473f882001-02-23 17:55:21 +00006570}
6571
6572/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006573 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006574 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006575 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006576 *
6577 * [8] Predicate ::= '[' PredicateExpr ']'
6578 * [9] PredicateExpr ::= Expr
6579 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006580 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006581 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006582static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006583xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006584 int op1 = ctxt->comp->last;
6585
6586 SKIP_BLANKS;
6587 if (CUR != '[') {
6588 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6589 }
6590 NEXT;
6591 SKIP_BLANKS;
6592
6593 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006594 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006595 CHECK_ERROR;
6596
6597 if (CUR != ']') {
6598 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6599 }
6600
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006601 if (filter)
6602 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6603 else
6604 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006605
6606 NEXT;
6607 SKIP_BLANKS;
6608}
6609
6610/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006611 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006612 * @ctxt: the XPath Parser context
6613 * @test: pointer to a xmlXPathTestVal
6614 * @type: pointer to a xmlXPathTypeVal
6615 * @prefix: placeholder for a possible name prefix
6616 *
6617 * [7] NodeTest ::= NameTest
6618 * | NodeType '(' ')'
6619 * | 'processing-instruction' '(' Literal ')'
6620 *
6621 * [37] NameTest ::= '*'
6622 * | NCName ':' '*'
6623 * | QName
6624 * [38] NodeType ::= 'comment'
6625 * | 'text'
6626 * | 'processing-instruction'
6627 * | 'node'
6628 *
6629 * Returns the name found and update @test, @type and @prefix appropriately
6630 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006631static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006632xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6633 xmlXPathTypeVal *type, const xmlChar **prefix,
6634 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006635 int blanks;
6636
6637 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6638 STRANGE;
6639 return(NULL);
6640 }
6641 *type = 0;
6642 *test = 0;
6643 *prefix = NULL;
6644 SKIP_BLANKS;
6645
6646 if ((name == NULL) && (CUR == '*')) {
6647 /*
6648 * All elements
6649 */
6650 NEXT;
6651 *test = NODE_TEST_ALL;
6652 return(NULL);
6653 }
6654
6655 if (name == NULL)
6656 name = xmlXPathParseNCName(ctxt);
6657 if (name == NULL) {
6658 XP_ERROR0(XPATH_EXPR_ERROR);
6659 }
6660
6661 blanks = IS_BLANK(CUR);
6662 SKIP_BLANKS;
6663 if (CUR == '(') {
6664 NEXT;
6665 /*
6666 * NodeType or PI search
6667 */
6668 if (xmlStrEqual(name, BAD_CAST "comment"))
6669 *type = NODE_TYPE_COMMENT;
6670 else if (xmlStrEqual(name, BAD_CAST "node"))
6671 *type = NODE_TYPE_NODE;
6672 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6673 *type = NODE_TYPE_PI;
6674 else if (xmlStrEqual(name, BAD_CAST "text"))
6675 *type = NODE_TYPE_TEXT;
6676 else {
6677 if (name != NULL)
6678 xmlFree(name);
6679 XP_ERROR0(XPATH_EXPR_ERROR);
6680 }
6681
6682 *test = NODE_TEST_TYPE;
6683
6684 SKIP_BLANKS;
6685 if (*type == NODE_TYPE_PI) {
6686 /*
6687 * Specific case: search a PI by name.
6688 */
Owen Taylor3473f882001-02-23 17:55:21 +00006689 if (name != NULL)
6690 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006691 name = NULL;
6692 if (CUR != ')') {
6693 name = xmlXPathParseLiteral(ctxt);
6694 CHECK_ERROR 0;
6695 SKIP_BLANKS;
6696 }
Owen Taylor3473f882001-02-23 17:55:21 +00006697 }
6698 if (CUR != ')') {
6699 if (name != NULL)
6700 xmlFree(name);
6701 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6702 }
6703 NEXT;
6704 return(name);
6705 }
6706 *test = NODE_TEST_NAME;
6707 if ((!blanks) && (CUR == ':')) {
6708 NEXT;
6709
6710 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006711 * Since currently the parser context don't have a
6712 * namespace list associated:
6713 * The namespace name for this prefix can be computed
6714 * only at evaluation time. The compilation is done
6715 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006716 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006717#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006718 *prefix = xmlXPathNsLookup(ctxt->context, name);
6719 if (name != NULL)
6720 xmlFree(name);
6721 if (*prefix == NULL) {
6722 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6723 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006724#else
6725 *prefix = name;
6726#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006727
6728 if (CUR == '*') {
6729 /*
6730 * All elements
6731 */
6732 NEXT;
6733 *test = NODE_TEST_ALL;
6734 return(NULL);
6735 }
6736
6737 name = xmlXPathParseNCName(ctxt);
6738 if (name == NULL) {
6739 XP_ERROR0(XPATH_EXPR_ERROR);
6740 }
6741 }
6742 return(name);
6743}
6744
6745/**
6746 * xmlXPathIsAxisName:
6747 * @name: a preparsed name token
6748 *
6749 * [6] AxisName ::= 'ancestor'
6750 * | 'ancestor-or-self'
6751 * | 'attribute'
6752 * | 'child'
6753 * | 'descendant'
6754 * | 'descendant-or-self'
6755 * | 'following'
6756 * | 'following-sibling'
6757 * | 'namespace'
6758 * | 'parent'
6759 * | 'preceding'
6760 * | 'preceding-sibling'
6761 * | 'self'
6762 *
6763 * Returns the axis or 0
6764 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006765static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006766xmlXPathIsAxisName(const xmlChar *name) {
6767 xmlXPathAxisVal ret = 0;
6768 switch (name[0]) {
6769 case 'a':
6770 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6771 ret = AXIS_ANCESTOR;
6772 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6773 ret = AXIS_ANCESTOR_OR_SELF;
6774 if (xmlStrEqual(name, BAD_CAST "attribute"))
6775 ret = AXIS_ATTRIBUTE;
6776 break;
6777 case 'c':
6778 if (xmlStrEqual(name, BAD_CAST "child"))
6779 ret = AXIS_CHILD;
6780 break;
6781 case 'd':
6782 if (xmlStrEqual(name, BAD_CAST "descendant"))
6783 ret = AXIS_DESCENDANT;
6784 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6785 ret = AXIS_DESCENDANT_OR_SELF;
6786 break;
6787 case 'f':
6788 if (xmlStrEqual(name, BAD_CAST "following"))
6789 ret = AXIS_FOLLOWING;
6790 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6791 ret = AXIS_FOLLOWING_SIBLING;
6792 break;
6793 case 'n':
6794 if (xmlStrEqual(name, BAD_CAST "namespace"))
6795 ret = AXIS_NAMESPACE;
6796 break;
6797 case 'p':
6798 if (xmlStrEqual(name, BAD_CAST "parent"))
6799 ret = AXIS_PARENT;
6800 if (xmlStrEqual(name, BAD_CAST "preceding"))
6801 ret = AXIS_PRECEDING;
6802 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6803 ret = AXIS_PRECEDING_SIBLING;
6804 break;
6805 case 's':
6806 if (xmlStrEqual(name, BAD_CAST "self"))
6807 ret = AXIS_SELF;
6808 break;
6809 }
6810 return(ret);
6811}
6812
6813/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006814 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006815 * @ctxt: the XPath Parser context
6816 *
6817 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6818 * | AbbreviatedStep
6819 *
6820 * [12] AbbreviatedStep ::= '.' | '..'
6821 *
6822 * [5] AxisSpecifier ::= AxisName '::'
6823 * | AbbreviatedAxisSpecifier
6824 *
6825 * [13] AbbreviatedAxisSpecifier ::= '@'?
6826 *
6827 * Modified for XPtr range support as:
6828 *
6829 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6830 * | AbbreviatedStep
6831 * | 'range-to' '(' Expr ')' Predicate*
6832 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006833 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006834 * A location step of . is short for self::node(). This is
6835 * particularly useful in conjunction with //. For example, the
6836 * location path .//para is short for
6837 * self::node()/descendant-or-self::node()/child::para
6838 * and so will select all para descendant elements of the context
6839 * node.
6840 * Similarly, a location step of .. is short for parent::node().
6841 * For example, ../title is short for parent::node()/child::title
6842 * and so will select the title children of the parent of the context
6843 * node.
6844 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006845static void
6846xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006847#ifdef LIBXML_XPTR_ENABLED
6848 int rangeto = 0;
6849 int op2 = -1;
6850#endif
6851
Owen Taylor3473f882001-02-23 17:55:21 +00006852 SKIP_BLANKS;
6853 if ((CUR == '.') && (NXT(1) == '.')) {
6854 SKIP(2);
6855 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006856 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6857 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006858 } else if (CUR == '.') {
6859 NEXT;
6860 SKIP_BLANKS;
6861 } else {
6862 xmlChar *name = NULL;
6863 const xmlChar *prefix = NULL;
6864 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006865 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006866 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006867 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006868
6869 /*
6870 * The modification needed for XPointer change to the production
6871 */
6872#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006873 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006874 name = xmlXPathParseNCName(ctxt);
6875 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006876 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006877 xmlFree(name);
6878 SKIP_BLANKS;
6879 if (CUR != '(') {
6880 XP_ERROR(XPATH_EXPR_ERROR);
6881 }
6882 NEXT;
6883 SKIP_BLANKS;
6884
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006885 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006886 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006887 CHECK_ERROR;
6888
6889 SKIP_BLANKS;
6890 if (CUR != ')') {
6891 XP_ERROR(XPATH_EXPR_ERROR);
6892 }
6893 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006894 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006895 goto eval_predicates;
6896 }
6897 }
6898#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006899 if (CUR == '*') {
6900 axis = AXIS_CHILD;
6901 } else {
6902 if (name == NULL)
6903 name = xmlXPathParseNCName(ctxt);
6904 if (name != NULL) {
6905 axis = xmlXPathIsAxisName(name);
6906 if (axis != 0) {
6907 SKIP_BLANKS;
6908 if ((CUR == ':') && (NXT(1) == ':')) {
6909 SKIP(2);
6910 xmlFree(name);
6911 name = NULL;
6912 } else {
6913 /* an element name can conflict with an axis one :-\ */
6914 axis = AXIS_CHILD;
6915 }
Owen Taylor3473f882001-02-23 17:55:21 +00006916 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00006917 axis = AXIS_CHILD;
6918 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006919 } else if (CUR == '@') {
6920 NEXT;
6921 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00006922 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00006923 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00006924 }
Owen Taylor3473f882001-02-23 17:55:21 +00006925 }
6926
6927 CHECK_ERROR;
6928
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006929 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006930 if (test == 0)
6931 return;
6932
6933#ifdef DEBUG_STEP
6934 xmlGenericError(xmlGenericErrorContext,
6935 "Basis : computing new set\n");
6936#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006937
Owen Taylor3473f882001-02-23 17:55:21 +00006938#ifdef DEBUG_STEP
6939 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006940 if (ctxt->value == NULL)
6941 xmlGenericError(xmlGenericErrorContext, "no value\n");
6942 else if (ctxt->value->nodesetval == NULL)
6943 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6944 else
6945 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006946#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006947
6948eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006949 op1 = ctxt->comp->last;
6950 ctxt->comp->last = -1;
6951
Owen Taylor3473f882001-02-23 17:55:21 +00006952 SKIP_BLANKS;
6953 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006954 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006955 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006956
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006957#ifdef LIBXML_XPTR_ENABLED
6958 if (rangeto) {
6959 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
6960 } else
6961#endif
6962 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
6963 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006964
Owen Taylor3473f882001-02-23 17:55:21 +00006965 }
6966#ifdef DEBUG_STEP
6967 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006968 if (ctxt->value == NULL)
6969 xmlGenericError(xmlGenericErrorContext, "no value\n");
6970 else if (ctxt->value->nodesetval == NULL)
6971 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6972 else
6973 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6974 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006975#endif
6976}
6977
6978/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006979 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006980 * @ctxt: the XPath Parser context
6981 *
6982 * [3] RelativeLocationPath ::= Step
6983 * | RelativeLocationPath '/' Step
6984 * | AbbreviatedRelativeLocationPath
6985 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6986 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006987 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00006988 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006989static void
Owen Taylor3473f882001-02-23 17:55:21 +00006990#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006991xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006992#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006993xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006994#endif
6995(xmlXPathParserContextPtr ctxt) {
6996 SKIP_BLANKS;
6997 if ((CUR == '/') && (NXT(1) == '/')) {
6998 SKIP(2);
6999 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007000 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7001 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007002 } else if (CUR == '/') {
7003 NEXT;
7004 SKIP_BLANKS;
7005 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007006 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007007 SKIP_BLANKS;
7008 while (CUR == '/') {
7009 if ((CUR == '/') && (NXT(1) == '/')) {
7010 SKIP(2);
7011 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007012 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007013 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007014 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007015 } else if (CUR == '/') {
7016 NEXT;
7017 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007018 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007019 }
7020 SKIP_BLANKS;
7021 }
7022}
7023
7024/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007025 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007026 * @ctxt: the XPath Parser context
7027 *
7028 * [1] LocationPath ::= RelativeLocationPath
7029 * | AbsoluteLocationPath
7030 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7031 * | AbbreviatedAbsoluteLocationPath
7032 * [10] AbbreviatedAbsoluteLocationPath ::=
7033 * '//' RelativeLocationPath
7034 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007035 * Compile a location path
7036 *
Owen Taylor3473f882001-02-23 17:55:21 +00007037 * // is short for /descendant-or-self::node()/. For example,
7038 * //para is short for /descendant-or-self::node()/child::para and
7039 * so will select any para element in the document (even a para element
7040 * that is a document element will be selected by //para since the
7041 * document element node is a child of the root node); div//para is
7042 * short for div/descendant-or-self::node()/child::para and so will
7043 * select all para descendants of div children.
7044 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007045static void
7046xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007047 SKIP_BLANKS;
7048 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007049 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007050 } else {
7051 while (CUR == '/') {
7052 if ((CUR == '/') && (NXT(1) == '/')) {
7053 SKIP(2);
7054 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007055 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7056 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007057 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007058 } else if (CUR == '/') {
7059 NEXT;
7060 SKIP_BLANKS;
7061 if (CUR != 0)
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007062 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007063 }
7064 }
7065 }
7066}
7067
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007068/************************************************************************
7069 * *
7070 * XPath precompiled expression evaluation *
7071 * *
7072 ************************************************************************/
7073
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007074static void
7075xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7076
7077/**
7078 * xmlXPathNodeCollectAndTest:
7079 * @ctxt: the XPath Parser context
7080 * @op: the XPath precompiled step operation
7081 *
7082 * This is the function implementing a step: based on the current list
7083 * of nodes, it builds up a new list, looking at all nodes under that
7084 * axis and selecting them it also do the predicate filtering
7085 *
7086 * Pushes the new NodeSet resulting from the search.
7087 */
7088static void
7089xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
7090 xmlXPathStepOpPtr op) {
7091 xmlXPathAxisVal axis = op->value;
7092 xmlXPathTestVal test = op->value2;
7093 xmlXPathTypeVal type = op->value3;
7094 const xmlChar *prefix = op->value4;
7095 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007096 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007097
7098#ifdef DEBUG_STEP
7099 int n = 0, t = 0;
7100#endif
7101 int i;
7102 xmlNodeSetPtr ret, list;
7103 xmlXPathTraversalFunction next = NULL;
7104 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
7105 xmlNodePtr cur = NULL;
7106 xmlXPathObjectPtr obj;
7107 xmlNodeSetPtr nodelist;
7108 xmlNodePtr tmp;
7109
7110 CHECK_TYPE(XPATH_NODESET);
7111 obj = valuePop(ctxt);
7112 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007113 if (prefix != NULL) {
7114 URI = xmlXPathNsLookup(ctxt->context, prefix);
7115 if (URI == NULL)
7116 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
7117 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007118
7119#ifdef DEBUG_STEP
7120 xmlGenericError(xmlGenericErrorContext,
7121 "new step : ");
7122#endif
7123 switch (axis) {
7124 case AXIS_ANCESTOR:
7125#ifdef DEBUG_STEP
7126 xmlGenericError(xmlGenericErrorContext,
7127 "axis 'ancestors' ");
7128#endif
7129 next = xmlXPathNextAncestor; break;
7130 case AXIS_ANCESTOR_OR_SELF:
7131#ifdef DEBUG_STEP
7132 xmlGenericError(xmlGenericErrorContext,
7133 "axis 'ancestors-or-self' ");
7134#endif
7135 next = xmlXPathNextAncestorOrSelf; break;
7136 case AXIS_ATTRIBUTE:
7137#ifdef DEBUG_STEP
7138 xmlGenericError(xmlGenericErrorContext,
7139 "axis 'attributes' ");
7140#endif
7141 next = xmlXPathNextAttribute; break;
7142 break;
7143 case AXIS_CHILD:
7144#ifdef DEBUG_STEP
7145 xmlGenericError(xmlGenericErrorContext,
7146 "axis 'child' ");
7147#endif
7148 next = xmlXPathNextChild; break;
7149 case AXIS_DESCENDANT:
7150#ifdef DEBUG_STEP
7151 xmlGenericError(xmlGenericErrorContext,
7152 "axis 'descendant' ");
7153#endif
7154 next = xmlXPathNextDescendant; break;
7155 case AXIS_DESCENDANT_OR_SELF:
7156#ifdef DEBUG_STEP
7157 xmlGenericError(xmlGenericErrorContext,
7158 "axis 'descendant-or-self' ");
7159#endif
7160 next = xmlXPathNextDescendantOrSelf; break;
7161 case AXIS_FOLLOWING:
7162#ifdef DEBUG_STEP
7163 xmlGenericError(xmlGenericErrorContext,
7164 "axis 'following' ");
7165#endif
7166 next = xmlXPathNextFollowing; break;
7167 case AXIS_FOLLOWING_SIBLING:
7168#ifdef DEBUG_STEP
7169 xmlGenericError(xmlGenericErrorContext,
7170 "axis 'following-siblings' ");
7171#endif
7172 next = xmlXPathNextFollowingSibling; break;
7173 case AXIS_NAMESPACE:
7174#ifdef DEBUG_STEP
7175 xmlGenericError(xmlGenericErrorContext,
7176 "axis 'namespace' ");
7177#endif
7178 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
7179 break;
7180 case AXIS_PARENT:
7181#ifdef DEBUG_STEP
7182 xmlGenericError(xmlGenericErrorContext,
7183 "axis 'parent' ");
7184#endif
7185 next = xmlXPathNextParent; break;
7186 case AXIS_PRECEDING:
7187#ifdef DEBUG_STEP
7188 xmlGenericError(xmlGenericErrorContext,
7189 "axis 'preceding' ");
7190#endif
7191 next = xmlXPathNextPreceding; break;
7192 case AXIS_PRECEDING_SIBLING:
7193#ifdef DEBUG_STEP
7194 xmlGenericError(xmlGenericErrorContext,
7195 "axis 'preceding-sibling' ");
7196#endif
7197 next = xmlXPathNextPrecedingSibling; break;
7198 case AXIS_SELF:
7199#ifdef DEBUG_STEP
7200 xmlGenericError(xmlGenericErrorContext,
7201 "axis 'self' ");
7202#endif
7203 next = xmlXPathNextSelf; break;
7204 }
7205 if (next == NULL)
7206 return;
7207
7208 nodelist = obj->nodesetval;
7209 if (nodelist == NULL) {
7210 xmlXPathFreeObject(obj);
7211 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7212 return;
7213 }
7214 addNode = xmlXPathNodeSetAddUnique;
7215 ret = NULL;
7216#ifdef DEBUG_STEP
7217 xmlGenericError(xmlGenericErrorContext,
7218 " context contains %d nodes\n",
7219 nodelist->nodeNr);
7220 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007221 case NODE_TEST_NONE:
7222 xmlGenericError(xmlGenericErrorContext,
7223 " searching for none !!!\n");
7224 break;
7225 case NODE_TEST_TYPE:
7226 xmlGenericError(xmlGenericErrorContext,
7227 " searching for type %d\n", type);
7228 break;
7229 case NODE_TEST_PI:
7230 xmlGenericError(xmlGenericErrorContext,
7231 " searching for PI !!!\n");
7232 break;
7233 case NODE_TEST_ALL:
7234 xmlGenericError(xmlGenericErrorContext,
7235 " searching for *\n");
7236 break;
7237 case NODE_TEST_NS:
7238 xmlGenericError(xmlGenericErrorContext,
7239 " searching for namespace %s\n",
7240 prefix);
7241 break;
7242 case NODE_TEST_NAME:
7243 xmlGenericError(xmlGenericErrorContext,
7244 " searching for name %s\n", name);
7245 if (prefix != NULL)
7246 xmlGenericError(xmlGenericErrorContext,
7247 " with namespace %s\n",
7248 prefix);
7249 break;
7250 }
7251 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7252#endif
7253 /*
7254 * 2.3 Node Tests
7255 * - For the attribute axis, the principal node type is attribute.
7256 * - For the namespace axis, the principal node type is namespace.
7257 * - For other axes, the principal node type is element.
7258 *
7259 * A node test * is true for any node of the
7260 * principal node type. For example, child::* willi
7261 * select all element children of the context node
7262 */
7263 tmp = ctxt->context->node;
7264 for (i = 0;i < nodelist->nodeNr; i++) {
7265 ctxt->context->node = nodelist->nodeTab[i];
7266
7267 cur = NULL;
7268 list = xmlXPathNodeSetCreate(NULL);
7269 do {
7270 cur = next(ctxt, cur);
7271 if (cur == NULL) break;
7272#ifdef DEBUG_STEP
7273 t++;
7274 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7275#endif
7276 switch (test) {
7277 case NODE_TEST_NONE:
7278 ctxt->context->node = tmp;
7279 STRANGE
7280 return;
7281 case NODE_TEST_TYPE:
7282 if ((cur->type == type) ||
7283 ((type == NODE_TYPE_NODE) &&
7284 ((cur->type == XML_DOCUMENT_NODE) ||
7285 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7286 (cur->type == XML_ELEMENT_NODE) ||
7287 (cur->type == XML_PI_NODE) ||
7288 (cur->type == XML_COMMENT_NODE) ||
7289 (cur->type == XML_CDATA_SECTION_NODE) ||
7290 (cur->type == XML_TEXT_NODE)))) {
7291#ifdef DEBUG_STEP
7292 n++;
7293#endif
7294 addNode(list, cur);
7295 }
7296 break;
7297 case NODE_TEST_PI:
7298 if (cur->type == XML_PI_NODE) {
7299 if ((name != NULL) &&
7300 (!xmlStrEqual(name, cur->name)))
7301 break;
7302#ifdef DEBUG_STEP
7303 n++;
7304#endif
7305 addNode(list, cur);
7306 }
7307 break;
7308 case NODE_TEST_ALL:
7309 if (axis == AXIS_ATTRIBUTE) {
7310 if (cur->type == XML_ATTRIBUTE_NODE) {
7311#ifdef DEBUG_STEP
7312 n++;
7313#endif
7314 addNode(list, cur);
7315 }
7316 } else if (axis == AXIS_NAMESPACE) {
7317 if (cur->type == XML_NAMESPACE_DECL) {
7318#ifdef DEBUG_STEP
7319 n++;
7320#endif
7321 addNode(list, cur);
7322 }
7323 } else {
7324 if ((cur->type == XML_ELEMENT_NODE) ||
7325 (cur->type == XML_DOCUMENT_NODE) ||
7326 (cur->type == XML_HTML_DOCUMENT_NODE)) {
7327 if (prefix == NULL) {
7328#ifdef DEBUG_STEP
7329 n++;
7330#endif
7331 addNode(list, cur);
7332 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007333 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007334 cur->ns->href))) {
7335#ifdef DEBUG_STEP
7336 n++;
7337#endif
7338 addNode(list, cur);
7339 }
7340 }
7341 }
7342 break;
7343 case NODE_TEST_NS: {
7344 TODO;
7345 break;
7346 }
7347 case NODE_TEST_NAME:
7348 switch (cur->type) {
7349 case XML_ELEMENT_NODE:
7350 if (xmlStrEqual(name, cur->name)) {
7351 if (prefix == NULL) {
7352 if ((cur->ns == NULL) ||
7353 (cur->ns->prefix == NULL)) {
7354#ifdef DEBUG_STEP
7355 n++;
7356#endif
7357 addNode(list, cur);
7358 }
7359 } else {
7360 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007361 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007362 cur->ns->href))) {
7363#ifdef DEBUG_STEP
7364 n++;
7365#endif
7366 addNode(list, cur);
7367 }
7368 }
7369 }
7370 break;
7371 case XML_ATTRIBUTE_NODE: {
7372 xmlAttrPtr attr = (xmlAttrPtr) cur;
7373 if (xmlStrEqual(name, attr->name)) {
7374 if (prefix == NULL) {
7375 if ((attr->ns == NULL) ||
7376 (attr->ns->prefix == NULL)) {
7377#ifdef DEBUG_STEP
7378 n++;
7379#endif
7380 addNode(list, (xmlNodePtr) attr);
7381 }
7382 } else {
7383 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007384 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007385 attr->ns->href))) {
7386#ifdef DEBUG_STEP
7387 n++;
7388#endif
7389 addNode(list, (xmlNodePtr) attr);
7390 }
7391 }
7392 }
7393 break;
7394 }
7395 case XML_NAMESPACE_DECL: {
7396 TODO;
7397 break;
7398 }
7399 default:
7400 break;
7401 }
7402 break;
7403 }
7404 } while (cur != NULL);
7405
7406 /*
7407 * If there is some predicate filtering do it now
7408 */
7409 if (op->ch2 != -1) {
7410 xmlXPathObjectPtr obj2;
7411
7412 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7413 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7414 CHECK_TYPE(XPATH_NODESET);
7415 obj2 = valuePop(ctxt);
7416 list = obj2->nodesetval;
7417 obj2->nodesetval = NULL;
7418 xmlXPathFreeObject(obj2);
7419 }
7420 if (ret == NULL) {
7421 ret = list;
7422 } else {
7423 ret = xmlXPathNodeSetMerge(ret, list);
7424 xmlXPathFreeNodeSet(list);
7425 }
7426 }
7427 ctxt->context->node = tmp;
7428#ifdef DEBUG_STEP
7429 xmlGenericError(xmlGenericErrorContext,
7430 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7431#endif
7432 xmlXPathFreeObject(obj);
7433 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7434}
7435
Owen Taylor3473f882001-02-23 17:55:21 +00007436/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007437 * xmlXPathCompOpEval:
7438 * @ctxt: the XPath parser context with the compiled expression
7439 * @op: an XPath compiled operation
7440 *
7441 * Evaluate the Precompiled XPath operation
7442 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007443static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007444xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7445 int equal, ret;
7446 xmlXPathCompExprPtr comp;
7447 xmlXPathObjectPtr arg1, arg2;
7448
7449 comp = ctxt->comp;
7450 switch (op->op) {
7451 case XPATH_OP_END:
7452 return;
7453 case XPATH_OP_AND:
7454 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7455 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007456 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007457 return;
7458 arg2 = valuePop(ctxt);
7459 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7460 xmlXPathBooleanFunction(ctxt, 1);
7461 arg1 = valuePop(ctxt);
7462 arg1->boolval &= arg2->boolval;
7463 valuePush(ctxt, arg1);
7464 xmlXPathFreeObject(arg2);
7465 return;
7466 case XPATH_OP_OR:
7467 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7468 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007469 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007470 return;
7471 arg2 = valuePop(ctxt);
7472 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7473 xmlXPathBooleanFunction(ctxt, 1);
7474 arg1 = valuePop(ctxt);
7475 arg1->boolval |= arg2->boolval;
7476 valuePush(ctxt, arg1);
7477 xmlXPathFreeObject(arg2);
7478 return;
7479 case XPATH_OP_EQUAL:
7480 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7481 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7482 equal = xmlXPathEqualValues(ctxt);
7483 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7484 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7485 return;
7486 case XPATH_OP_CMP:
7487 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7488 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7489 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7490 valuePush(ctxt, xmlXPathNewBoolean(ret));
7491 return;
7492 case XPATH_OP_PLUS:
7493 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7494 if (op->ch2 != -1)
7495 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7496 if (op->value == 0) xmlXPathSubValues(ctxt);
7497 else if (op->value == 1) xmlXPathAddValues(ctxt);
7498 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7499 else if (op->value == 3) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007500 CAST_TO_NUMBER;
7501 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007502 }
7503 return;
7504 case XPATH_OP_MULT:
7505 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7506 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7507 if (op->value == 0) xmlXPathMultValues(ctxt);
7508 else if (op->value == 1) xmlXPathDivValues(ctxt);
7509 else if (op->value == 2) xmlXPathModValues(ctxt);
7510 return;
7511 case XPATH_OP_UNION:
7512 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7513 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7514 CHECK_TYPE(XPATH_NODESET);
7515 arg2 = valuePop(ctxt);
7516
7517 CHECK_TYPE(XPATH_NODESET);
7518 arg1 = valuePop(ctxt);
7519
7520 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7521 arg2->nodesetval);
7522 valuePush(ctxt, arg1);
7523 xmlXPathFreeObject(arg2);
7524 return;
7525 case XPATH_OP_ROOT:
7526 xmlXPathRoot(ctxt);
7527 return;
7528 case XPATH_OP_NODE:
7529 if (op->ch1 != -1)
7530 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7531 if (op->ch2 != -1)
7532 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7533 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7534 return;
7535 case XPATH_OP_RESET:
7536 if (op->ch1 != -1)
7537 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7538 if (op->ch2 != -1)
7539 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7540 ctxt->context->node = NULL;
7541 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007542 case XPATH_OP_COLLECT: {
7543 if (op->ch1 == -1)
7544 return;
7545
7546 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7547 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007548 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007549 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007550 case XPATH_OP_VALUE:
7551 valuePush(ctxt,
7552 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7553 return;
7554 case XPATH_OP_VARIABLE: {
7555 if (op->ch1 != -1)
7556 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7557 if (op->value5 == NULL)
7558 valuePush(ctxt,
7559 xmlXPathVariableLookup(ctxt->context, op->value4));
7560 else {
7561 const xmlChar *URI;
7562 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7563 if (URI == NULL) {
7564 xmlGenericError(xmlGenericErrorContext,
7565 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7566 op->value4, op->value5);
7567 return;
7568 }
7569 valuePush(ctxt,
7570 xmlXPathVariableLookupNS(ctxt->context,
7571 op->value4, URI));
7572 }
7573 return;
7574 }
7575 case XPATH_OP_FUNCTION: {
7576 xmlXPathFunction func;
7577
7578 if (op->ch1 != -1)
7579 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007580 if (op->cache != NULL)
7581 func = (xmlXPathFunction) op->cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007582 else {
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007583 if (op->value5 == NULL)
7584 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7585 else {
7586 const xmlChar *URI;
7587 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7588 if (URI == NULL) {
7589 xmlGenericError(xmlGenericErrorContext,
7590 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7591 op->value4, op->value5);
7592 return;
7593 }
7594 func = xmlXPathFunctionLookupNS(ctxt->context,
7595 op->value4, URI);
7596 }
7597 if (func == NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007598 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007599 "xmlXPathRunEval: function %s not found\n",
7600 op->value4);
7601 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007602 return;
7603 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007604 op->cache = (void *) func;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007605 }
7606 func(ctxt, op->value);
7607 return;
7608 }
7609 case XPATH_OP_ARG:
7610 if (op->ch1 != -1)
7611 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7612 if (op->ch2 != -1)
7613 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7614 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007615 case XPATH_OP_PREDICATE:
7616 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007617 xmlXPathObjectPtr res;
7618 xmlXPathObjectPtr obj, tmp;
7619 xmlNodeSetPtr newset = NULL;
7620 xmlNodeSetPtr oldset;
7621 xmlNodePtr oldnode;
7622 int i;
7623
7624 if (op->ch1 != -1)
7625 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7626 if (op->ch2 == -1)
7627 return;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007628 if (ctxt->value == NULL)
7629 return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007630
7631 oldnode = ctxt->context->node;
7632
7633#ifdef LIBXML_XPTR_ENABLED
7634 /*
7635 * Hum are we filtering the result of an XPointer expression
7636 */
7637 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007638 xmlLocationSetPtr newlocset = NULL;
7639 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007640
7641 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007642 * Extract the old locset, and then evaluate the result of the
7643 * expression for all the element in the locset. use it to grow
7644 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007645 */
7646 CHECK_TYPE(XPATH_LOCATIONSET);
7647 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007648 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007649 ctxt->context->node = NULL;
7650
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007651 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007652 ctxt->context->contextSize = 0;
7653 ctxt->context->proximityPosition = 0;
7654 if (op->ch2 != -1)
7655 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7656 res = valuePop(ctxt);
7657 if (res != NULL)
7658 xmlXPathFreeObject(res);
7659 valuePush(ctxt, obj);
7660 CHECK_ERROR;
7661 return;
7662 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007663 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007664
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007665 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007666 /*
7667 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007668 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007669 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007670 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007671 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7672 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007673 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007674 ctxt->context->proximityPosition = i + 1;
7675
7676 if (op->ch2 != -1)
7677 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7678 CHECK_ERROR;
7679
7680 /*
7681 * The result of the evaluation need to be tested to
7682 * decided whether the filter succeeded or not
7683 */
7684 res = valuePop(ctxt);
7685 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007686 xmlXPtrLocationSetAdd(newlocset,
7687 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007688 }
7689
7690 /*
7691 * Cleanup
7692 */
7693 if (res != NULL)
7694 xmlXPathFreeObject(res);
7695 if (ctxt->value == tmp) {
7696 res = valuePop(ctxt);
7697 xmlXPathFreeObject(res);
7698 }
7699
7700 ctxt->context->node = NULL;
7701 }
7702
7703 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007704 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007705 */
7706 xmlXPathFreeObject(obj);
7707 ctxt->context->node = NULL;
7708 ctxt->context->contextSize = -1;
7709 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007710 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007711 ctxt->context->node = oldnode;
7712 return;
7713 }
7714#endif /* LIBXML_XPTR_ENABLED */
7715
7716 /*
7717 * Extract the old set, and then evaluate the result of the
7718 * expression for all the element in the set. use it to grow
7719 * up a new set.
7720 */
7721 CHECK_TYPE(XPATH_NODESET);
7722 obj = valuePop(ctxt);
7723 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007724
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007725 oldnode = ctxt->context->node;
7726 ctxt->context->node = NULL;
7727
7728 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7729 ctxt->context->contextSize = 0;
7730 ctxt->context->proximityPosition = 0;
7731 if (op->ch2 != -1)
7732 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7733 res = valuePop(ctxt);
7734 if (res != NULL)
7735 xmlXPathFreeObject(res);
7736 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007737 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007738 CHECK_ERROR;
7739 } else {
7740 /*
7741 * Initialize the new set.
7742 */
7743 newset = xmlXPathNodeSetCreate(NULL);
7744
7745 for (i = 0; i < oldset->nodeNr; i++) {
7746 /*
7747 * Run the evaluation with a node list made of
7748 * a single item in the nodeset.
7749 */
7750 ctxt->context->node = oldset->nodeTab[i];
7751 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7752 valuePush(ctxt, tmp);
7753 ctxt->context->contextSize = oldset->nodeNr;
7754 ctxt->context->proximityPosition = i + 1;
7755
7756 if (op->ch2 != -1)
7757 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7758 CHECK_ERROR;
7759
7760 /*
7761 * The result of the evaluation need to be tested to
7762 * decided whether the filter succeeded or not
7763 */
7764 res = valuePop(ctxt);
7765 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7766 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7767 }
7768
7769 /*
7770 * Cleanup
7771 */
7772 if (res != NULL)
7773 xmlXPathFreeObject(res);
7774 if (ctxt->value == tmp) {
7775 res = valuePop(ctxt);
7776 xmlXPathFreeObject(res);
7777 }
7778
7779 ctxt->context->node = NULL;
7780 }
7781
7782 /*
7783 * The result is used as the new evaluation set.
7784 */
7785 xmlXPathFreeObject(obj);
7786 ctxt->context->node = NULL;
7787 ctxt->context->contextSize = -1;
7788 ctxt->context->proximityPosition = -1;
7789 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7790 }
7791 ctxt->context->node = oldnode;
7792 return;
7793 }
7794 case XPATH_OP_SORT:
7795 if (op->ch1 != -1)
7796 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7797 if ((ctxt->value != NULL) &&
7798 (ctxt->value->type == XPATH_NODESET) &&
7799 (ctxt->value->nodesetval != NULL))
7800 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7801 return;
7802#ifdef LIBXML_XPTR_ENABLED
7803 case XPATH_OP_RANGETO: {
7804 xmlXPathObjectPtr range;
7805 xmlXPathObjectPtr res, obj;
7806 xmlXPathObjectPtr tmp;
7807 xmlLocationSetPtr newset = NULL;
7808 xmlNodeSetPtr oldset;
7809 int i;
7810
7811 if (op->ch1 != -1)
7812 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7813 if (op->ch2 == -1)
7814 return;
7815
7816 CHECK_TYPE(XPATH_NODESET);
7817 obj = valuePop(ctxt);
7818 oldset = obj->nodesetval;
7819 ctxt->context->node = NULL;
7820
7821 newset = xmlXPtrLocationSetCreate(NULL);
7822
Daniel Veillard911f49a2001-04-07 15:39:35 +00007823 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007824 for (i = 0; i < oldset->nodeNr; i++) {
7825 /*
7826 * Run the evaluation with a node list made of a single item
7827 * in the nodeset.
7828 */
7829 ctxt->context->node = oldset->nodeTab[i];
7830 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7831 valuePush(ctxt, tmp);
7832
7833 if (op->ch2 != -1)
7834 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7835 CHECK_ERROR;
7836
7837 /*
7838 * The result of the evaluation need to be tested to
7839 * decided whether the filter succeeded or not
7840 */
7841 res = valuePop(ctxt);
7842 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7843 if (range != NULL) {
7844 xmlXPtrLocationSetAdd(newset, range);
7845 }
7846
7847 /*
7848 * Cleanup
7849 */
7850 if (res != NULL)
7851 xmlXPathFreeObject(res);
7852 if (ctxt->value == tmp) {
7853 res = valuePop(ctxt);
7854 xmlXPathFreeObject(res);
7855 }
7856
7857 ctxt->context->node = NULL;
7858 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007859 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007860
7861 /*
7862 * The result is used as the new evaluation set.
7863 */
7864 xmlXPathFreeObject(obj);
7865 ctxt->context->node = NULL;
7866 ctxt->context->contextSize = -1;
7867 ctxt->context->proximityPosition = -1;
7868 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7869 return;
7870 }
7871#endif /* LIBXML_XPTR_ENABLED */
7872 }
7873 xmlGenericError(xmlGenericErrorContext,
7874 "XPath: unknown precompiled operation %d\n",
7875 op->op);
7876 return;
7877}
7878
7879/**
7880 * xmlXPathRunEval:
7881 * @ctxt: the XPath parser context with the compiled expression
7882 *
7883 * Evaluate the Precompiled XPath expression in the given context.
7884 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007885static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007886xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7887 xmlXPathCompExprPtr comp;
7888
7889 if ((ctxt == NULL) || (ctxt->comp == NULL))
7890 return;
7891
7892 if (ctxt->valueTab == NULL) {
7893 /* Allocate the value stack */
7894 ctxt->valueTab = (xmlXPathObjectPtr *)
7895 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7896 if (ctxt->valueTab == NULL) {
7897 xmlFree(ctxt);
7898 xmlGenericError(xmlGenericErrorContext,
7899 "xmlXPathRunEval: out of memory\n");
7900 return;
7901 }
7902 ctxt->valueNr = 0;
7903 ctxt->valueMax = 10;
7904 ctxt->value = NULL;
7905 }
7906 comp = ctxt->comp;
7907 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7908}
7909
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007910/************************************************************************
7911 * *
7912 * Public interfaces *
7913 * *
7914 ************************************************************************/
7915
7916/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007917 * xmlXPathEvalPredicate:
7918 * @ctxt: the XPath context
7919 * @res: the Predicate Expression evaluation result
7920 *
7921 * Evaluate a predicate result for the current node.
7922 * A PredicateExpr is evaluated by evaluating the Expr and converting
7923 * the result to a boolean. If the result is a number, the result will
7924 * be converted to true if the number is equal to the position of the
7925 * context node in the context node list (as returned by the position
7926 * function) and will be converted to false otherwise; if the result
7927 * is not a number, then the result will be converted as if by a call
7928 * to the boolean function.
7929 *
7930 * Return 1 if predicate is true, 0 otherwise
7931 */
7932int
7933xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7934 if (res == NULL) return(0);
7935 switch (res->type) {
7936 case XPATH_BOOLEAN:
7937 return(res->boolval);
7938 case XPATH_NUMBER:
7939 return(res->floatval == ctxt->proximityPosition);
7940 case XPATH_NODESET:
7941 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007942 if (res->nodesetval == NULL)
7943 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007944 return(res->nodesetval->nodeNr != 0);
7945 case XPATH_STRING:
7946 return((res->stringval != NULL) &&
7947 (xmlStrlen(res->stringval) != 0));
7948 default:
7949 STRANGE
7950 }
7951 return(0);
7952}
7953
7954/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007955 * xmlXPathEvaluatePredicateResult:
7956 * @ctxt: the XPath Parser context
7957 * @res: the Predicate Expression evaluation result
7958 *
7959 * Evaluate a predicate result for the current node.
7960 * A PredicateExpr is evaluated by evaluating the Expr and converting
7961 * the result to a boolean. If the result is a number, the result will
7962 * be converted to true if the number is equal to the position of the
7963 * context node in the context node list (as returned by the position
7964 * function) and will be converted to false otherwise; if the result
7965 * is not a number, then the result will be converted as if by a call
7966 * to the boolean function.
7967 *
7968 * Return 1 if predicate is true, 0 otherwise
7969 */
7970int
7971xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
7972 xmlXPathObjectPtr res) {
7973 if (res == NULL) return(0);
7974 switch (res->type) {
7975 case XPATH_BOOLEAN:
7976 return(res->boolval);
7977 case XPATH_NUMBER:
7978 return(res->floatval == ctxt->context->proximityPosition);
7979 case XPATH_NODESET:
7980 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00007981 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00007982 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007983 return(res->nodesetval->nodeNr != 0);
7984 case XPATH_STRING:
7985 return((res->stringval != NULL) &&
7986 (xmlStrlen(res->stringval) != 0));
7987 default:
7988 STRANGE
7989 }
7990 return(0);
7991}
7992
7993/**
7994 * xmlXPathCompile:
7995 * @str: the XPath expression
7996 *
7997 * Compile an XPath expression
7998 *
7999 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8000 * the caller has to free the object.
8001 */
8002xmlXPathCompExprPtr
8003xmlXPathCompile(const xmlChar *str) {
8004 xmlXPathParserContextPtr ctxt;
8005 xmlXPathCompExprPtr comp;
8006
8007 xmlXPathInit();
8008
8009 ctxt = xmlXPathNewParserContext(str, NULL);
8010 xmlXPathCompileExpr(ctxt);
8011
Daniel Veillard40af6492001-04-22 08:50:55 +00008012 if (*ctxt->cur != 0) {
8013 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8014 comp = NULL;
8015 } else {
8016 comp = ctxt->comp;
8017 ctxt->comp = NULL;
8018 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008019 xmlXPathFreeParserContext(ctxt);
8020 return(comp);
8021}
8022
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008023/**
8024 * xmlXPathCompiledEval:
8025 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00008026 * @ctx: the XPath context
8027 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008028 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00008029 *
8030 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8031 * the caller has to free the object.
8032 */
8033xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008034xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00008035 xmlXPathParserContextPtr ctxt;
8036 xmlXPathObjectPtr res, tmp, init = NULL;
8037 int stack = 0;
8038
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008039 if ((comp == NULL) || (ctx == NULL))
8040 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008041 xmlXPathInit();
8042
8043 CHECK_CONTEXT(ctx)
8044
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008045 ctxt = xmlXPathCompParserContext(comp, ctx);
8046 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008047
8048 if (ctxt->value == NULL) {
8049 xmlGenericError(xmlGenericErrorContext,
8050 "xmlXPathEval: evaluation failed\n");
8051 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00008052 } else {
8053 res = valuePop(ctxt);
8054 }
8055
8056 do {
8057 tmp = valuePop(ctxt);
8058 if (tmp != NULL) {
8059 if (tmp != init)
8060 stack++;
8061 xmlXPathFreeObject(tmp);
8062 }
8063 } while (tmp != NULL);
8064 if ((stack != 0) && (res != NULL)) {
8065 xmlGenericError(xmlGenericErrorContext,
8066 "xmlXPathEval: %d object left on the stack\n",
8067 stack);
8068 }
8069 if (ctxt->error != XPATH_EXPRESSION_OK) {
8070 xmlXPathFreeObject(res);
8071 res = NULL;
8072 }
8073
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008074
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008075 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008076 xmlXPathFreeParserContext(ctxt);
8077 return(res);
8078}
8079
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008080/**
8081 * xmlXPathEvalExpr:
8082 * @ctxt: the XPath Parser context
8083 *
8084 * Parse and evaluate an XPath expression in the given context,
8085 * then push the result on the context stack
8086 */
8087void
8088xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
8089 xmlXPathCompileExpr(ctxt);
8090 xmlXPathRunEval(ctxt);
8091}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008092
8093/**
8094 * xmlXPathEval:
8095 * @str: the XPath expression
8096 * @ctx: the XPath context
8097 *
8098 * Evaluate the XPath Location Path in the given context.
8099 *
8100 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8101 * the caller has to free the object.
8102 */
8103xmlXPathObjectPtr
8104xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
8105 xmlXPathParserContextPtr ctxt;
8106 xmlXPathObjectPtr res, tmp, init = NULL;
8107 int stack = 0;
8108
8109 xmlXPathInit();
8110
8111 CHECK_CONTEXT(ctx)
8112
8113 ctxt = xmlXPathNewParserContext(str, ctx);
8114 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008115
8116 if (ctxt->value == NULL) {
8117 xmlGenericError(xmlGenericErrorContext,
8118 "xmlXPathEval: evaluation failed\n");
8119 res = NULL;
8120 } else if (*ctxt->cur != 0) {
8121 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8122 res = NULL;
8123 } else {
8124 res = valuePop(ctxt);
8125 }
8126
8127 do {
8128 tmp = valuePop(ctxt);
8129 if (tmp != NULL) {
8130 if (tmp != init)
8131 stack++;
8132 xmlXPathFreeObject(tmp);
8133 }
8134 } while (tmp != NULL);
8135 if ((stack != 0) && (res != NULL)) {
8136 xmlGenericError(xmlGenericErrorContext,
8137 "xmlXPathEval: %d object left on the stack\n",
8138 stack);
8139 }
8140 if (ctxt->error != XPATH_EXPRESSION_OK) {
8141 xmlXPathFreeObject(res);
8142 res = NULL;
8143 }
8144
Owen Taylor3473f882001-02-23 17:55:21 +00008145 xmlXPathFreeParserContext(ctxt);
8146 return(res);
8147}
8148
8149/**
8150 * xmlXPathEvalExpression:
8151 * @str: the XPath expression
8152 * @ctxt: the XPath context
8153 *
8154 * Evaluate the XPath expression in the given context.
8155 *
8156 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
8157 * the caller has to free the object.
8158 */
8159xmlXPathObjectPtr
8160xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
8161 xmlXPathParserContextPtr pctxt;
8162 xmlXPathObjectPtr res, tmp;
8163 int stack = 0;
8164
8165 xmlXPathInit();
8166
8167 CHECK_CONTEXT(ctxt)
8168
8169 pctxt = xmlXPathNewParserContext(str, ctxt);
8170 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008171
8172 if (*pctxt->cur != 0) {
8173 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8174 res = NULL;
8175 } else {
8176 res = valuePop(pctxt);
8177 }
8178 do {
8179 tmp = valuePop(pctxt);
8180 if (tmp != NULL) {
8181 xmlXPathFreeObject(tmp);
8182 stack++;
8183 }
8184 } while (tmp != NULL);
8185 if ((stack != 0) && (res != NULL)) {
8186 xmlGenericError(xmlGenericErrorContext,
8187 "xmlXPathEvalExpression: %d object left on the stack\n",
8188 stack);
8189 }
8190 xmlXPathFreeParserContext(pctxt);
8191 return(res);
8192}
8193
8194/**
8195 * xmlXPathRegisterAllFunctions:
8196 * @ctxt: the XPath context
8197 *
8198 * Registers all default XPath functions in this context
8199 */
8200void
8201xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
8202{
8203 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
8204 xmlXPathBooleanFunction);
8205 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
8206 xmlXPathCeilingFunction);
8207 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
8208 xmlXPathCountFunction);
8209 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
8210 xmlXPathConcatFunction);
8211 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
8212 xmlXPathContainsFunction);
8213 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
8214 xmlXPathIdFunction);
8215 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
8216 xmlXPathFalseFunction);
8217 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
8218 xmlXPathFloorFunction);
8219 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
8220 xmlXPathLastFunction);
8221 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
8222 xmlXPathLangFunction);
8223 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
8224 xmlXPathLocalNameFunction);
8225 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
8226 xmlXPathNotFunction);
8227 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
8228 xmlXPathNameFunction);
8229 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
8230 xmlXPathNamespaceURIFunction);
8231 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
8232 xmlXPathNormalizeFunction);
8233 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
8234 xmlXPathNumberFunction);
8235 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
8236 xmlXPathPositionFunction);
8237 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
8238 xmlXPathRoundFunction);
8239 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
8240 xmlXPathStringFunction);
8241 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
8242 xmlXPathStringLengthFunction);
8243 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
8244 xmlXPathStartsWithFunction);
8245 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
8246 xmlXPathSubstringFunction);
8247 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
8248 xmlXPathSubstringBeforeFunction);
8249 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
8250 xmlXPathSubstringAfterFunction);
8251 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
8252 xmlXPathSumFunction);
8253 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
8254 xmlXPathTrueFunction);
8255 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
8256 xmlXPathTranslateFunction);
8257}
8258
8259#endif /* LIBXML_XPATH_ENABLED */