blob: cefe05faae16f7a7cffc2a6a731eba95ffac9aec [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
1929 xmlHashFree(ctxt->varHash, NULL);
1930 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)) ||
5606 (*in == '_') || (*in == ':'))
5607 in++;
5608 if ((*in == ' ') || (*in == '>') || (*in == '/')) {
5609 count = in - ctxt->cur;
5610 ret = xmlStrndup(ctxt->cur, count);
5611 ctxt->cur = in;
5612 return(ret);
5613 }
5614 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005615 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005616}
5617
Daniel Veillard61d80a22001-04-27 17:13:01 +00005618static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005619xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005620 xmlChar buf[XML_MAX_NAMELEN + 5];
5621 int len = 0, l;
5622 int c;
5623
5624 /*
5625 * Handler for more complex cases
5626 */
5627 c = CUR_CHAR(l);
5628 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005629 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5630 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005631 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005632 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005633 return(NULL);
5634 }
5635
5636 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5637 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5638 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005639 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005640 (IS_COMBINING(c)) ||
5641 (IS_EXTENDER(c)))) {
5642 COPY_BUF(l,buf,len,c);
5643 NEXTL(l);
5644 c = CUR_CHAR(l);
5645 if (len >= XML_MAX_NAMELEN) {
5646 /*
5647 * Okay someone managed to make a huge name, so he's ready to pay
5648 * for the processing speed.
5649 */
5650 xmlChar *buffer;
5651 int max = len * 2;
5652
5653 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5654 if (buffer == NULL) {
5655 XP_ERROR0(XPATH_MEMORY_ERROR);
5656 }
5657 memcpy(buffer, buf, len);
5658 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5659 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005660 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005661 (IS_COMBINING(c)) ||
5662 (IS_EXTENDER(c))) {
5663 if (len + 10 > max) {
5664 max *= 2;
5665 buffer = (xmlChar *) xmlRealloc(buffer,
5666 max * sizeof(xmlChar));
5667 XP_ERROR0(XPATH_MEMORY_ERROR);
5668 if (buffer == NULL) {
5669 XP_ERROR0(XPATH_MEMORY_ERROR);
5670 }
5671 }
5672 COPY_BUF(l,buffer,len,c);
5673 NEXTL(l);
5674 c = CUR_CHAR(l);
5675 }
5676 buffer[len] = 0;
5677 return(buffer);
5678 }
5679 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005680 if (len == 0)
5681 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005682 return(xmlStrndup(buf, len));
5683}
Owen Taylor3473f882001-02-23 17:55:21 +00005684/**
5685 * xmlXPathStringEvalNumber:
5686 * @str: A string to scan
5687 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005688 * [30a] Float ::= Number ('e' Digits?)?
5689 *
Owen Taylor3473f882001-02-23 17:55:21 +00005690 * [30] Number ::= Digits ('.' Digits?)?
5691 * | '.' Digits
5692 * [31] Digits ::= [0-9]+
5693 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005694 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005695 * In complement of the Number expression, this function also handles
5696 * negative values : '-' Number.
5697 *
5698 * Returns the double value.
5699 */
5700double
5701xmlXPathStringEvalNumber(const xmlChar *str) {
5702 const xmlChar *cur = str;
5703 double ret = 0.0;
5704 double mult = 1;
5705 int ok = 0;
5706 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005707 int exponent = 0;
5708 int is_exponent_negative = 0;
5709
Owen Taylor3473f882001-02-23 17:55:21 +00005710 while (IS_BLANK(*cur)) cur++;
5711 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5712 return(xmlXPathNAN);
5713 }
5714 if (*cur == '-') {
5715 isneg = 1;
5716 cur++;
5717 }
5718 while ((*cur >= '0') && (*cur <= '9')) {
5719 ret = ret * 10 + (*cur - '0');
5720 ok = 1;
5721 cur++;
5722 }
5723 if (*cur == '.') {
5724 cur++;
5725 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5726 return(xmlXPathNAN);
5727 }
5728 while ((*cur >= '0') && (*cur <= '9')) {
5729 mult /= 10;
5730 ret = ret + (*cur - '0') * mult;
5731 cur++;
5732 }
5733 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005734 if ((*cur == 'e') || (*cur == 'E')) {
5735 cur++;
5736 if (*cur == '-') {
5737 is_exponent_negative = 1;
5738 cur++;
5739 }
5740 while ((*cur >= '0') && (*cur <= '9')) {
5741 exponent = exponent * 10 + (*cur - '0');
5742 cur++;
5743 }
5744 }
Owen Taylor3473f882001-02-23 17:55:21 +00005745 while (IS_BLANK(*cur)) cur++;
5746 if (*cur != 0) return(xmlXPathNAN);
5747 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005748 if (is_exponent_negative) exponent = -exponent;
5749 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005750 return(ret);
5751}
5752
5753/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005754 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005755 * @ctxt: the XPath Parser context
5756 *
5757 * [30] Number ::= Digits ('.' Digits?)?
5758 * | '.' Digits
5759 * [31] Digits ::= [0-9]+
5760 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005761 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005762 *
5763 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005764static void
5765xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005766 double ret = 0.0;
5767 double mult = 1;
5768 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005769 int exponent = 0;
5770 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005771
5772 CHECK_ERROR;
5773 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5774 XP_ERROR(XPATH_NUMBER_ERROR);
5775 }
5776 while ((CUR >= '0') && (CUR <= '9')) {
5777 ret = ret * 10 + (CUR - '0');
5778 ok = 1;
5779 NEXT;
5780 }
5781 if (CUR == '.') {
5782 NEXT;
5783 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5784 XP_ERROR(XPATH_NUMBER_ERROR);
5785 }
5786 while ((CUR >= '0') && (CUR <= '9')) {
5787 mult /= 10;
5788 ret = ret + (CUR - '0') * mult;
5789 NEXT;
5790 }
5791 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005792 if ((CUR == 'e') || (CUR == 'E')) {
5793 NEXT;
5794 if (CUR == '-') {
5795 is_exponent_negative = 1;
5796 NEXT;
5797 }
5798 while ((CUR >= '0') && (CUR <= '9')) {
5799 exponent = exponent * 10 + (CUR - '0');
5800 NEXT;
5801 }
5802 }
5803 if (is_exponent_negative)
5804 exponent = -exponent;
5805 ret *= pow(10.0, (double)exponent);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005806 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5807 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005808}
5809
5810/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005811 * xmlXPathParseLiteral:
5812 * @ctxt: the XPath Parser context
5813 *
5814 * Parse a Literal
5815 *
5816 * [29] Literal ::= '"' [^"]* '"'
5817 * | "'" [^']* "'"
5818 *
5819 * Returns the value found or NULL in case of error
5820 */
5821static xmlChar *
5822xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5823 const xmlChar *q;
5824 xmlChar *ret = NULL;
5825
5826 if (CUR == '"') {
5827 NEXT;
5828 q = CUR_PTR;
5829 while ((IS_CHAR(CUR)) && (CUR != '"'))
5830 NEXT;
5831 if (!IS_CHAR(CUR)) {
5832 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5833 } else {
5834 ret = xmlStrndup(q, CUR_PTR - q);
5835 NEXT;
5836 }
5837 } else if (CUR == '\'') {
5838 NEXT;
5839 q = CUR_PTR;
5840 while ((IS_CHAR(CUR)) && (CUR != '\''))
5841 NEXT;
5842 if (!IS_CHAR(CUR)) {
5843 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5844 } else {
5845 ret = xmlStrndup(q, CUR_PTR - q);
5846 NEXT;
5847 }
5848 } else {
5849 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5850 }
5851 return(ret);
5852}
5853
5854/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005855 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005856 * @ctxt: the XPath Parser context
5857 *
5858 * Parse a Literal and push it on the stack.
5859 *
5860 * [29] Literal ::= '"' [^"]* '"'
5861 * | "'" [^']* "'"
5862 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005863 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005864 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005865static void
5866xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005867 const xmlChar *q;
5868 xmlChar *ret = NULL;
5869
5870 if (CUR == '"') {
5871 NEXT;
5872 q = CUR_PTR;
5873 while ((IS_CHAR(CUR)) && (CUR != '"'))
5874 NEXT;
5875 if (!IS_CHAR(CUR)) {
5876 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5877 } else {
5878 ret = xmlStrndup(q, CUR_PTR - q);
5879 NEXT;
5880 }
5881 } else if (CUR == '\'') {
5882 NEXT;
5883 q = CUR_PTR;
5884 while ((IS_CHAR(CUR)) && (CUR != '\''))
5885 NEXT;
5886 if (!IS_CHAR(CUR)) {
5887 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5888 } else {
5889 ret = xmlStrndup(q, CUR_PTR - q);
5890 NEXT;
5891 }
5892 } else {
5893 XP_ERROR(XPATH_START_LITERAL_ERROR);
5894 }
5895 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005896 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5897 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005898 xmlFree(ret);
5899}
5900
5901/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005902 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005903 * @ctxt: the XPath Parser context
5904 *
5905 * Parse a VariableReference, evaluate it and push it on the stack.
5906 *
5907 * The variable bindings consist of a mapping from variable names
5908 * to variable values. The value of a variable is an object, which
5909 * of any of the types that are possible for the value of an expression,
5910 * and may also be of additional types not specified here.
5911 *
5912 * Early evaluation is possible since:
5913 * The variable bindings [...] used to evaluate a subexpression are
5914 * always the same as those used to evaluate the containing expression.
5915 *
5916 * [36] VariableReference ::= '$' QName
5917 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005918static void
5919xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005920 xmlChar *name;
5921 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005922
5923 SKIP_BLANKS;
5924 if (CUR != '$') {
5925 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5926 }
5927 NEXT;
5928 name = xmlXPathParseQName(ctxt, &prefix);
5929 if (name == NULL) {
5930 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5931 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005932 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005933 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5934 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005935 SKIP_BLANKS;
5936}
5937
5938/**
5939 * xmlXPathIsNodeType:
5940 * @ctxt: the XPath Parser context
5941 * @name: a name string
5942 *
5943 * Is the name given a NodeType one.
5944 *
5945 * [38] NodeType ::= 'comment'
5946 * | 'text'
5947 * | 'processing-instruction'
5948 * | 'node'
5949 *
5950 * Returns 1 if true 0 otherwise
5951 */
5952int
5953xmlXPathIsNodeType(const xmlChar *name) {
5954 if (name == NULL)
5955 return(0);
5956
5957 if (xmlStrEqual(name, BAD_CAST "comment"))
5958 return(1);
5959 if (xmlStrEqual(name, BAD_CAST "text"))
5960 return(1);
5961 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5962 return(1);
5963 if (xmlStrEqual(name, BAD_CAST "node"))
5964 return(1);
5965 return(0);
5966}
5967
5968/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005969 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005970 * @ctxt: the XPath Parser context
5971 *
5972 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5973 * [17] Argument ::= Expr
5974 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005975 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00005976 * pushed on the stack
5977 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005978static void
5979xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005980 xmlChar *name;
5981 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005982 int nbargs = 0;
5983
5984 name = xmlXPathParseQName(ctxt, &prefix);
5985 if (name == NULL) {
5986 XP_ERROR(XPATH_EXPR_ERROR);
5987 }
5988 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005989#ifdef DEBUG_EXPR
5990 if (prefix == NULL)
5991 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5992 name);
5993 else
5994 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5995 prefix, name);
5996#endif
5997
Owen Taylor3473f882001-02-23 17:55:21 +00005998 if (CUR != '(') {
5999 XP_ERROR(XPATH_EXPR_ERROR);
6000 }
6001 NEXT;
6002 SKIP_BLANKS;
6003
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006004 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006005 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006006 int op1 = ctxt->comp->last;
6007 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006008 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006009 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006010 nbargs++;
6011 if (CUR == ')') break;
6012 if (CUR != ',') {
6013 XP_ERROR(XPATH_EXPR_ERROR);
6014 }
6015 NEXT;
6016 SKIP_BLANKS;
6017 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006018 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6019 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006020 NEXT;
6021 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006022}
6023
6024/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006025 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006026 * @ctxt: the XPath Parser context
6027 *
6028 * [15] PrimaryExpr ::= VariableReference
6029 * | '(' Expr ')'
6030 * | Literal
6031 * | Number
6032 * | FunctionCall
6033 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006034 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006035 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006036static void
6037xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006038 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006039 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006040 else if (CUR == '(') {
6041 NEXT;
6042 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006043 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006044 if (CUR != ')') {
6045 XP_ERROR(XPATH_EXPR_ERROR);
6046 }
6047 NEXT;
6048 SKIP_BLANKS;
6049 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006050 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006051 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006052 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006053 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006054 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006055 }
6056 SKIP_BLANKS;
6057}
6058
6059/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006060 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006061 * @ctxt: the XPath Parser context
6062 *
6063 * [20] FilterExpr ::= PrimaryExpr
6064 * | FilterExpr Predicate
6065 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006066 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006067 * Square brackets are used to filter expressions in the same way that
6068 * they are used in location paths. It is an error if the expression to
6069 * be filtered does not evaluate to a node-set. The context node list
6070 * used for evaluating the expression in square brackets is the node-set
6071 * to be filtered listed in document order.
6072 */
6073
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006074static void
6075xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6076 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006077 CHECK_ERROR;
6078 SKIP_BLANKS;
6079
6080 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006081 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006082 SKIP_BLANKS;
6083 }
6084
6085
6086}
6087
6088/**
6089 * xmlXPathScanName:
6090 * @ctxt: the XPath Parser context
6091 *
6092 * Trickery: parse an XML name but without consuming the input flow
6093 * Needed to avoid insanity in the parser state.
6094 *
6095 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6096 * CombiningChar | Extender
6097 *
6098 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6099 *
6100 * [6] Names ::= Name (S Name)*
6101 *
6102 * Returns the Name parsed or NULL
6103 */
6104
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006105static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006106xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6107 xmlChar buf[XML_MAX_NAMELEN];
6108 int len = 0;
6109
6110 SKIP_BLANKS;
6111 if (!IS_LETTER(CUR) && (CUR != '_') &&
6112 (CUR != ':')) {
6113 return(NULL);
6114 }
6115
6116 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6117 (NXT(len) == '.') || (NXT(len) == '-') ||
6118 (NXT(len) == '_') || (NXT(len) == ':') ||
6119 (IS_COMBINING(NXT(len))) ||
6120 (IS_EXTENDER(NXT(len)))) {
6121 buf[len] = NXT(len);
6122 len++;
6123 if (len >= XML_MAX_NAMELEN) {
6124 xmlGenericError(xmlGenericErrorContext,
6125 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6126 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6127 (NXT(len) == '.') || (NXT(len) == '-') ||
6128 (NXT(len) == '_') || (NXT(len) == ':') ||
6129 (IS_COMBINING(NXT(len))) ||
6130 (IS_EXTENDER(NXT(len))))
6131 len++;
6132 break;
6133 }
6134 }
6135 return(xmlStrndup(buf, len));
6136}
6137
6138/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006139 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006140 * @ctxt: the XPath Parser context
6141 *
6142 * [19] PathExpr ::= LocationPath
6143 * | FilterExpr
6144 * | FilterExpr '/' RelativeLocationPath
6145 * | FilterExpr '//' RelativeLocationPath
6146 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006147 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006148 * The / operator and // operators combine an arbitrary expression
6149 * and a relative location path. It is an error if the expression
6150 * does not evaluate to a node-set.
6151 * The / operator does composition in the same way as when / is
6152 * used in a location path. As in location paths, // is short for
6153 * /descendant-or-self::node()/.
6154 */
6155
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006156static void
6157xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006158 int lc = 1; /* Should we branch to LocationPath ? */
6159 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6160
6161 SKIP_BLANKS;
6162 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6163 (CUR == '\'') || (CUR == '"')) {
6164 lc = 0;
6165 } else if (CUR == '*') {
6166 /* relative or absolute location path */
6167 lc = 1;
6168 } else if (CUR == '/') {
6169 /* relative or absolute location path */
6170 lc = 1;
6171 } else if (CUR == '@') {
6172 /* relative abbreviated attribute location path */
6173 lc = 1;
6174 } else if (CUR == '.') {
6175 /* relative abbreviated attribute location path */
6176 lc = 1;
6177 } else {
6178 /*
6179 * Problem is finding if we have a name here whether it's:
6180 * - a nodetype
6181 * - a function call in which case it's followed by '('
6182 * - an axis in which case it's followed by ':'
6183 * - a element name
6184 * We do an a priori analysis here rather than having to
6185 * maintain parsed token content through the recursive function
6186 * calls. This looks uglier but makes the code quite easier to
6187 * read/write/debug.
6188 */
6189 SKIP_BLANKS;
6190 name = xmlXPathScanName(ctxt);
6191 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6192#ifdef DEBUG_STEP
6193 xmlGenericError(xmlGenericErrorContext,
6194 "PathExpr: Axis\n");
6195#endif
6196 lc = 1;
6197 xmlFree(name);
6198 } else if (name != NULL) {
6199 int len =xmlStrlen(name);
6200 int blank = 0;
6201
6202
6203 while (NXT(len) != 0) {
6204 if (NXT(len) == '/') {
6205 /* element name */
6206#ifdef DEBUG_STEP
6207 xmlGenericError(xmlGenericErrorContext,
6208 "PathExpr: AbbrRelLocation\n");
6209#endif
6210 lc = 1;
6211 break;
6212 } else if (IS_BLANK(NXT(len))) {
6213 /* skip to next */
6214 blank = 1;
6215 } else if (NXT(len) == ':') {
6216#ifdef DEBUG_STEP
6217 xmlGenericError(xmlGenericErrorContext,
6218 "PathExpr: AbbrRelLocation\n");
6219#endif
6220 lc = 1;
6221 break;
6222 } else if ((NXT(len) == '(')) {
6223 /* Note Type or Function */
6224 if (xmlXPathIsNodeType(name)) {
6225#ifdef DEBUG_STEP
6226 xmlGenericError(xmlGenericErrorContext,
6227 "PathExpr: Type search\n");
6228#endif
6229 lc = 1;
6230 } else {
6231#ifdef DEBUG_STEP
6232 xmlGenericError(xmlGenericErrorContext,
6233 "PathExpr: function call\n");
6234#endif
6235 lc = 0;
6236 }
6237 break;
6238 } else if ((NXT(len) == '[')) {
6239 /* element name */
6240#ifdef DEBUG_STEP
6241 xmlGenericError(xmlGenericErrorContext,
6242 "PathExpr: AbbrRelLocation\n");
6243#endif
6244 lc = 1;
6245 break;
6246 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6247 (NXT(len) == '=')) {
6248 lc = 1;
6249 break;
6250 } else {
6251 lc = 1;
6252 break;
6253 }
6254 len++;
6255 }
6256 if (NXT(len) == 0) {
6257#ifdef DEBUG_STEP
6258 xmlGenericError(xmlGenericErrorContext,
6259 "PathExpr: AbbrRelLocation\n");
6260#endif
6261 /* element name */
6262 lc = 1;
6263 }
6264 xmlFree(name);
6265 } else {
6266 /* make sure all cases are covered explicitely */
6267 XP_ERROR(XPATH_EXPR_ERROR);
6268 }
6269 }
6270
6271 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006272 if (CUR == '/') {
6273 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6274 } else {
6275 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006276 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006277 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006278 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006279 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006280 CHECK_ERROR;
6281 if ((CUR == '/') && (NXT(1) == '/')) {
6282 SKIP(2);
6283 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006284
6285 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6286 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6287 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6288
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006289 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006290 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006291 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006292 }
6293 }
6294 SKIP_BLANKS;
6295}
6296
6297/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006298 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006299 * @ctxt: the XPath Parser context
6300 *
6301 * [18] UnionExpr ::= PathExpr
6302 * | UnionExpr '|' PathExpr
6303 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006304 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006305 */
6306
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006307static void
6308xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6309 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006310 CHECK_ERROR;
6311 SKIP_BLANKS;
6312 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006313 int op1 = ctxt->comp->last;
6314 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006315
6316 NEXT;
6317 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006318 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006319
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006320 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6321
Owen Taylor3473f882001-02-23 17:55:21 +00006322 SKIP_BLANKS;
6323 }
Owen Taylor3473f882001-02-23 17:55:21 +00006324}
6325
6326/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006327 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006328 * @ctxt: the XPath Parser context
6329 *
6330 * [27] UnaryExpr ::= UnionExpr
6331 * | '-' UnaryExpr
6332 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006333 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006334 */
6335
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006336static void
6337xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006338 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006339 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006340
6341 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006342 while (CUR == '-') {
6343 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006344 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006345 NEXT;
6346 SKIP_BLANKS;
6347 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006348
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006349 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006350 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006351 if (found) {
6352 if (minus)
6353 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6354 else
6355 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006356 }
6357}
6358
6359/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006360 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006361 * @ctxt: the XPath Parser context
6362 *
6363 * [26] MultiplicativeExpr ::= UnaryExpr
6364 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6365 * | MultiplicativeExpr 'div' UnaryExpr
6366 * | MultiplicativeExpr 'mod' UnaryExpr
6367 * [34] MultiplyOperator ::= '*'
6368 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006369 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006370 */
6371
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006372static void
6373xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6374 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006375 CHECK_ERROR;
6376 SKIP_BLANKS;
6377 while ((CUR == '*') ||
6378 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6379 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6380 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006381 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006382
6383 if (CUR == '*') {
6384 op = 0;
6385 NEXT;
6386 } else if (CUR == 'd') {
6387 op = 1;
6388 SKIP(3);
6389 } else if (CUR == 'm') {
6390 op = 2;
6391 SKIP(3);
6392 }
6393 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006394 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006395 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006396 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006397 SKIP_BLANKS;
6398 }
6399}
6400
6401/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006402 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006403 * @ctxt: the XPath Parser context
6404 *
6405 * [25] AdditiveExpr ::= MultiplicativeExpr
6406 * | AdditiveExpr '+' MultiplicativeExpr
6407 * | AdditiveExpr '-' MultiplicativeExpr
6408 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006409 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006410 */
6411
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006412static void
6413xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006414
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006415 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006416 CHECK_ERROR;
6417 SKIP_BLANKS;
6418 while ((CUR == '+') || (CUR == '-')) {
6419 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006420 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006421
6422 if (CUR == '+') plus = 1;
6423 else plus = 0;
6424 NEXT;
6425 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006426 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006427 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006428 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006429 SKIP_BLANKS;
6430 }
6431}
6432
6433/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006434 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006435 * @ctxt: the XPath Parser context
6436 *
6437 * [24] RelationalExpr ::= AdditiveExpr
6438 * | RelationalExpr '<' AdditiveExpr
6439 * | RelationalExpr '>' AdditiveExpr
6440 * | RelationalExpr '<=' AdditiveExpr
6441 * | RelationalExpr '>=' AdditiveExpr
6442 *
6443 * A <= B > C is allowed ? Answer from James, yes with
6444 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6445 * which is basically what got implemented.
6446 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006447 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006448 * on the stack
6449 */
6450
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006451static void
6452xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6453 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006454 CHECK_ERROR;
6455 SKIP_BLANKS;
6456 while ((CUR == '<') ||
6457 (CUR == '>') ||
6458 ((CUR == '<') && (NXT(1) == '=')) ||
6459 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006460 int inf, strict;
6461 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006462
6463 if (CUR == '<') inf = 1;
6464 else inf = 0;
6465 if (NXT(1) == '=') strict = 0;
6466 else strict = 1;
6467 NEXT;
6468 if (!strict) NEXT;
6469 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006470 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006471 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006472 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006473 SKIP_BLANKS;
6474 }
6475}
6476
6477/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006478 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006479 * @ctxt: the XPath Parser context
6480 *
6481 * [23] EqualityExpr ::= RelationalExpr
6482 * | EqualityExpr '=' RelationalExpr
6483 * | EqualityExpr '!=' RelationalExpr
6484 *
6485 * A != B != C is allowed ? Answer from James, yes with
6486 * (RelationalExpr = RelationalExpr) = RelationalExpr
6487 * (RelationalExpr != RelationalExpr) != RelationalExpr
6488 * which is basically what got implemented.
6489 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006490 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006491 *
6492 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006493static void
6494xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6495 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006496 CHECK_ERROR;
6497 SKIP_BLANKS;
6498 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006499 int eq;
6500 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006501
6502 if (CUR == '=') eq = 1;
6503 else eq = 0;
6504 NEXT;
6505 if (!eq) NEXT;
6506 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006507 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006508 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006509 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006510 SKIP_BLANKS;
6511 }
6512}
6513
6514/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006515 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006516 * @ctxt: the XPath Parser context
6517 *
6518 * [22] AndExpr ::= EqualityExpr
6519 * | AndExpr 'and' EqualityExpr
6520 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006521 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006522 *
6523 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006524static void
6525xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6526 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006527 CHECK_ERROR;
6528 SKIP_BLANKS;
6529 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006530 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006531 SKIP(3);
6532 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006533 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006534 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006535 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006536 SKIP_BLANKS;
6537 }
6538}
6539
6540/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006541 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006542 * @ctxt: the XPath Parser context
6543 *
6544 * [14] Expr ::= OrExpr
6545 * [21] OrExpr ::= AndExpr
6546 * | OrExpr 'or' AndExpr
6547 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006548 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006549 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006550static void
6551xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6552 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006553 CHECK_ERROR;
6554 SKIP_BLANKS;
6555 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006556 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006557 SKIP(2);
6558 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006559 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006560 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006561 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6562 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006563 SKIP_BLANKS;
6564 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006565 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6566 /* more ops could be optimized too */
6567 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6568 }
Owen Taylor3473f882001-02-23 17:55:21 +00006569}
6570
6571/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006572 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006573 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006574 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006575 *
6576 * [8] Predicate ::= '[' PredicateExpr ']'
6577 * [9] PredicateExpr ::= Expr
6578 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006579 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006580 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006581static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006582xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006583 int op1 = ctxt->comp->last;
6584
6585 SKIP_BLANKS;
6586 if (CUR != '[') {
6587 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6588 }
6589 NEXT;
6590 SKIP_BLANKS;
6591
6592 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006593 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006594 CHECK_ERROR;
6595
6596 if (CUR != ']') {
6597 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6598 }
6599
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006600 if (filter)
6601 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6602 else
6603 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006604
6605 NEXT;
6606 SKIP_BLANKS;
6607}
6608
6609/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006610 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006611 * @ctxt: the XPath Parser context
6612 * @test: pointer to a xmlXPathTestVal
6613 * @type: pointer to a xmlXPathTypeVal
6614 * @prefix: placeholder for a possible name prefix
6615 *
6616 * [7] NodeTest ::= NameTest
6617 * | NodeType '(' ')'
6618 * | 'processing-instruction' '(' Literal ')'
6619 *
6620 * [37] NameTest ::= '*'
6621 * | NCName ':' '*'
6622 * | QName
6623 * [38] NodeType ::= 'comment'
6624 * | 'text'
6625 * | 'processing-instruction'
6626 * | 'node'
6627 *
6628 * Returns the name found and update @test, @type and @prefix appropriately
6629 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006630static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006631xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6632 xmlXPathTypeVal *type, const xmlChar **prefix,
6633 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006634 int blanks;
6635
6636 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6637 STRANGE;
6638 return(NULL);
6639 }
6640 *type = 0;
6641 *test = 0;
6642 *prefix = NULL;
6643 SKIP_BLANKS;
6644
6645 if ((name == NULL) && (CUR == '*')) {
6646 /*
6647 * All elements
6648 */
6649 NEXT;
6650 *test = NODE_TEST_ALL;
6651 return(NULL);
6652 }
6653
6654 if (name == NULL)
6655 name = xmlXPathParseNCName(ctxt);
6656 if (name == NULL) {
6657 XP_ERROR0(XPATH_EXPR_ERROR);
6658 }
6659
6660 blanks = IS_BLANK(CUR);
6661 SKIP_BLANKS;
6662 if (CUR == '(') {
6663 NEXT;
6664 /*
6665 * NodeType or PI search
6666 */
6667 if (xmlStrEqual(name, BAD_CAST "comment"))
6668 *type = NODE_TYPE_COMMENT;
6669 else if (xmlStrEqual(name, BAD_CAST "node"))
6670 *type = NODE_TYPE_NODE;
6671 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6672 *type = NODE_TYPE_PI;
6673 else if (xmlStrEqual(name, BAD_CAST "text"))
6674 *type = NODE_TYPE_TEXT;
6675 else {
6676 if (name != NULL)
6677 xmlFree(name);
6678 XP_ERROR0(XPATH_EXPR_ERROR);
6679 }
6680
6681 *test = NODE_TEST_TYPE;
6682
6683 SKIP_BLANKS;
6684 if (*type == NODE_TYPE_PI) {
6685 /*
6686 * Specific case: search a PI by name.
6687 */
Owen Taylor3473f882001-02-23 17:55:21 +00006688 if (name != NULL)
6689 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006690 name = NULL;
6691 if (CUR != ')') {
6692 name = xmlXPathParseLiteral(ctxt);
6693 CHECK_ERROR 0;
6694 SKIP_BLANKS;
6695 }
Owen Taylor3473f882001-02-23 17:55:21 +00006696 }
6697 if (CUR != ')') {
6698 if (name != NULL)
6699 xmlFree(name);
6700 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6701 }
6702 NEXT;
6703 return(name);
6704 }
6705 *test = NODE_TEST_NAME;
6706 if ((!blanks) && (CUR == ':')) {
6707 NEXT;
6708
6709 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006710 * Since currently the parser context don't have a
6711 * namespace list associated:
6712 * The namespace name for this prefix can be computed
6713 * only at evaluation time. The compilation is done
6714 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006715 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006716#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006717 *prefix = xmlXPathNsLookup(ctxt->context, name);
6718 if (name != NULL)
6719 xmlFree(name);
6720 if (*prefix == NULL) {
6721 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6722 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006723#else
6724 *prefix = name;
6725#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006726
6727 if (CUR == '*') {
6728 /*
6729 * All elements
6730 */
6731 NEXT;
6732 *test = NODE_TEST_ALL;
6733 return(NULL);
6734 }
6735
6736 name = xmlXPathParseNCName(ctxt);
6737 if (name == NULL) {
6738 XP_ERROR0(XPATH_EXPR_ERROR);
6739 }
6740 }
6741 return(name);
6742}
6743
6744/**
6745 * xmlXPathIsAxisName:
6746 * @name: a preparsed name token
6747 *
6748 * [6] AxisName ::= 'ancestor'
6749 * | 'ancestor-or-self'
6750 * | 'attribute'
6751 * | 'child'
6752 * | 'descendant'
6753 * | 'descendant-or-self'
6754 * | 'following'
6755 * | 'following-sibling'
6756 * | 'namespace'
6757 * | 'parent'
6758 * | 'preceding'
6759 * | 'preceding-sibling'
6760 * | 'self'
6761 *
6762 * Returns the axis or 0
6763 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006764static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006765xmlXPathIsAxisName(const xmlChar *name) {
6766 xmlXPathAxisVal ret = 0;
6767 switch (name[0]) {
6768 case 'a':
6769 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6770 ret = AXIS_ANCESTOR;
6771 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6772 ret = AXIS_ANCESTOR_OR_SELF;
6773 if (xmlStrEqual(name, BAD_CAST "attribute"))
6774 ret = AXIS_ATTRIBUTE;
6775 break;
6776 case 'c':
6777 if (xmlStrEqual(name, BAD_CAST "child"))
6778 ret = AXIS_CHILD;
6779 break;
6780 case 'd':
6781 if (xmlStrEqual(name, BAD_CAST "descendant"))
6782 ret = AXIS_DESCENDANT;
6783 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6784 ret = AXIS_DESCENDANT_OR_SELF;
6785 break;
6786 case 'f':
6787 if (xmlStrEqual(name, BAD_CAST "following"))
6788 ret = AXIS_FOLLOWING;
6789 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6790 ret = AXIS_FOLLOWING_SIBLING;
6791 break;
6792 case 'n':
6793 if (xmlStrEqual(name, BAD_CAST "namespace"))
6794 ret = AXIS_NAMESPACE;
6795 break;
6796 case 'p':
6797 if (xmlStrEqual(name, BAD_CAST "parent"))
6798 ret = AXIS_PARENT;
6799 if (xmlStrEqual(name, BAD_CAST "preceding"))
6800 ret = AXIS_PRECEDING;
6801 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6802 ret = AXIS_PRECEDING_SIBLING;
6803 break;
6804 case 's':
6805 if (xmlStrEqual(name, BAD_CAST "self"))
6806 ret = AXIS_SELF;
6807 break;
6808 }
6809 return(ret);
6810}
6811
6812/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006813 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006814 * @ctxt: the XPath Parser context
6815 *
6816 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6817 * | AbbreviatedStep
6818 *
6819 * [12] AbbreviatedStep ::= '.' | '..'
6820 *
6821 * [5] AxisSpecifier ::= AxisName '::'
6822 * | AbbreviatedAxisSpecifier
6823 *
6824 * [13] AbbreviatedAxisSpecifier ::= '@'?
6825 *
6826 * Modified for XPtr range support as:
6827 *
6828 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6829 * | AbbreviatedStep
6830 * | 'range-to' '(' Expr ')' Predicate*
6831 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006832 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006833 * A location step of . is short for self::node(). This is
6834 * particularly useful in conjunction with //. For example, the
6835 * location path .//para is short for
6836 * self::node()/descendant-or-self::node()/child::para
6837 * and so will select all para descendant elements of the context
6838 * node.
6839 * Similarly, a location step of .. is short for parent::node().
6840 * For example, ../title is short for parent::node()/child::title
6841 * and so will select the title children of the parent of the context
6842 * node.
6843 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006844static void
6845xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006846#ifdef LIBXML_XPTR_ENABLED
6847 int rangeto = 0;
6848 int op2 = -1;
6849#endif
6850
Owen Taylor3473f882001-02-23 17:55:21 +00006851 SKIP_BLANKS;
6852 if ((CUR == '.') && (NXT(1) == '.')) {
6853 SKIP(2);
6854 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006855 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6856 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006857 } else if (CUR == '.') {
6858 NEXT;
6859 SKIP_BLANKS;
6860 } else {
6861 xmlChar *name = NULL;
6862 const xmlChar *prefix = NULL;
6863 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006864 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006865 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006866 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006867
6868 /*
6869 * The modification needed for XPointer change to the production
6870 */
6871#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006872 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006873 name = xmlXPathParseNCName(ctxt);
6874 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006875 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006876 xmlFree(name);
6877 SKIP_BLANKS;
6878 if (CUR != '(') {
6879 XP_ERROR(XPATH_EXPR_ERROR);
6880 }
6881 NEXT;
6882 SKIP_BLANKS;
6883
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006884 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006885 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006886 CHECK_ERROR;
6887
6888 SKIP_BLANKS;
6889 if (CUR != ')') {
6890 XP_ERROR(XPATH_EXPR_ERROR);
6891 }
6892 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006893 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006894 goto eval_predicates;
6895 }
6896 }
6897#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006898 if (CUR == '*') {
6899 axis = AXIS_CHILD;
6900 } else {
6901 if (name == NULL)
6902 name = xmlXPathParseNCName(ctxt);
6903 if (name != NULL) {
6904 axis = xmlXPathIsAxisName(name);
6905 if (axis != 0) {
6906 SKIP_BLANKS;
6907 if ((CUR == ':') && (NXT(1) == ':')) {
6908 SKIP(2);
6909 xmlFree(name);
6910 name = NULL;
6911 } else {
6912 /* an element name can conflict with an axis one :-\ */
6913 axis = AXIS_CHILD;
6914 }
Owen Taylor3473f882001-02-23 17:55:21 +00006915 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00006916 axis = AXIS_CHILD;
6917 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006918 } else if (CUR == '@') {
6919 NEXT;
6920 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00006921 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00006922 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00006923 }
Owen Taylor3473f882001-02-23 17:55:21 +00006924 }
6925
6926 CHECK_ERROR;
6927
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006928 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006929 if (test == 0)
6930 return;
6931
6932#ifdef DEBUG_STEP
6933 xmlGenericError(xmlGenericErrorContext,
6934 "Basis : computing new set\n");
6935#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006936
Owen Taylor3473f882001-02-23 17:55:21 +00006937#ifdef DEBUG_STEP
6938 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006939 if (ctxt->value == NULL)
6940 xmlGenericError(xmlGenericErrorContext, "no value\n");
6941 else if (ctxt->value->nodesetval == NULL)
6942 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6943 else
6944 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006945#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006946
6947eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006948 op1 = ctxt->comp->last;
6949 ctxt->comp->last = -1;
6950
Owen Taylor3473f882001-02-23 17:55:21 +00006951 SKIP_BLANKS;
6952 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006953 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006954 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006955
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006956#ifdef LIBXML_XPTR_ENABLED
6957 if (rangeto) {
6958 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
6959 } else
6960#endif
6961 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
6962 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006963
Owen Taylor3473f882001-02-23 17:55:21 +00006964 }
6965#ifdef DEBUG_STEP
6966 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006967 if (ctxt->value == NULL)
6968 xmlGenericError(xmlGenericErrorContext, "no value\n");
6969 else if (ctxt->value->nodesetval == NULL)
6970 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6971 else
6972 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6973 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006974#endif
6975}
6976
6977/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006978 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006979 * @ctxt: the XPath Parser context
6980 *
6981 * [3] RelativeLocationPath ::= Step
6982 * | RelativeLocationPath '/' Step
6983 * | AbbreviatedRelativeLocationPath
6984 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6985 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006986 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00006987 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006988static void
Owen Taylor3473f882001-02-23 17:55:21 +00006989#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006990xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006991#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006992xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006993#endif
6994(xmlXPathParserContextPtr ctxt) {
6995 SKIP_BLANKS;
6996 if ((CUR == '/') && (NXT(1) == '/')) {
6997 SKIP(2);
6998 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006999 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7000 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007001 } else if (CUR == '/') {
7002 NEXT;
7003 SKIP_BLANKS;
7004 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007005 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007006 SKIP_BLANKS;
7007 while (CUR == '/') {
7008 if ((CUR == '/') && (NXT(1) == '/')) {
7009 SKIP(2);
7010 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007011 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007012 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007013 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007014 } else if (CUR == '/') {
7015 NEXT;
7016 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007017 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007018 }
7019 SKIP_BLANKS;
7020 }
7021}
7022
7023/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007024 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007025 * @ctxt: the XPath Parser context
7026 *
7027 * [1] LocationPath ::= RelativeLocationPath
7028 * | AbsoluteLocationPath
7029 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7030 * | AbbreviatedAbsoluteLocationPath
7031 * [10] AbbreviatedAbsoluteLocationPath ::=
7032 * '//' RelativeLocationPath
7033 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007034 * Compile a location path
7035 *
Owen Taylor3473f882001-02-23 17:55:21 +00007036 * // is short for /descendant-or-self::node()/. For example,
7037 * //para is short for /descendant-or-self::node()/child::para and
7038 * so will select any para element in the document (even a para element
7039 * that is a document element will be selected by //para since the
7040 * document element node is a child of the root node); div//para is
7041 * short for div/descendant-or-self::node()/child::para and so will
7042 * select all para descendants of div children.
7043 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007044static void
7045xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007046 SKIP_BLANKS;
7047 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007048 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007049 } else {
7050 while (CUR == '/') {
7051 if ((CUR == '/') && (NXT(1) == '/')) {
7052 SKIP(2);
7053 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007054 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7055 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007056 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007057 } else if (CUR == '/') {
7058 NEXT;
7059 SKIP_BLANKS;
7060 if (CUR != 0)
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007061 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007062 }
7063 }
7064 }
7065}
7066
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007067/************************************************************************
7068 * *
7069 * XPath precompiled expression evaluation *
7070 * *
7071 ************************************************************************/
7072
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007073static void
7074xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7075
7076/**
7077 * xmlXPathNodeCollectAndTest:
7078 * @ctxt: the XPath Parser context
7079 * @op: the XPath precompiled step operation
7080 *
7081 * This is the function implementing a step: based on the current list
7082 * of nodes, it builds up a new list, looking at all nodes under that
7083 * axis and selecting them it also do the predicate filtering
7084 *
7085 * Pushes the new NodeSet resulting from the search.
7086 */
7087static void
7088xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
7089 xmlXPathStepOpPtr op) {
7090 xmlXPathAxisVal axis = op->value;
7091 xmlXPathTestVal test = op->value2;
7092 xmlXPathTypeVal type = op->value3;
7093 const xmlChar *prefix = op->value4;
7094 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007095 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007096
7097#ifdef DEBUG_STEP
7098 int n = 0, t = 0;
7099#endif
7100 int i;
7101 xmlNodeSetPtr ret, list;
7102 xmlXPathTraversalFunction next = NULL;
7103 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
7104 xmlNodePtr cur = NULL;
7105 xmlXPathObjectPtr obj;
7106 xmlNodeSetPtr nodelist;
7107 xmlNodePtr tmp;
7108
7109 CHECK_TYPE(XPATH_NODESET);
7110 obj = valuePop(ctxt);
7111 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007112 if (prefix != NULL) {
7113 URI = xmlXPathNsLookup(ctxt->context, prefix);
7114 if (URI == NULL)
7115 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
7116 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007117
7118#ifdef DEBUG_STEP
7119 xmlGenericError(xmlGenericErrorContext,
7120 "new step : ");
7121#endif
7122 switch (axis) {
7123 case AXIS_ANCESTOR:
7124#ifdef DEBUG_STEP
7125 xmlGenericError(xmlGenericErrorContext,
7126 "axis 'ancestors' ");
7127#endif
7128 next = xmlXPathNextAncestor; break;
7129 case AXIS_ANCESTOR_OR_SELF:
7130#ifdef DEBUG_STEP
7131 xmlGenericError(xmlGenericErrorContext,
7132 "axis 'ancestors-or-self' ");
7133#endif
7134 next = xmlXPathNextAncestorOrSelf; break;
7135 case AXIS_ATTRIBUTE:
7136#ifdef DEBUG_STEP
7137 xmlGenericError(xmlGenericErrorContext,
7138 "axis 'attributes' ");
7139#endif
7140 next = xmlXPathNextAttribute; break;
7141 break;
7142 case AXIS_CHILD:
7143#ifdef DEBUG_STEP
7144 xmlGenericError(xmlGenericErrorContext,
7145 "axis 'child' ");
7146#endif
7147 next = xmlXPathNextChild; break;
7148 case AXIS_DESCENDANT:
7149#ifdef DEBUG_STEP
7150 xmlGenericError(xmlGenericErrorContext,
7151 "axis 'descendant' ");
7152#endif
7153 next = xmlXPathNextDescendant; break;
7154 case AXIS_DESCENDANT_OR_SELF:
7155#ifdef DEBUG_STEP
7156 xmlGenericError(xmlGenericErrorContext,
7157 "axis 'descendant-or-self' ");
7158#endif
7159 next = xmlXPathNextDescendantOrSelf; break;
7160 case AXIS_FOLLOWING:
7161#ifdef DEBUG_STEP
7162 xmlGenericError(xmlGenericErrorContext,
7163 "axis 'following' ");
7164#endif
7165 next = xmlXPathNextFollowing; break;
7166 case AXIS_FOLLOWING_SIBLING:
7167#ifdef DEBUG_STEP
7168 xmlGenericError(xmlGenericErrorContext,
7169 "axis 'following-siblings' ");
7170#endif
7171 next = xmlXPathNextFollowingSibling; break;
7172 case AXIS_NAMESPACE:
7173#ifdef DEBUG_STEP
7174 xmlGenericError(xmlGenericErrorContext,
7175 "axis 'namespace' ");
7176#endif
7177 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
7178 break;
7179 case AXIS_PARENT:
7180#ifdef DEBUG_STEP
7181 xmlGenericError(xmlGenericErrorContext,
7182 "axis 'parent' ");
7183#endif
7184 next = xmlXPathNextParent; break;
7185 case AXIS_PRECEDING:
7186#ifdef DEBUG_STEP
7187 xmlGenericError(xmlGenericErrorContext,
7188 "axis 'preceding' ");
7189#endif
7190 next = xmlXPathNextPreceding; break;
7191 case AXIS_PRECEDING_SIBLING:
7192#ifdef DEBUG_STEP
7193 xmlGenericError(xmlGenericErrorContext,
7194 "axis 'preceding-sibling' ");
7195#endif
7196 next = xmlXPathNextPrecedingSibling; break;
7197 case AXIS_SELF:
7198#ifdef DEBUG_STEP
7199 xmlGenericError(xmlGenericErrorContext,
7200 "axis 'self' ");
7201#endif
7202 next = xmlXPathNextSelf; break;
7203 }
7204 if (next == NULL)
7205 return;
7206
7207 nodelist = obj->nodesetval;
7208 if (nodelist == NULL) {
7209 xmlXPathFreeObject(obj);
7210 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7211 return;
7212 }
7213 addNode = xmlXPathNodeSetAddUnique;
7214 ret = NULL;
7215#ifdef DEBUG_STEP
7216 xmlGenericError(xmlGenericErrorContext,
7217 " context contains %d nodes\n",
7218 nodelist->nodeNr);
7219 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007220 case NODE_TEST_NONE:
7221 xmlGenericError(xmlGenericErrorContext,
7222 " searching for none !!!\n");
7223 break;
7224 case NODE_TEST_TYPE:
7225 xmlGenericError(xmlGenericErrorContext,
7226 " searching for type %d\n", type);
7227 break;
7228 case NODE_TEST_PI:
7229 xmlGenericError(xmlGenericErrorContext,
7230 " searching for PI !!!\n");
7231 break;
7232 case NODE_TEST_ALL:
7233 xmlGenericError(xmlGenericErrorContext,
7234 " searching for *\n");
7235 break;
7236 case NODE_TEST_NS:
7237 xmlGenericError(xmlGenericErrorContext,
7238 " searching for namespace %s\n",
7239 prefix);
7240 break;
7241 case NODE_TEST_NAME:
7242 xmlGenericError(xmlGenericErrorContext,
7243 " searching for name %s\n", name);
7244 if (prefix != NULL)
7245 xmlGenericError(xmlGenericErrorContext,
7246 " with namespace %s\n",
7247 prefix);
7248 break;
7249 }
7250 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7251#endif
7252 /*
7253 * 2.3 Node Tests
7254 * - For the attribute axis, the principal node type is attribute.
7255 * - For the namespace axis, the principal node type is namespace.
7256 * - For other axes, the principal node type is element.
7257 *
7258 * A node test * is true for any node of the
7259 * principal node type. For example, child::* willi
7260 * select all element children of the context node
7261 */
7262 tmp = ctxt->context->node;
7263 for (i = 0;i < nodelist->nodeNr; i++) {
7264 ctxt->context->node = nodelist->nodeTab[i];
7265
7266 cur = NULL;
7267 list = xmlXPathNodeSetCreate(NULL);
7268 do {
7269 cur = next(ctxt, cur);
7270 if (cur == NULL) break;
7271#ifdef DEBUG_STEP
7272 t++;
7273 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7274#endif
7275 switch (test) {
7276 case NODE_TEST_NONE:
7277 ctxt->context->node = tmp;
7278 STRANGE
7279 return;
7280 case NODE_TEST_TYPE:
7281 if ((cur->type == type) ||
7282 ((type == NODE_TYPE_NODE) &&
7283 ((cur->type == XML_DOCUMENT_NODE) ||
7284 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7285 (cur->type == XML_ELEMENT_NODE) ||
7286 (cur->type == XML_PI_NODE) ||
7287 (cur->type == XML_COMMENT_NODE) ||
7288 (cur->type == XML_CDATA_SECTION_NODE) ||
7289 (cur->type == XML_TEXT_NODE)))) {
7290#ifdef DEBUG_STEP
7291 n++;
7292#endif
7293 addNode(list, cur);
7294 }
7295 break;
7296 case NODE_TEST_PI:
7297 if (cur->type == XML_PI_NODE) {
7298 if ((name != NULL) &&
7299 (!xmlStrEqual(name, cur->name)))
7300 break;
7301#ifdef DEBUG_STEP
7302 n++;
7303#endif
7304 addNode(list, cur);
7305 }
7306 break;
7307 case NODE_TEST_ALL:
7308 if (axis == AXIS_ATTRIBUTE) {
7309 if (cur->type == XML_ATTRIBUTE_NODE) {
7310#ifdef DEBUG_STEP
7311 n++;
7312#endif
7313 addNode(list, cur);
7314 }
7315 } else if (axis == AXIS_NAMESPACE) {
7316 if (cur->type == XML_NAMESPACE_DECL) {
7317#ifdef DEBUG_STEP
7318 n++;
7319#endif
7320 addNode(list, cur);
7321 }
7322 } else {
7323 if ((cur->type == XML_ELEMENT_NODE) ||
7324 (cur->type == XML_DOCUMENT_NODE) ||
7325 (cur->type == XML_HTML_DOCUMENT_NODE)) {
7326 if (prefix == NULL) {
7327#ifdef DEBUG_STEP
7328 n++;
7329#endif
7330 addNode(list, cur);
7331 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007332 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007333 cur->ns->href))) {
7334#ifdef DEBUG_STEP
7335 n++;
7336#endif
7337 addNode(list, cur);
7338 }
7339 }
7340 }
7341 break;
7342 case NODE_TEST_NS: {
7343 TODO;
7344 break;
7345 }
7346 case NODE_TEST_NAME:
7347 switch (cur->type) {
7348 case XML_ELEMENT_NODE:
7349 if (xmlStrEqual(name, cur->name)) {
7350 if (prefix == NULL) {
7351 if ((cur->ns == NULL) ||
7352 (cur->ns->prefix == NULL)) {
7353#ifdef DEBUG_STEP
7354 n++;
7355#endif
7356 addNode(list, cur);
7357 }
7358 } else {
7359 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007360 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007361 cur->ns->href))) {
7362#ifdef DEBUG_STEP
7363 n++;
7364#endif
7365 addNode(list, cur);
7366 }
7367 }
7368 }
7369 break;
7370 case XML_ATTRIBUTE_NODE: {
7371 xmlAttrPtr attr = (xmlAttrPtr) cur;
7372 if (xmlStrEqual(name, attr->name)) {
7373 if (prefix == NULL) {
7374 if ((attr->ns == NULL) ||
7375 (attr->ns->prefix == NULL)) {
7376#ifdef DEBUG_STEP
7377 n++;
7378#endif
7379 addNode(list, (xmlNodePtr) attr);
7380 }
7381 } else {
7382 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007383 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007384 attr->ns->href))) {
7385#ifdef DEBUG_STEP
7386 n++;
7387#endif
7388 addNode(list, (xmlNodePtr) attr);
7389 }
7390 }
7391 }
7392 break;
7393 }
7394 case XML_NAMESPACE_DECL: {
7395 TODO;
7396 break;
7397 }
7398 default:
7399 break;
7400 }
7401 break;
7402 }
7403 } while (cur != NULL);
7404
7405 /*
7406 * If there is some predicate filtering do it now
7407 */
7408 if (op->ch2 != -1) {
7409 xmlXPathObjectPtr obj2;
7410
7411 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7412 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7413 CHECK_TYPE(XPATH_NODESET);
7414 obj2 = valuePop(ctxt);
7415 list = obj2->nodesetval;
7416 obj2->nodesetval = NULL;
7417 xmlXPathFreeObject(obj2);
7418 }
7419 if (ret == NULL) {
7420 ret = list;
7421 } else {
7422 ret = xmlXPathNodeSetMerge(ret, list);
7423 xmlXPathFreeNodeSet(list);
7424 }
7425 }
7426 ctxt->context->node = tmp;
7427#ifdef DEBUG_STEP
7428 xmlGenericError(xmlGenericErrorContext,
7429 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7430#endif
7431 xmlXPathFreeObject(obj);
7432 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7433}
7434
Owen Taylor3473f882001-02-23 17:55:21 +00007435/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007436 * xmlXPathCompOpEval:
7437 * @ctxt: the XPath parser context with the compiled expression
7438 * @op: an XPath compiled operation
7439 *
7440 * Evaluate the Precompiled XPath operation
7441 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007442static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007443xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7444 int equal, ret;
7445 xmlXPathCompExprPtr comp;
7446 xmlXPathObjectPtr arg1, arg2;
7447
7448 comp = ctxt->comp;
7449 switch (op->op) {
7450 case XPATH_OP_END:
7451 return;
7452 case XPATH_OP_AND:
7453 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7454 xmlXPathBooleanFunction(ctxt, 1);
7455 if (ctxt->value->boolval == 0)
7456 return;
7457 arg2 = valuePop(ctxt);
7458 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7459 xmlXPathBooleanFunction(ctxt, 1);
7460 arg1 = valuePop(ctxt);
7461 arg1->boolval &= arg2->boolval;
7462 valuePush(ctxt, arg1);
7463 xmlXPathFreeObject(arg2);
7464 return;
7465 case XPATH_OP_OR:
7466 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7467 xmlXPathBooleanFunction(ctxt, 1);
7468 if (ctxt->value->boolval == 1)
7469 return;
7470 arg2 = valuePop(ctxt);
7471 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7472 xmlXPathBooleanFunction(ctxt, 1);
7473 arg1 = valuePop(ctxt);
7474 arg1->boolval |= arg2->boolval;
7475 valuePush(ctxt, arg1);
7476 xmlXPathFreeObject(arg2);
7477 return;
7478 case XPATH_OP_EQUAL:
7479 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7480 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7481 equal = xmlXPathEqualValues(ctxt);
7482 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7483 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7484 return;
7485 case XPATH_OP_CMP:
7486 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7487 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7488 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7489 valuePush(ctxt, xmlXPathNewBoolean(ret));
7490 return;
7491 case XPATH_OP_PLUS:
7492 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7493 if (op->ch2 != -1)
7494 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7495 if (op->value == 0) xmlXPathSubValues(ctxt);
7496 else if (op->value == 1) xmlXPathAddValues(ctxt);
7497 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7498 else if (op->value == 3) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007499 CAST_TO_NUMBER;
7500 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007501 }
7502 return;
7503 case XPATH_OP_MULT:
7504 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7505 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7506 if (op->value == 0) xmlXPathMultValues(ctxt);
7507 else if (op->value == 1) xmlXPathDivValues(ctxt);
7508 else if (op->value == 2) xmlXPathModValues(ctxt);
7509 return;
7510 case XPATH_OP_UNION:
7511 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7512 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7513 CHECK_TYPE(XPATH_NODESET);
7514 arg2 = valuePop(ctxt);
7515
7516 CHECK_TYPE(XPATH_NODESET);
7517 arg1 = valuePop(ctxt);
7518
7519 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7520 arg2->nodesetval);
7521 valuePush(ctxt, arg1);
7522 xmlXPathFreeObject(arg2);
7523 return;
7524 case XPATH_OP_ROOT:
7525 xmlXPathRoot(ctxt);
7526 return;
7527 case XPATH_OP_NODE:
7528 if (op->ch1 != -1)
7529 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7530 if (op->ch2 != -1)
7531 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7532 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7533 return;
7534 case XPATH_OP_RESET:
7535 if (op->ch1 != -1)
7536 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7537 if (op->ch2 != -1)
7538 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7539 ctxt->context->node = NULL;
7540 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007541 case XPATH_OP_COLLECT: {
7542 if (op->ch1 == -1)
7543 return;
7544
7545 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7546 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007547 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007548 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007549 case XPATH_OP_VALUE:
7550 valuePush(ctxt,
7551 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7552 return;
7553 case XPATH_OP_VARIABLE: {
7554 if (op->ch1 != -1)
7555 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7556 if (op->value5 == NULL)
7557 valuePush(ctxt,
7558 xmlXPathVariableLookup(ctxt->context, op->value4));
7559 else {
7560 const xmlChar *URI;
7561 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7562 if (URI == NULL) {
7563 xmlGenericError(xmlGenericErrorContext,
7564 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7565 op->value4, op->value5);
7566 return;
7567 }
7568 valuePush(ctxt,
7569 xmlXPathVariableLookupNS(ctxt->context,
7570 op->value4, URI));
7571 }
7572 return;
7573 }
7574 case XPATH_OP_FUNCTION: {
7575 xmlXPathFunction func;
7576
7577 if (op->ch1 != -1)
7578 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007579 if (op->cache != NULL)
7580 func = (xmlXPathFunction) op->cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007581 else {
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007582 if (op->value5 == NULL)
7583 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7584 else {
7585 const xmlChar *URI;
7586 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7587 if (URI == NULL) {
7588 xmlGenericError(xmlGenericErrorContext,
7589 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7590 op->value4, op->value5);
7591 return;
7592 }
7593 func = xmlXPathFunctionLookupNS(ctxt->context,
7594 op->value4, URI);
7595 }
7596 if (func == NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007597 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007598 "xmlXPathRunEval: function %s not found\n",
7599 op->value4);
7600 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007601 return;
7602 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007603 op->cache = (void *) func;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007604 }
7605 func(ctxt, op->value);
7606 return;
7607 }
7608 case XPATH_OP_ARG:
7609 if (op->ch1 != -1)
7610 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7611 if (op->ch2 != -1)
7612 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7613 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007614 case XPATH_OP_PREDICATE:
7615 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007616 xmlXPathObjectPtr res;
7617 xmlXPathObjectPtr obj, tmp;
7618 xmlNodeSetPtr newset = NULL;
7619 xmlNodeSetPtr oldset;
7620 xmlNodePtr oldnode;
7621 int i;
7622
7623 if (op->ch1 != -1)
7624 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7625 if (op->ch2 == -1)
7626 return;
7627
7628 oldnode = ctxt->context->node;
7629
7630#ifdef LIBXML_XPTR_ENABLED
7631 /*
7632 * Hum are we filtering the result of an XPointer expression
7633 */
7634 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007635 xmlLocationSetPtr newlocset = NULL;
7636 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007637
7638 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007639 * Extract the old locset, and then evaluate the result of the
7640 * expression for all the element in the locset. use it to grow
7641 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007642 */
7643 CHECK_TYPE(XPATH_LOCATIONSET);
7644 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007645 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007646 ctxt->context->node = NULL;
7647
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007648 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007649 ctxt->context->contextSize = 0;
7650 ctxt->context->proximityPosition = 0;
7651 if (op->ch2 != -1)
7652 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7653 res = valuePop(ctxt);
7654 if (res != NULL)
7655 xmlXPathFreeObject(res);
7656 valuePush(ctxt, obj);
7657 CHECK_ERROR;
7658 return;
7659 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007660 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007661
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007662 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007663 /*
7664 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007665 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007666 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007667 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007668 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7669 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007670 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007671 ctxt->context->proximityPosition = i + 1;
7672
7673 if (op->ch2 != -1)
7674 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7675 CHECK_ERROR;
7676
7677 /*
7678 * The result of the evaluation need to be tested to
7679 * decided whether the filter succeeded or not
7680 */
7681 res = valuePop(ctxt);
7682 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007683 xmlXPtrLocationSetAdd(newlocset,
7684 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007685 }
7686
7687 /*
7688 * Cleanup
7689 */
7690 if (res != NULL)
7691 xmlXPathFreeObject(res);
7692 if (ctxt->value == tmp) {
7693 res = valuePop(ctxt);
7694 xmlXPathFreeObject(res);
7695 }
7696
7697 ctxt->context->node = NULL;
7698 }
7699
7700 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007701 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007702 */
7703 xmlXPathFreeObject(obj);
7704 ctxt->context->node = NULL;
7705 ctxt->context->contextSize = -1;
7706 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007707 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007708 ctxt->context->node = oldnode;
7709 return;
7710 }
7711#endif /* LIBXML_XPTR_ENABLED */
7712
7713 /*
7714 * Extract the old set, and then evaluate the result of the
7715 * expression for all the element in the set. use it to grow
7716 * up a new set.
7717 */
7718 CHECK_TYPE(XPATH_NODESET);
7719 obj = valuePop(ctxt);
7720 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007721
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007722 oldnode = ctxt->context->node;
7723 ctxt->context->node = NULL;
7724
7725 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7726 ctxt->context->contextSize = 0;
7727 ctxt->context->proximityPosition = 0;
7728 if (op->ch2 != -1)
7729 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7730 res = valuePop(ctxt);
7731 if (res != NULL)
7732 xmlXPathFreeObject(res);
7733 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007734 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007735 CHECK_ERROR;
7736 } else {
7737 /*
7738 * Initialize the new set.
7739 */
7740 newset = xmlXPathNodeSetCreate(NULL);
7741
7742 for (i = 0; i < oldset->nodeNr; i++) {
7743 /*
7744 * Run the evaluation with a node list made of
7745 * a single item in the nodeset.
7746 */
7747 ctxt->context->node = oldset->nodeTab[i];
7748 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7749 valuePush(ctxt, tmp);
7750 ctxt->context->contextSize = oldset->nodeNr;
7751 ctxt->context->proximityPosition = i + 1;
7752
7753 if (op->ch2 != -1)
7754 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7755 CHECK_ERROR;
7756
7757 /*
7758 * The result of the evaluation need to be tested to
7759 * decided whether the filter succeeded or not
7760 */
7761 res = valuePop(ctxt);
7762 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7763 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7764 }
7765
7766 /*
7767 * Cleanup
7768 */
7769 if (res != NULL)
7770 xmlXPathFreeObject(res);
7771 if (ctxt->value == tmp) {
7772 res = valuePop(ctxt);
7773 xmlXPathFreeObject(res);
7774 }
7775
7776 ctxt->context->node = NULL;
7777 }
7778
7779 /*
7780 * The result is used as the new evaluation set.
7781 */
7782 xmlXPathFreeObject(obj);
7783 ctxt->context->node = NULL;
7784 ctxt->context->contextSize = -1;
7785 ctxt->context->proximityPosition = -1;
7786 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7787 }
7788 ctxt->context->node = oldnode;
7789 return;
7790 }
7791 case XPATH_OP_SORT:
7792 if (op->ch1 != -1)
7793 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7794 if ((ctxt->value != NULL) &&
7795 (ctxt->value->type == XPATH_NODESET) &&
7796 (ctxt->value->nodesetval != NULL))
7797 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7798 return;
7799#ifdef LIBXML_XPTR_ENABLED
7800 case XPATH_OP_RANGETO: {
7801 xmlXPathObjectPtr range;
7802 xmlXPathObjectPtr res, obj;
7803 xmlXPathObjectPtr tmp;
7804 xmlLocationSetPtr newset = NULL;
7805 xmlNodeSetPtr oldset;
7806 int i;
7807
7808 if (op->ch1 != -1)
7809 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7810 if (op->ch2 == -1)
7811 return;
7812
7813 CHECK_TYPE(XPATH_NODESET);
7814 obj = valuePop(ctxt);
7815 oldset = obj->nodesetval;
7816 ctxt->context->node = NULL;
7817
7818 newset = xmlXPtrLocationSetCreate(NULL);
7819
Daniel Veillard911f49a2001-04-07 15:39:35 +00007820 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007821 for (i = 0; i < oldset->nodeNr; i++) {
7822 /*
7823 * Run the evaluation with a node list made of a single item
7824 * in the nodeset.
7825 */
7826 ctxt->context->node = oldset->nodeTab[i];
7827 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7828 valuePush(ctxt, tmp);
7829
7830 if (op->ch2 != -1)
7831 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7832 CHECK_ERROR;
7833
7834 /*
7835 * The result of the evaluation need to be tested to
7836 * decided whether the filter succeeded or not
7837 */
7838 res = valuePop(ctxt);
7839 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7840 if (range != NULL) {
7841 xmlXPtrLocationSetAdd(newset, range);
7842 }
7843
7844 /*
7845 * Cleanup
7846 */
7847 if (res != NULL)
7848 xmlXPathFreeObject(res);
7849 if (ctxt->value == tmp) {
7850 res = valuePop(ctxt);
7851 xmlXPathFreeObject(res);
7852 }
7853
7854 ctxt->context->node = NULL;
7855 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007856 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007857
7858 /*
7859 * The result is used as the new evaluation set.
7860 */
7861 xmlXPathFreeObject(obj);
7862 ctxt->context->node = NULL;
7863 ctxt->context->contextSize = -1;
7864 ctxt->context->proximityPosition = -1;
7865 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7866 return;
7867 }
7868#endif /* LIBXML_XPTR_ENABLED */
7869 }
7870 xmlGenericError(xmlGenericErrorContext,
7871 "XPath: unknown precompiled operation %d\n",
7872 op->op);
7873 return;
7874}
7875
7876/**
7877 * xmlXPathRunEval:
7878 * @ctxt: the XPath parser context with the compiled expression
7879 *
7880 * Evaluate the Precompiled XPath expression in the given context.
7881 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007882static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007883xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7884 xmlXPathCompExprPtr comp;
7885
7886 if ((ctxt == NULL) || (ctxt->comp == NULL))
7887 return;
7888
7889 if (ctxt->valueTab == NULL) {
7890 /* Allocate the value stack */
7891 ctxt->valueTab = (xmlXPathObjectPtr *)
7892 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7893 if (ctxt->valueTab == NULL) {
7894 xmlFree(ctxt);
7895 xmlGenericError(xmlGenericErrorContext,
7896 "xmlXPathRunEval: out of memory\n");
7897 return;
7898 }
7899 ctxt->valueNr = 0;
7900 ctxt->valueMax = 10;
7901 ctxt->value = NULL;
7902 }
7903 comp = ctxt->comp;
7904 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7905}
7906
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007907/************************************************************************
7908 * *
7909 * Public interfaces *
7910 * *
7911 ************************************************************************/
7912
7913/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007914 * xmlXPathEvalPredicate:
7915 * @ctxt: the XPath context
7916 * @res: the Predicate Expression evaluation result
7917 *
7918 * Evaluate a predicate result for the current node.
7919 * A PredicateExpr is evaluated by evaluating the Expr and converting
7920 * the result to a boolean. If the result is a number, the result will
7921 * be converted to true if the number is equal to the position of the
7922 * context node in the context node list (as returned by the position
7923 * function) and will be converted to false otherwise; if the result
7924 * is not a number, then the result will be converted as if by a call
7925 * to the boolean function.
7926 *
7927 * Return 1 if predicate is true, 0 otherwise
7928 */
7929int
7930xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7931 if (res == NULL) return(0);
7932 switch (res->type) {
7933 case XPATH_BOOLEAN:
7934 return(res->boolval);
7935 case XPATH_NUMBER:
7936 return(res->floatval == ctxt->proximityPosition);
7937 case XPATH_NODESET:
7938 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007939 if (res->nodesetval == NULL)
7940 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007941 return(res->nodesetval->nodeNr != 0);
7942 case XPATH_STRING:
7943 return((res->stringval != NULL) &&
7944 (xmlStrlen(res->stringval) != 0));
7945 default:
7946 STRANGE
7947 }
7948 return(0);
7949}
7950
7951/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007952 * xmlXPathEvaluatePredicateResult:
7953 * @ctxt: the XPath Parser context
7954 * @res: the Predicate Expression evaluation result
7955 *
7956 * Evaluate a predicate result for the current node.
7957 * A PredicateExpr is evaluated by evaluating the Expr and converting
7958 * the result to a boolean. If the result is a number, the result will
7959 * be converted to true if the number is equal to the position of the
7960 * context node in the context node list (as returned by the position
7961 * function) and will be converted to false otherwise; if the result
7962 * is not a number, then the result will be converted as if by a call
7963 * to the boolean function.
7964 *
7965 * Return 1 if predicate is true, 0 otherwise
7966 */
7967int
7968xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
7969 xmlXPathObjectPtr res) {
7970 if (res == NULL) return(0);
7971 switch (res->type) {
7972 case XPATH_BOOLEAN:
7973 return(res->boolval);
7974 case XPATH_NUMBER:
7975 return(res->floatval == ctxt->context->proximityPosition);
7976 case XPATH_NODESET:
7977 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00007978 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00007979 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007980 return(res->nodesetval->nodeNr != 0);
7981 case XPATH_STRING:
7982 return((res->stringval != NULL) &&
7983 (xmlStrlen(res->stringval) != 0));
7984 default:
7985 STRANGE
7986 }
7987 return(0);
7988}
7989
7990/**
7991 * xmlXPathCompile:
7992 * @str: the XPath expression
7993 *
7994 * Compile an XPath expression
7995 *
7996 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7997 * the caller has to free the object.
7998 */
7999xmlXPathCompExprPtr
8000xmlXPathCompile(const xmlChar *str) {
8001 xmlXPathParserContextPtr ctxt;
8002 xmlXPathCompExprPtr comp;
8003
8004 xmlXPathInit();
8005
8006 ctxt = xmlXPathNewParserContext(str, NULL);
8007 xmlXPathCompileExpr(ctxt);
8008
Daniel Veillard40af6492001-04-22 08:50:55 +00008009 if (*ctxt->cur != 0) {
8010 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8011 comp = NULL;
8012 } else {
8013 comp = ctxt->comp;
8014 ctxt->comp = NULL;
8015 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008016 xmlXPathFreeParserContext(ctxt);
8017 return(comp);
8018}
8019
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008020/**
8021 * xmlXPathCompiledEval:
8022 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00008023 * @ctx: the XPath context
8024 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008025 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00008026 *
8027 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8028 * the caller has to free the object.
8029 */
8030xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008031xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00008032 xmlXPathParserContextPtr ctxt;
8033 xmlXPathObjectPtr res, tmp, init = NULL;
8034 int stack = 0;
8035
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008036 if ((comp == NULL) || (ctx == NULL))
8037 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008038 xmlXPathInit();
8039
8040 CHECK_CONTEXT(ctx)
8041
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008042 ctxt = xmlXPathCompParserContext(comp, ctx);
8043 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008044
8045 if (ctxt->value == NULL) {
8046 xmlGenericError(xmlGenericErrorContext,
8047 "xmlXPathEval: evaluation failed\n");
8048 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00008049 } else {
8050 res = valuePop(ctxt);
8051 }
8052
8053 do {
8054 tmp = valuePop(ctxt);
8055 if (tmp != NULL) {
8056 if (tmp != init)
8057 stack++;
8058 xmlXPathFreeObject(tmp);
8059 }
8060 } while (tmp != NULL);
8061 if ((stack != 0) && (res != NULL)) {
8062 xmlGenericError(xmlGenericErrorContext,
8063 "xmlXPathEval: %d object left on the stack\n",
8064 stack);
8065 }
8066 if (ctxt->error != XPATH_EXPRESSION_OK) {
8067 xmlXPathFreeObject(res);
8068 res = NULL;
8069 }
8070
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008071
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008072 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008073 xmlXPathFreeParserContext(ctxt);
8074 return(res);
8075}
8076
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008077/**
8078 * xmlXPathEvalExpr:
8079 * @ctxt: the XPath Parser context
8080 *
8081 * Parse and evaluate an XPath expression in the given context,
8082 * then push the result on the context stack
8083 */
8084void
8085xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
8086 xmlXPathCompileExpr(ctxt);
8087 xmlXPathRunEval(ctxt);
8088}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008089
8090/**
8091 * xmlXPathEval:
8092 * @str: the XPath expression
8093 * @ctx: the XPath context
8094 *
8095 * Evaluate the XPath Location Path in the given context.
8096 *
8097 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8098 * the caller has to free the object.
8099 */
8100xmlXPathObjectPtr
8101xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
8102 xmlXPathParserContextPtr ctxt;
8103 xmlXPathObjectPtr res, tmp, init = NULL;
8104 int stack = 0;
8105
8106 xmlXPathInit();
8107
8108 CHECK_CONTEXT(ctx)
8109
8110 ctxt = xmlXPathNewParserContext(str, ctx);
8111 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008112
8113 if (ctxt->value == NULL) {
8114 xmlGenericError(xmlGenericErrorContext,
8115 "xmlXPathEval: evaluation failed\n");
8116 res = NULL;
8117 } else if (*ctxt->cur != 0) {
8118 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8119 res = NULL;
8120 } else {
8121 res = valuePop(ctxt);
8122 }
8123
8124 do {
8125 tmp = valuePop(ctxt);
8126 if (tmp != NULL) {
8127 if (tmp != init)
8128 stack++;
8129 xmlXPathFreeObject(tmp);
8130 }
8131 } while (tmp != NULL);
8132 if ((stack != 0) && (res != NULL)) {
8133 xmlGenericError(xmlGenericErrorContext,
8134 "xmlXPathEval: %d object left on the stack\n",
8135 stack);
8136 }
8137 if (ctxt->error != XPATH_EXPRESSION_OK) {
8138 xmlXPathFreeObject(res);
8139 res = NULL;
8140 }
8141
Owen Taylor3473f882001-02-23 17:55:21 +00008142 xmlXPathFreeParserContext(ctxt);
8143 return(res);
8144}
8145
8146/**
8147 * xmlXPathEvalExpression:
8148 * @str: the XPath expression
8149 * @ctxt: the XPath context
8150 *
8151 * Evaluate the XPath expression in the given context.
8152 *
8153 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
8154 * the caller has to free the object.
8155 */
8156xmlXPathObjectPtr
8157xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
8158 xmlXPathParserContextPtr pctxt;
8159 xmlXPathObjectPtr res, tmp;
8160 int stack = 0;
8161
8162 xmlXPathInit();
8163
8164 CHECK_CONTEXT(ctxt)
8165
8166 pctxt = xmlXPathNewParserContext(str, ctxt);
8167 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008168
8169 if (*pctxt->cur != 0) {
8170 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8171 res = NULL;
8172 } else {
8173 res = valuePop(pctxt);
8174 }
8175 do {
8176 tmp = valuePop(pctxt);
8177 if (tmp != NULL) {
8178 xmlXPathFreeObject(tmp);
8179 stack++;
8180 }
8181 } while (tmp != NULL);
8182 if ((stack != 0) && (res != NULL)) {
8183 xmlGenericError(xmlGenericErrorContext,
8184 "xmlXPathEvalExpression: %d object left on the stack\n",
8185 stack);
8186 }
8187 xmlXPathFreeParserContext(pctxt);
8188 return(res);
8189}
8190
8191/**
8192 * xmlXPathRegisterAllFunctions:
8193 * @ctxt: the XPath context
8194 *
8195 * Registers all default XPath functions in this context
8196 */
8197void
8198xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
8199{
8200 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
8201 xmlXPathBooleanFunction);
8202 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
8203 xmlXPathCeilingFunction);
8204 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
8205 xmlXPathCountFunction);
8206 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
8207 xmlXPathConcatFunction);
8208 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
8209 xmlXPathContainsFunction);
8210 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
8211 xmlXPathIdFunction);
8212 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
8213 xmlXPathFalseFunction);
8214 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
8215 xmlXPathFloorFunction);
8216 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
8217 xmlXPathLastFunction);
8218 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
8219 xmlXPathLangFunction);
8220 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
8221 xmlXPathLocalNameFunction);
8222 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
8223 xmlXPathNotFunction);
8224 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
8225 xmlXPathNameFunction);
8226 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
8227 xmlXPathNamespaceURIFunction);
8228 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
8229 xmlXPathNormalizeFunction);
8230 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
8231 xmlXPathNumberFunction);
8232 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
8233 xmlXPathPositionFunction);
8234 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
8235 xmlXPathRoundFunction);
8236 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
8237 xmlXPathStringFunction);
8238 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
8239 xmlXPathStringLengthFunction);
8240 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
8241 xmlXPathStartsWithFunction);
8242 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
8243 xmlXPathSubstringFunction);
8244 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
8245 xmlXPathSubstringBeforeFunction);
8246 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
8247 xmlXPathSubstringAfterFunction);
8248 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
8249 xmlXPathSumFunction);
8250 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
8251 xmlXPathTrueFunction);
8252 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
8253 xmlXPathTranslateFunction);
8254}
8255
8256#endif /* LIBXML_XPATH_ENABLED */