blob: d65f2513fd6752f9d3b20e936c6cdf31bab02e0b [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:
600 fprintf(output, "Object is a number : %0g\n", cur->floatval);
601 break;
602 case XPATH_STRING:
603 fprintf(output, "Object is a string : ");
604 xmlDebugDumpString(output, cur->stringval);
605 fprintf(output, "\n");
606 break;
607 case XPATH_POINT:
608 fprintf(output, "Object is a point : index %d in node", cur->index);
609 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
610 fprintf(output, "\n");
611 break;
612 case XPATH_RANGE:
613 if ((cur->user2 == NULL) ||
614 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
615 fprintf(output, "Object is a collapsed range :\n");
616 fprintf(output, shift);
617 if (cur->index >= 0)
618 fprintf(output, "index %d in ", cur->index);
619 fprintf(output, "node\n");
620 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
621 depth + 1);
622 } else {
623 fprintf(output, "Object is a range :\n");
624 fprintf(output, shift);
625 fprintf(output, "From ");
626 if (cur->index >= 0)
627 fprintf(output, "index %d in ", cur->index);
628 fprintf(output, "node\n");
629 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
630 depth + 1);
631 fprintf(output, shift);
632 fprintf(output, "To ");
633 if (cur->index2 >= 0)
634 fprintf(output, "index %d in ", cur->index2);
635 fprintf(output, "node\n");
636 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
637 depth + 1);
638 fprintf(output, "\n");
639 }
640 break;
641 case XPATH_LOCATIONSET:
642#if defined(LIBXML_XPTR_ENABLED)
643 fprintf(output, "Object is a Location Set:\n");
644 xmlXPathDebugDumpLocationSet(output,
645 (xmlLocationSetPtr) cur->user, depth);
646#endif
647 break;
648 case XPATH_USERS:
649 fprintf(output, "Object is user defined\n");
650 break;
651 }
652}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000653
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000654static void
655xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000656 xmlXPathStepOpPtr op, int depth) {
657 int i;
658 char shift[100];
659
660 for (i = 0;((i < depth) && (i < 25));i++)
661 shift[2 * i] = shift[2 * i + 1] = ' ';
662 shift[2 * i] = shift[2 * i + 1] = 0;
663
664 fprintf(output, shift);
665 if (op == NULL) {
666 fprintf(output, "Step is NULL\n");
667 return;
668 }
669 switch (op->op) {
670 case XPATH_OP_END:
671 fprintf(output, "END"); break;
672 case XPATH_OP_AND:
673 fprintf(output, "AND"); break;
674 case XPATH_OP_OR:
675 fprintf(output, "OR"); break;
676 case XPATH_OP_EQUAL:
677 if (op->value)
678 fprintf(output, "EQUAL =");
679 else
680 fprintf(output, "EQUAL !=");
681 break;
682 case XPATH_OP_CMP:
683 if (op->value)
684 fprintf(output, "CMP <");
685 else
686 fprintf(output, "CMP >");
687 if (!op->value2)
688 fprintf(output, "=");
689 break;
690 case XPATH_OP_PLUS:
691 if (op->value == 0)
692 fprintf(output, "PLUS -");
693 else if (op->value == 1)
694 fprintf(output, "PLUS +");
695 else if (op->value == 2)
696 fprintf(output, "PLUS unary -");
697 else if (op->value == 3)
698 fprintf(output, "PLUS unary - -");
699 break;
700 case XPATH_OP_MULT:
701 if (op->value == 0)
702 fprintf(output, "MULT *");
703 else if (op->value == 1)
704 fprintf(output, "MULT div");
705 else
706 fprintf(output, "MULT mod");
707 break;
708 case XPATH_OP_UNION:
709 fprintf(output, "UNION"); break;
710 case XPATH_OP_ROOT:
711 fprintf(output, "ROOT"); break;
712 case XPATH_OP_NODE:
713 fprintf(output, "NODE"); break;
714 case XPATH_OP_RESET:
715 fprintf(output, "RESET"); break;
716 case XPATH_OP_SORT:
717 fprintf(output, "SORT"); break;
718 case XPATH_OP_COLLECT: {
719 xmlXPathAxisVal axis = op->value;
720 xmlXPathTestVal test = op->value2;
721 xmlXPathTypeVal type = op->value3;
722 const xmlChar *prefix = op->value4;
723 const xmlChar *name = op->value5;
724
725 fprintf(output, "COLLECT ");
726 switch (axis) {
727 case AXIS_ANCESTOR:
728 fprintf(output, " 'ancestors' "); break;
729 case AXIS_ANCESTOR_OR_SELF:
730 fprintf(output, " 'ancestors-or-self' "); break;
731 case AXIS_ATTRIBUTE:
732 fprintf(output, " 'attributes' "); break;
733 case AXIS_CHILD:
734 fprintf(output, " 'child' "); break;
735 case AXIS_DESCENDANT:
736 fprintf(output, " 'descendant' "); break;
737 case AXIS_DESCENDANT_OR_SELF:
738 fprintf(output, " 'descendant-or-self' "); break;
739 case AXIS_FOLLOWING:
740 fprintf(output, " 'following' "); break;
741 case AXIS_FOLLOWING_SIBLING:
742 fprintf(output, " 'following-siblings' "); break;
743 case AXIS_NAMESPACE:
744 fprintf(output, " 'namespace' "); break;
745 case AXIS_PARENT:
746 fprintf(output, " 'parent' "); break;
747 case AXIS_PRECEDING:
748 fprintf(output, " 'preceding' "); break;
749 case AXIS_PRECEDING_SIBLING:
750 fprintf(output, " 'preceding-sibling' "); break;
751 case AXIS_SELF:
752 fprintf(output, " 'self' "); break;
753 }
754 switch (test) {
755 case NODE_TEST_NONE:
756 fprintf(output, "'none' "); break;
757 case NODE_TEST_TYPE:
758 fprintf(output, "'type' "); break;
759 case NODE_TEST_PI:
760 fprintf(output, "'PI' "); break;
761 case NODE_TEST_ALL:
762 fprintf(output, "'all' "); break;
763 case NODE_TEST_NS:
764 fprintf(output, "'namespace' "); break;
765 case NODE_TEST_NAME:
766 fprintf(output, "'name' "); break;
767 }
768 switch (type) {
769 case NODE_TYPE_NODE:
770 fprintf(output, "'node' "); break;
771 case NODE_TYPE_COMMENT:
772 fprintf(output, "'comment' "); break;
773 case NODE_TYPE_TEXT:
774 fprintf(output, "'text' "); break;
775 case NODE_TYPE_PI:
776 fprintf(output, "'PI' "); break;
777 }
778 if (prefix != NULL)
779 fprintf(output, "%s:", prefix);
780 if (name != NULL)
781 fprintf(output, "%s", name);
782 break;
783
784 }
785 case XPATH_OP_VALUE: {
786 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
787
788 fprintf(output, "ELEM ");
789 xmlXPathDebugDumpObject(output, object, 0);
790 goto finish;
791 }
792 case XPATH_OP_VARIABLE: {
793 const xmlChar *prefix = op->value5;
794 const xmlChar *name = op->value4;
795
796 if (prefix != NULL)
797 fprintf(output, "VARIABLE %s:%s", prefix, name);
798 else
799 fprintf(output, "VARIABLE %s", name);
800 break;
801 }
802 case XPATH_OP_FUNCTION: {
803 int nbargs = op->value;
804 const xmlChar *prefix = op->value5;
805 const xmlChar *name = op->value4;
806
807 if (prefix != NULL)
808 fprintf(output, "FUNCTION %s:%s(%d args)",
809 prefix, name, nbargs);
810 else
811 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
812 break;
813 }
814 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
815 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000816 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000817#ifdef LIBXML_XPTR_ENABLED
818 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
819#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000820 default:
821 fprintf(output, "UNKNOWN %d\n", op->op); return;
822 }
823 fprintf(output, "\n");
824finish:
825 if (op->ch1 >= 0)
826 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
827 if (op->ch2 >= 0)
828 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
829}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000830
831void
832xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
833 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000834 int i;
835 char shift[100];
836
837 for (i = 0;((i < depth) && (i < 25));i++)
838 shift[2 * i] = shift[2 * i + 1] = ' ';
839 shift[2 * i] = shift[2 * i + 1] = 0;
840
841 fprintf(output, shift);
842
843 if (comp == NULL) {
844 fprintf(output, "Compiled Expression is NULL\n");
845 return;
846 }
847 fprintf(output, "Compiled Expression : %d elements\n",
848 comp->nbStep);
849 i = comp->last;
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
851}
Owen Taylor3473f882001-02-23 17:55:21 +0000852#endif
853
854/************************************************************************
855 * *
856 * Parser stacks related functions and macros *
857 * *
858 ************************************************************************/
859
860/*
861 * Generic function for accessing stacks in the Parser Context
862 */
863
864#define PUSH_AND_POP(type, name) \
865extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
866 if (ctxt->name##Nr >= ctxt->name##Max) { \
867 ctxt->name##Max *= 2; \
868 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
869 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
870 if (ctxt->name##Tab == NULL) { \
871 xmlGenericError(xmlGenericErrorContext, \
872 "realloc failed !\n"); \
873 return(0); \
874 } \
875 } \
876 ctxt->name##Tab[ctxt->name##Nr] = value; \
877 ctxt->name = value; \
878 return(ctxt->name##Nr++); \
879} \
880extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
881 type ret; \
882 if (ctxt->name##Nr <= 0) return(0); \
883 ctxt->name##Nr--; \
884 if (ctxt->name##Nr > 0) \
885 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
886 else \
887 ctxt->name = NULL; \
888 ret = ctxt->name##Tab[ctxt->name##Nr]; \
889 ctxt->name##Tab[ctxt->name##Nr] = 0; \
890 return(ret); \
891} \
892
893PUSH_AND_POP(xmlXPathObjectPtr, value)
894
895/*
896 * Macros for accessing the content. Those should be used only by the parser,
897 * and not exported.
898 *
899 * Dirty macros, i.e. one need to make assumption on the context to use them
900 *
901 * CUR_PTR return the current pointer to the xmlChar to be parsed.
902 * CUR returns the current xmlChar value, i.e. a 8 bit value
903 * in ISO-Latin or UTF-8.
904 * This should be used internally by the parser
905 * only to compare to ASCII values otherwise it would break when
906 * running with UTF-8 encoding.
907 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
908 * to compare on ASCII based substring.
909 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
910 * strings within the parser.
911 * CURRENT Returns the current char value, with the full decoding of
912 * UTF-8 if we are using this mode. It returns an int.
913 * NEXT Skip to the next character, this does the proper decoding
914 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
915 * It returns the pointer to the current xmlChar.
916 */
917
918#define CUR (*ctxt->cur)
919#define SKIP(val) ctxt->cur += (val)
920#define NXT(val) ctxt->cur[(val)]
921#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +0000922#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
923
924#define COPY_BUF(l,b,i,v) \
925 if (l == 1) b[i++] = (xmlChar) v; \
926 else i += xmlCopyChar(l,&b[i],v)
927
928#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +0000929
930#define SKIP_BLANKS \
931 while (IS_BLANK(*(ctxt->cur))) NEXT
932
933#define CURRENT (*ctxt->cur)
934#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
935
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000936
937#ifndef DBL_DIG
938#define DBL_DIG 16
939#endif
940#ifndef DBL_EPSILON
941#define DBL_EPSILON 1E-9
942#endif
943
944#define UPPER_DOUBLE 1E9
945#define LOWER_DOUBLE 1E-5
946
947#define INTEGER_DIGITS DBL_DIG
948#define FRACTION_DIGITS (DBL_DIG + 1)
949#define EXPONENT_DIGITS (3 + 2)
950
951/**
952 * xmlXPathFormatNumber:
953 * @number: number to format
954 * @buffer: output buffer
955 * @buffersize: size of output buffer
956 *
957 * Convert the number into a string representation.
958 */
959static void
960xmlXPathFormatNumber(double number, char buffer[], int buffersize)
961{
962 switch (isinf(number)) {
963 case 1:
964 if (buffersize > (int)sizeof("+Infinity"))
965 sprintf(buffer, "+Infinity");
966 break;
967 case -1:
968 if (buffersize > (int)sizeof("-Infinity"))
969 sprintf(buffer, "-Infinity");
970 break;
971 default:
972 if (isnan(number)) {
973 if (buffersize > (int)sizeof("NaN"))
974 sprintf(buffer, "NaN");
975 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000976 /* 3 is sign, decimal point, and terminating zero */
977 char work[DBL_DIG + EXPONENT_DIGITS + 3];
978 int integer_place, fraction_place;
979 char *ptr;
980 char *after_fraction;
981 double absolute_value;
982 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000983
Bjorn Reese70a9da52001-04-21 16:57:29 +0000984 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000985
Bjorn Reese70a9da52001-04-21 16:57:29 +0000986 /*
987 * First choose format - scientific or regular floating point.
988 * In either case, result is in work, and after_fraction points
989 * just past the fractional part.
990 */
991 if ( ((absolute_value > UPPER_DOUBLE) ||
992 (absolute_value < LOWER_DOUBLE)) &&
993 (absolute_value != 0.0) ) {
994 /* Use scientific notation */
995 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
996 fraction_place = DBL_DIG - 1;
997 snprintf(work, sizeof(work),"%*.*e",
998 integer_place, fraction_place, number);
999 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001000 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001001 else {
1002 /* Use regular notation */
1003 integer_place = 1 + (int)log10(absolute_value);
1004 fraction_place = (integer_place > 0)
1005 ? DBL_DIG - integer_place
1006 : DBL_DIG;
1007 size = snprintf(work, sizeof(work), "%0.*f",
1008 fraction_place, number);
1009 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001010 }
1011
Bjorn Reese70a9da52001-04-21 16:57:29 +00001012 /* Remove fractional trailing zeroes */
1013 ptr = after_fraction;
1014 while (*(--ptr) == '0')
1015 ;
1016 if (*ptr != '.')
1017 ptr++;
1018 strcpy(ptr, after_fraction);
1019
1020 /* Finally copy result back to caller */
1021 size = strlen(work) + 1;
1022 if (size > buffersize) {
1023 work[buffersize - 1] = 0;
1024 size = buffersize;
1025 }
1026 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001027 }
1028 break;
1029 }
1030}
1031
Owen Taylor3473f882001-02-23 17:55:21 +00001032/************************************************************************
1033 * *
1034 * Error handling routines *
1035 * *
1036 ************************************************************************/
1037
1038
1039const char *xmlXPathErrorMessages[] = {
1040 "Ok",
1041 "Number encoding",
1042 "Unfinished litteral",
1043 "Start of litteral",
1044 "Expected $ for variable reference",
1045 "Undefined variable",
1046 "Invalid predicate",
1047 "Invalid expression",
1048 "Missing closing curly brace",
1049 "Unregistered function",
1050 "Invalid operand",
1051 "Invalid type",
1052 "Invalid number of arguments",
1053 "Invalid context size",
1054 "Invalid context position",
1055 "Memory allocation error",
1056 "Syntax error",
1057 "Resource error",
1058 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001059 "Undefined namespace prefix",
1060 "Encoding error",
1061 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001062};
1063
1064/**
1065 * xmlXPathError:
1066 * @ctxt: the XPath Parser context
1067 * @file: the file name
1068 * @line: the line number
1069 * @no: the error number
1070 *
1071 * Create a new xmlNodeSetPtr of type double and of value @val
1072 *
1073 * Returns the newly created object.
1074 */
1075void
1076xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1077 int line, int no) {
1078 int n;
1079 const xmlChar *cur;
1080 const xmlChar *base;
1081
1082 xmlGenericError(xmlGenericErrorContext,
1083 "Error %s:%d: %s\n", file, line,
1084 xmlXPathErrorMessages[no]);
1085
1086 cur = ctxt->cur;
1087 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001088 if ((cur == NULL) || (base == NULL))
1089 return;
1090
Owen Taylor3473f882001-02-23 17:55:21 +00001091 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1092 cur--;
1093 }
1094 n = 0;
1095 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1096 cur--;
1097 if ((*cur == '\n') || (*cur == '\r')) cur++;
1098 base = cur;
1099 n = 0;
1100 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1101 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1102 n++;
1103 }
1104 xmlGenericError(xmlGenericErrorContext, "\n");
1105 cur = ctxt->cur;
1106 while ((*cur == '\n') || (*cur == '\r'))
1107 cur--;
1108 n = 0;
1109 while ((cur != base) && (n++ < 80)) {
1110 xmlGenericError(xmlGenericErrorContext, " ");
1111 base++;
1112 }
1113 xmlGenericError(xmlGenericErrorContext,"^\n");
1114}
1115
1116
1117/************************************************************************
1118 * *
1119 * Routines to handle NodeSets *
1120 * *
1121 ************************************************************************/
1122
1123/**
1124 * xmlXPathCmpNodes:
1125 * @node1: the first node
1126 * @node2: the second node
1127 *
1128 * Compare two nodes w.r.t document order
1129 *
1130 * Returns -2 in case of error 1 if first point < second point, 0 if
1131 * that's the same node, -1 otherwise
1132 */
1133int
1134xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1135 int depth1, depth2;
1136 xmlNodePtr cur, root;
1137
1138 if ((node1 == NULL) || (node2 == NULL))
1139 return(-2);
1140 /*
1141 * a couple of optimizations which will avoid computations in most cases
1142 */
1143 if (node1 == node2)
1144 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001145 if ((node1->type == XML_NAMESPACE_DECL) ||
1146 (node2->type == XML_NAMESPACE_DECL))
1147 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001148 if (node1 == node2->prev)
1149 return(1);
1150 if (node1 == node2->next)
1151 return(-1);
1152
1153 /*
1154 * compute depth to root
1155 */
1156 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1157 if (cur == node1)
1158 return(1);
1159 depth2++;
1160 }
1161 root = cur;
1162 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1163 if (cur == node2)
1164 return(-1);
1165 depth1++;
1166 }
1167 /*
1168 * Distinct document (or distinct entities :-( ) case.
1169 */
1170 if (root != cur) {
1171 return(-2);
1172 }
1173 /*
1174 * get the nearest common ancestor.
1175 */
1176 while (depth1 > depth2) {
1177 depth1--;
1178 node1 = node1->parent;
1179 }
1180 while (depth2 > depth1) {
1181 depth2--;
1182 node2 = node2->parent;
1183 }
1184 while (node1->parent != node2->parent) {
1185 node1 = node1->parent;
1186 node2 = node2->parent;
1187 /* should not happen but just in case ... */
1188 if ((node1 == NULL) || (node2 == NULL))
1189 return(-2);
1190 }
1191 /*
1192 * Find who's first.
1193 */
1194 if (node1 == node2->next)
1195 return(-1);
1196 for (cur = node1->next;cur != NULL;cur = cur->next)
1197 if (cur == node2)
1198 return(1);
1199 return(-1); /* assume there is no sibling list corruption */
1200}
1201
1202/**
1203 * xmlXPathNodeSetSort:
1204 * @set: the node set
1205 *
1206 * Sort the node set in document order
1207 */
1208void
1209xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001210 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001211 xmlNodePtr tmp;
1212
1213 if (set == NULL)
1214 return;
1215
1216 /* Use Shell's sort to sort the node-set */
1217 len = set->nodeNr;
1218 for (incr = len / 2; incr > 0; incr /= 2) {
1219 for (i = incr; i < len; i++) {
1220 j = i - incr;
1221 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001222 if (xmlXPathCmpNodes(set->nodeTab[j],
1223 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001224 tmp = set->nodeTab[j];
1225 set->nodeTab[j] = set->nodeTab[j + incr];
1226 set->nodeTab[j + incr] = tmp;
1227 j -= incr;
1228 } else
1229 break;
1230 }
1231 }
1232 }
1233}
1234
1235#define XML_NODESET_DEFAULT 10
1236/**
1237 * xmlXPathNodeSetCreate:
1238 * @val: an initial xmlNodePtr, or NULL
1239 *
1240 * Create a new xmlNodeSetPtr of type double and of value @val
1241 *
1242 * Returns the newly created object.
1243 */
1244xmlNodeSetPtr
1245xmlXPathNodeSetCreate(xmlNodePtr val) {
1246 xmlNodeSetPtr ret;
1247
1248 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1249 if (ret == NULL) {
1250 xmlGenericError(xmlGenericErrorContext,
1251 "xmlXPathNewNodeSet: out of memory\n");
1252 return(NULL);
1253 }
1254 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1255 if (val != NULL) {
1256 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1257 sizeof(xmlNodePtr));
1258 if (ret->nodeTab == NULL) {
1259 xmlGenericError(xmlGenericErrorContext,
1260 "xmlXPathNewNodeSet: out of memory\n");
1261 return(NULL);
1262 }
1263 memset(ret->nodeTab, 0 ,
1264 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1265 ret->nodeMax = XML_NODESET_DEFAULT;
1266 ret->nodeTab[ret->nodeNr++] = val;
1267 }
1268 return(ret);
1269}
1270
1271/**
1272 * xmlXPathNodeSetAdd:
1273 * @cur: the initial node set
1274 * @val: a new xmlNodePtr
1275 *
1276 * add a new xmlNodePtr ot an existing NodeSet
1277 */
1278void
1279xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1280 int i;
1281
1282 if (val == NULL) return;
1283
1284 /*
1285 * check against doublons
1286 */
1287 for (i = 0;i < cur->nodeNr;i++)
1288 if (cur->nodeTab[i] == val) return;
1289
1290 /*
1291 * grow the nodeTab if needed
1292 */
1293 if (cur->nodeMax == 0) {
1294 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1295 sizeof(xmlNodePtr));
1296 if (cur->nodeTab == NULL) {
1297 xmlGenericError(xmlGenericErrorContext,
1298 "xmlXPathNodeSetAdd: out of memory\n");
1299 return;
1300 }
1301 memset(cur->nodeTab, 0 ,
1302 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1303 cur->nodeMax = XML_NODESET_DEFAULT;
1304 } else if (cur->nodeNr == cur->nodeMax) {
1305 xmlNodePtr *temp;
1306
1307 cur->nodeMax *= 2;
1308 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1309 sizeof(xmlNodePtr));
1310 if (temp == NULL) {
1311 xmlGenericError(xmlGenericErrorContext,
1312 "xmlXPathNodeSetAdd: out of memory\n");
1313 return;
1314 }
1315 cur->nodeTab = temp;
1316 }
1317 cur->nodeTab[cur->nodeNr++] = val;
1318}
1319
1320/**
1321 * xmlXPathNodeSetAddUnique:
1322 * @cur: the initial node set
1323 * @val: a new xmlNodePtr
1324 *
1325 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1326 * when we are sure the node is not already in the set.
1327 */
1328void
1329xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1330 if (val == NULL) return;
1331
1332 /*
1333 * grow the nodeTab if needed
1334 */
1335 if (cur->nodeMax == 0) {
1336 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1337 sizeof(xmlNodePtr));
1338 if (cur->nodeTab == NULL) {
1339 xmlGenericError(xmlGenericErrorContext,
1340 "xmlXPathNodeSetAddUnique: out of memory\n");
1341 return;
1342 }
1343 memset(cur->nodeTab, 0 ,
1344 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1345 cur->nodeMax = XML_NODESET_DEFAULT;
1346 } else if (cur->nodeNr == cur->nodeMax) {
1347 xmlNodePtr *temp;
1348
1349 cur->nodeMax *= 2;
1350 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1351 sizeof(xmlNodePtr));
1352 if (temp == NULL) {
1353 xmlGenericError(xmlGenericErrorContext,
1354 "xmlXPathNodeSetAddUnique: out of memory\n");
1355 return;
1356 }
1357 cur->nodeTab = temp;
1358 }
1359 cur->nodeTab[cur->nodeNr++] = val;
1360}
1361
1362/**
1363 * xmlXPathNodeSetMerge:
1364 * @val1: the first NodeSet or NULL
1365 * @val2: the second NodeSet
1366 *
1367 * Merges two nodesets, all nodes from @val2 are added to @val1
1368 * if @val1 is NULL, a new set is created and copied from @val2
1369 *
1370 * Returns val1 once extended or NULL in case of error.
1371 */
1372xmlNodeSetPtr
1373xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001374 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001375
1376 if (val2 == NULL) return(val1);
1377 if (val1 == NULL) {
1378 val1 = xmlXPathNodeSetCreate(NULL);
1379 }
1380
1381 initNr = val1->nodeNr;
1382
1383 for (i = 0;i < val2->nodeNr;i++) {
1384 /*
1385 * check against doublons
1386 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001387 skip = 0;
1388 for (j = 0; j < initNr; j++) {
1389 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1390 skip = 1;
1391 break;
1392 }
1393 }
1394 if (skip)
1395 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001396
1397 /*
1398 * grow the nodeTab if needed
1399 */
1400 if (val1->nodeMax == 0) {
1401 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1402 sizeof(xmlNodePtr));
1403 if (val1->nodeTab == NULL) {
1404 xmlGenericError(xmlGenericErrorContext,
1405 "xmlXPathNodeSetMerge: out of memory\n");
1406 return(NULL);
1407 }
1408 memset(val1->nodeTab, 0 ,
1409 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1410 val1->nodeMax = XML_NODESET_DEFAULT;
1411 } else if (val1->nodeNr == val1->nodeMax) {
1412 xmlNodePtr *temp;
1413
1414 val1->nodeMax *= 2;
1415 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1416 sizeof(xmlNodePtr));
1417 if (temp == NULL) {
1418 xmlGenericError(xmlGenericErrorContext,
1419 "xmlXPathNodeSetMerge: out of memory\n");
1420 return(NULL);
1421 }
1422 val1->nodeTab = temp;
1423 }
1424 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1425 }
1426
1427 return(val1);
1428}
1429
1430/**
1431 * xmlXPathNodeSetDel:
1432 * @cur: the initial node set
1433 * @val: an xmlNodePtr
1434 *
1435 * Removes an xmlNodePtr from an existing NodeSet
1436 */
1437void
1438xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1439 int i;
1440
1441 if (cur == NULL) return;
1442 if (val == NULL) return;
1443
1444 /*
1445 * check against doublons
1446 */
1447 for (i = 0;i < cur->nodeNr;i++)
1448 if (cur->nodeTab[i] == val) break;
1449
1450 if (i >= cur->nodeNr) {
1451#ifdef DEBUG
1452 xmlGenericError(xmlGenericErrorContext,
1453 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1454 val->name);
1455#endif
1456 return;
1457 }
1458 cur->nodeNr--;
1459 for (;i < cur->nodeNr;i++)
1460 cur->nodeTab[i] = cur->nodeTab[i + 1];
1461 cur->nodeTab[cur->nodeNr] = NULL;
1462}
1463
1464/**
1465 * xmlXPathNodeSetRemove:
1466 * @cur: the initial node set
1467 * @val: the index to remove
1468 *
1469 * Removes an entry from an existing NodeSet list.
1470 */
1471void
1472xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1473 if (cur == NULL) return;
1474 if (val >= cur->nodeNr) return;
1475 cur->nodeNr--;
1476 for (;val < cur->nodeNr;val++)
1477 cur->nodeTab[val] = cur->nodeTab[val + 1];
1478 cur->nodeTab[cur->nodeNr] = NULL;
1479}
1480
1481/**
1482 * xmlXPathFreeNodeSet:
1483 * @obj: the xmlNodeSetPtr to free
1484 *
1485 * Free the NodeSet compound (not the actual nodes !).
1486 */
1487void
1488xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1489 if (obj == NULL) return;
1490 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001491 xmlFree(obj->nodeTab);
1492 }
Owen Taylor3473f882001-02-23 17:55:21 +00001493 xmlFree(obj);
1494}
1495
1496/**
1497 * xmlXPathFreeValueTree:
1498 * @obj: the xmlNodeSetPtr to free
1499 *
1500 * Free the NodeSet compound and the actual tree, this is different
1501 * from xmlXPathFreeNodeSet()
1502 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001503static void
Owen Taylor3473f882001-02-23 17:55:21 +00001504xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1505 int i;
1506
1507 if (obj == NULL) return;
1508 for (i = 0;i < obj->nodeNr;i++)
1509 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001510 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001511
1512 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001513 xmlFree(obj->nodeTab);
1514 }
Owen Taylor3473f882001-02-23 17:55:21 +00001515 xmlFree(obj);
1516}
1517
1518#if defined(DEBUG) || defined(DEBUG_STEP)
1519/**
1520 * xmlGenericErrorContextNodeSet:
1521 * @output: a FILE * for the output
1522 * @obj: the xmlNodeSetPtr to free
1523 *
1524 * Quick display of a NodeSet
1525 */
1526void
1527xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1528 int i;
1529
1530 if (output == NULL) output = xmlGenericErrorContext;
1531 if (obj == NULL) {
1532 fprintf(output, "NodeSet == NULL !\n");
1533 return;
1534 }
1535 if (obj->nodeNr == 0) {
1536 fprintf(output, "NodeSet is empty\n");
1537 return;
1538 }
1539 if (obj->nodeTab == NULL) {
1540 fprintf(output, " nodeTab == NULL !\n");
1541 return;
1542 }
1543 for (i = 0; i < obj->nodeNr; i++) {
1544 if (obj->nodeTab[i] == NULL) {
1545 fprintf(output, " NULL !\n");
1546 return;
1547 }
1548 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1549 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1550 fprintf(output, " /");
1551 else if (obj->nodeTab[i]->name == NULL)
1552 fprintf(output, " noname!");
1553 else fprintf(output, " %s", obj->nodeTab[i]->name);
1554 }
1555 fprintf(output, "\n");
1556}
1557#endif
1558
1559/**
1560 * xmlXPathNewNodeSet:
1561 * @val: the NodePtr value
1562 *
1563 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1564 * it with the single Node @val
1565 *
1566 * Returns the newly created object.
1567 */
1568xmlXPathObjectPtr
1569xmlXPathNewNodeSet(xmlNodePtr val) {
1570 xmlXPathObjectPtr ret;
1571
1572 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1573 if (ret == NULL) {
1574 xmlGenericError(xmlGenericErrorContext,
1575 "xmlXPathNewNodeSet: out of memory\n");
1576 return(NULL);
1577 }
1578 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1579 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001580 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001581 ret->nodesetval = xmlXPathNodeSetCreate(val);
1582 return(ret);
1583}
1584
1585/**
1586 * xmlXPathNewValueTree:
1587 * @val: the NodePtr value
1588 *
1589 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1590 * it with the tree root @val
1591 *
1592 * Returns the newly created object.
1593 */
1594xmlXPathObjectPtr
1595xmlXPathNewValueTree(xmlNodePtr val) {
1596 xmlXPathObjectPtr ret;
1597
1598 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1599 if (ret == NULL) {
1600 xmlGenericError(xmlGenericErrorContext,
1601 "xmlXPathNewNodeSet: out of memory\n");
1602 return(NULL);
1603 }
1604 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1605 ret->type = XPATH_XSLT_TREE;
1606 ret->nodesetval = xmlXPathNodeSetCreate(val);
1607 return(ret);
1608}
1609
1610/**
1611 * xmlXPathNewNodeSetList:
1612 * @val: an existing NodeSet
1613 *
1614 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1615 * it with the Nodeset @val
1616 *
1617 * Returns the newly created object.
1618 */
1619xmlXPathObjectPtr
1620xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1621 xmlXPathObjectPtr ret;
1622 int i;
1623
1624 if (val == NULL)
1625 ret = NULL;
1626 else if (val->nodeTab == NULL)
1627 ret = xmlXPathNewNodeSet(NULL);
1628 else
1629 {
1630 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1631 for (i = 1; i < val->nodeNr; ++i)
1632 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1633 }
1634
1635 return(ret);
1636}
1637
1638/**
1639 * xmlXPathWrapNodeSet:
1640 * @val: the NodePtr value
1641 *
1642 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1643 *
1644 * Returns the newly created object.
1645 */
1646xmlXPathObjectPtr
1647xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1648 xmlXPathObjectPtr ret;
1649
1650 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1651 if (ret == NULL) {
1652 xmlGenericError(xmlGenericErrorContext,
1653 "xmlXPathWrapNodeSet: out of memory\n");
1654 return(NULL);
1655 }
1656 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1657 ret->type = XPATH_NODESET;
1658 ret->nodesetval = val;
1659 return(ret);
1660}
1661
1662/**
1663 * xmlXPathFreeNodeSetList:
1664 * @obj: an existing NodeSetList object
1665 *
1666 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1667 * the list contrary to xmlXPathFreeObject().
1668 */
1669void
1670xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1671 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001672 xmlFree(obj);
1673}
1674
1675/************************************************************************
1676 * *
1677 * Routines to handle extra functions *
1678 * *
1679 ************************************************************************/
1680
1681/**
1682 * xmlXPathRegisterFunc:
1683 * @ctxt: the XPath context
1684 * @name: the function name
1685 * @f: the function implementation or NULL
1686 *
1687 * Register a new function. If @f is NULL it unregisters the function
1688 *
1689 * Returns 0 in case of success, -1 in case of error
1690 */
1691int
1692xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1693 xmlXPathFunction f) {
1694 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1695}
1696
1697/**
1698 * xmlXPathRegisterFuncNS:
1699 * @ctxt: the XPath context
1700 * @name: the function name
1701 * @ns_uri: the function namespace URI
1702 * @f: the function implementation or NULL
1703 *
1704 * Register a new function. If @f is NULL it unregisters the function
1705 *
1706 * Returns 0 in case of success, -1 in case of error
1707 */
1708int
1709xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1710 const xmlChar *ns_uri, xmlXPathFunction f) {
1711 if (ctxt == NULL)
1712 return(-1);
1713 if (name == NULL)
1714 return(-1);
1715
1716 if (ctxt->funcHash == NULL)
1717 ctxt->funcHash = xmlHashCreate(0);
1718 if (ctxt->funcHash == NULL)
1719 return(-1);
1720 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1721}
1722
1723/**
1724 * xmlXPathFunctionLookup:
1725 * @ctxt: the XPath context
1726 * @name: the function name
1727 *
1728 * Search in the Function array of the context for the given
1729 * function.
1730 *
1731 * Returns the xmlXPathFunction or NULL if not found
1732 */
1733xmlXPathFunction
1734xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1735 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1736}
1737
1738/**
1739 * xmlXPathFunctionLookupNS:
1740 * @ctxt: the XPath context
1741 * @name: the function name
1742 * @ns_uri: the function namespace URI
1743 *
1744 * Search in the Function array of the context for the given
1745 * function.
1746 *
1747 * Returns the xmlXPathFunction or NULL if not found
1748 */
1749xmlXPathFunction
1750xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1751 const xmlChar *ns_uri) {
1752 if (ctxt == NULL)
1753 return(NULL);
1754 if (ctxt->funcHash == NULL)
1755 return(NULL);
1756 if (name == NULL)
1757 return(NULL);
1758
1759 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1760}
1761
1762/**
1763 * xmlXPathRegisteredFuncsCleanup:
1764 * @ctxt: the XPath context
1765 *
1766 * Cleanup the XPath context data associated to registered functions
1767 */
1768void
1769xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1770 if (ctxt == NULL)
1771 return;
1772
1773 xmlHashFree(ctxt->funcHash, NULL);
1774 ctxt->funcHash = NULL;
1775}
1776
1777/************************************************************************
1778 * *
1779 * Routines to handle Variable *
1780 * *
1781 ************************************************************************/
1782
1783/**
1784 * xmlXPathRegisterVariable:
1785 * @ctxt: the XPath context
1786 * @name: the variable name
1787 * @value: the variable value or NULL
1788 *
1789 * Register a new variable value. If @value is NULL it unregisters
1790 * the variable
1791 *
1792 * Returns 0 in case of success, -1 in case of error
1793 */
1794int
1795xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1796 xmlXPathObjectPtr value) {
1797 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1798}
1799
1800/**
1801 * xmlXPathRegisterVariableNS:
1802 * @ctxt: the XPath context
1803 * @name: the variable name
1804 * @ns_uri: the variable namespace URI
1805 * @value: the variable value or NULL
1806 *
1807 * Register a new variable value. If @value is NULL it unregisters
1808 * the variable
1809 *
1810 * Returns 0 in case of success, -1 in case of error
1811 */
1812int
1813xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1814 const xmlChar *ns_uri,
1815 xmlXPathObjectPtr value) {
1816 if (ctxt == NULL)
1817 return(-1);
1818 if (name == NULL)
1819 return(-1);
1820
1821 if (ctxt->varHash == NULL)
1822 ctxt->varHash = xmlHashCreate(0);
1823 if (ctxt->varHash == NULL)
1824 return(-1);
1825 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1826 (void *) value,
1827 (xmlHashDeallocator)xmlXPathFreeObject));
1828}
1829
1830/**
1831 * xmlXPathRegisterVariableLookup:
1832 * @ctxt: the XPath context
1833 * @f: the lookup function
1834 * @data: the lookup data
1835 *
1836 * register an external mechanism to do variable lookup
1837 */
1838void
1839xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1840 xmlXPathVariableLookupFunc f, void *data) {
1841 if (ctxt == NULL)
1842 return;
1843 ctxt->varLookupFunc = (void *) f;
1844 ctxt->varLookupData = data;
1845}
1846
1847/**
1848 * xmlXPathVariableLookup:
1849 * @ctxt: the XPath context
1850 * @name: the variable name
1851 *
1852 * Search in the Variable array of the context for the given
1853 * variable value.
1854 *
1855 * Returns the value or NULL if not found
1856 */
1857xmlXPathObjectPtr
1858xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1859 if (ctxt == NULL)
1860 return(NULL);
1861
1862 if (ctxt->varLookupFunc != NULL) {
1863 xmlXPathObjectPtr ret;
1864
1865 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1866 (ctxt->varLookupData, name, NULL);
1867 if (ret != NULL) return(ret);
1868 }
1869 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1870}
1871
1872/**
1873 * xmlXPathVariableLookupNS:
1874 * @ctxt: the XPath context
1875 * @name: the variable name
1876 * @ns_uri: the variable namespace URI
1877 *
1878 * Search in the Variable array of the context for the given
1879 * variable value.
1880 *
1881 * Returns the value or NULL if not found
1882 */
1883xmlXPathObjectPtr
1884xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1885 const xmlChar *ns_uri) {
1886 if (ctxt == NULL)
1887 return(NULL);
1888
1889 if (ctxt->varLookupFunc != NULL) {
1890 xmlXPathObjectPtr ret;
1891
1892 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1893 (ctxt->varLookupData, name, ns_uri);
1894 if (ret != NULL) return(ret);
1895 }
1896
1897 if (ctxt->varHash == NULL)
1898 return(NULL);
1899 if (name == NULL)
1900 return(NULL);
1901
1902 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1903}
1904
1905/**
1906 * xmlXPathRegisteredVariablesCleanup:
1907 * @ctxt: the XPath context
1908 *
1909 * Cleanup the XPath context data associated to registered variables
1910 */
1911void
1912xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1913 if (ctxt == NULL)
1914 return;
1915
1916 xmlHashFree(ctxt->varHash, NULL);
1917 ctxt->varHash = NULL;
1918}
1919
1920/**
1921 * xmlXPathRegisterNs:
1922 * @ctxt: the XPath context
1923 * @prefix: the namespace prefix
1924 * @ns_uri: the namespace name
1925 *
1926 * Register a new namespace. If @ns_uri is NULL it unregisters
1927 * the namespace
1928 *
1929 * Returns 0 in case of success, -1 in case of error
1930 */
1931int
1932xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1933 const xmlChar *ns_uri) {
1934 if (ctxt == NULL)
1935 return(-1);
1936 if (prefix == NULL)
1937 return(-1);
1938
1939 if (ctxt->nsHash == NULL)
1940 ctxt->nsHash = xmlHashCreate(10);
1941 if (ctxt->nsHash == NULL)
1942 return(-1);
1943 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1944 (xmlHashDeallocator)xmlFree));
1945}
1946
1947/**
1948 * xmlXPathNsLookup:
1949 * @ctxt: the XPath context
1950 * @prefix: the namespace prefix value
1951 *
1952 * Search in the namespace declaration array of the context for the given
1953 * namespace name associated to the given prefix
1954 *
1955 * Returns the value or NULL if not found
1956 */
1957const xmlChar *
1958xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1959 if (ctxt == NULL)
1960 return(NULL);
1961 if (prefix == NULL)
1962 return(NULL);
1963
1964#ifdef XML_XML_NAMESPACE
1965 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1966 return(XML_XML_NAMESPACE);
1967#endif
1968
1969 if (ctxt->nsHash == NULL)
1970 return(NULL);
1971
1972 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1973}
1974
1975/**
1976 * xmlXPathRegisteredVariablesCleanup:
1977 * @ctxt: the XPath context
1978 *
1979 * Cleanup the XPath context data associated to registered variables
1980 */
1981void
1982xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
1983 if (ctxt == NULL)
1984 return;
1985
1986 xmlHashFree(ctxt->nsHash, NULL);
1987 ctxt->nsHash = NULL;
1988}
1989
1990/************************************************************************
1991 * *
1992 * Routines to handle Values *
1993 * *
1994 ************************************************************************/
1995
1996/* Allocations are terrible, one need to optimize all this !!! */
1997
1998/**
1999 * xmlXPathNewFloat:
2000 * @val: the double value
2001 *
2002 * Create a new xmlXPathObjectPtr of type double and of value @val
2003 *
2004 * Returns the newly created object.
2005 */
2006xmlXPathObjectPtr
2007xmlXPathNewFloat(double val) {
2008 xmlXPathObjectPtr ret;
2009
2010 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2011 if (ret == NULL) {
2012 xmlGenericError(xmlGenericErrorContext,
2013 "xmlXPathNewFloat: out of memory\n");
2014 return(NULL);
2015 }
2016 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2017 ret->type = XPATH_NUMBER;
2018 ret->floatval = val;
2019 return(ret);
2020}
2021
2022/**
2023 * xmlXPathNewBoolean:
2024 * @val: the boolean value
2025 *
2026 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2027 *
2028 * Returns the newly created object.
2029 */
2030xmlXPathObjectPtr
2031xmlXPathNewBoolean(int val) {
2032 xmlXPathObjectPtr ret;
2033
2034 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2035 if (ret == NULL) {
2036 xmlGenericError(xmlGenericErrorContext,
2037 "xmlXPathNewBoolean: out of memory\n");
2038 return(NULL);
2039 }
2040 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2041 ret->type = XPATH_BOOLEAN;
2042 ret->boolval = (val != 0);
2043 return(ret);
2044}
2045
2046/**
2047 * xmlXPathNewString:
2048 * @val: the xmlChar * value
2049 *
2050 * Create a new xmlXPathObjectPtr of type string and of value @val
2051 *
2052 * Returns the newly created object.
2053 */
2054xmlXPathObjectPtr
2055xmlXPathNewString(const xmlChar *val) {
2056 xmlXPathObjectPtr ret;
2057
2058 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2059 if (ret == NULL) {
2060 xmlGenericError(xmlGenericErrorContext,
2061 "xmlXPathNewString: out of memory\n");
2062 return(NULL);
2063 }
2064 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2065 ret->type = XPATH_STRING;
2066 if (val != NULL)
2067 ret->stringval = xmlStrdup(val);
2068 else
2069 ret->stringval = xmlStrdup((const xmlChar *)"");
2070 return(ret);
2071}
2072
2073/**
2074 * xmlXPathNewCString:
2075 * @val: the char * value
2076 *
2077 * Create a new xmlXPathObjectPtr of type string and of value @val
2078 *
2079 * Returns the newly created object.
2080 */
2081xmlXPathObjectPtr
2082xmlXPathNewCString(const char *val) {
2083 xmlXPathObjectPtr ret;
2084
2085 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2086 if (ret == NULL) {
2087 xmlGenericError(xmlGenericErrorContext,
2088 "xmlXPathNewCString: out of memory\n");
2089 return(NULL);
2090 }
2091 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2092 ret->type = XPATH_STRING;
2093 ret->stringval = xmlStrdup(BAD_CAST val);
2094 return(ret);
2095}
2096
2097/**
2098 * xmlXPathObjectCopy:
2099 * @val: the original object
2100 *
2101 * allocate a new copy of a given object
2102 *
2103 * Returns the newly created object.
2104 */
2105xmlXPathObjectPtr
2106xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2107 xmlXPathObjectPtr ret;
2108
2109 if (val == NULL)
2110 return(NULL);
2111
2112 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2113 if (ret == NULL) {
2114 xmlGenericError(xmlGenericErrorContext,
2115 "xmlXPathObjectCopy: out of memory\n");
2116 return(NULL);
2117 }
2118 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2119 switch (val->type) {
2120 case XPATH_BOOLEAN:
2121 case XPATH_NUMBER:
2122 case XPATH_POINT:
2123 case XPATH_RANGE:
2124 break;
2125 case XPATH_STRING:
2126 ret->stringval = xmlStrdup(val->stringval);
2127 break;
2128 case XPATH_XSLT_TREE:
2129 if ((val->nodesetval != NULL) &&
2130 (val->nodesetval->nodeTab != NULL))
2131 ret->nodesetval = xmlXPathNodeSetCreate(
2132 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2133 else
2134 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2135 break;
2136 case XPATH_NODESET:
2137 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2138 break;
2139 case XPATH_LOCATIONSET:
2140#ifdef LIBXML_XPTR_ENABLED
2141 {
2142 xmlLocationSetPtr loc = val->user;
2143 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2144 break;
2145 }
2146#endif
2147 case XPATH_UNDEFINED:
2148 case XPATH_USERS:
2149 xmlGenericError(xmlGenericErrorContext,
2150 "xmlXPathObjectCopy: unsupported type %d\n",
2151 val->type);
2152 break;
2153 }
2154 return(ret);
2155}
2156
2157/**
2158 * xmlXPathFreeObject:
2159 * @obj: the object to free
2160 *
2161 * Free up an xmlXPathObjectPtr object.
2162 */
2163void
2164xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2165 if (obj == NULL) return;
2166 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002167 if (obj->boolval) {
2168 obj->type = XPATH_XSLT_TREE;
2169 if (obj->nodesetval != NULL)
2170 xmlXPathFreeValueTree(obj->nodesetval);
2171 } else {
2172 if (obj->nodesetval != NULL)
2173 xmlXPathFreeNodeSet(obj->nodesetval);
2174 }
Owen Taylor3473f882001-02-23 17:55:21 +00002175#ifdef LIBXML_XPTR_ENABLED
2176 } else if (obj->type == XPATH_LOCATIONSET) {
2177 if (obj->user != NULL)
2178 xmlXPtrFreeLocationSet(obj->user);
2179#endif
2180 } else if (obj->type == XPATH_STRING) {
2181 if (obj->stringval != NULL)
2182 xmlFree(obj->stringval);
2183 } else if (obj->type == XPATH_XSLT_TREE) {
2184 if (obj->nodesetval != NULL)
2185 xmlXPathFreeValueTree(obj->nodesetval);
2186 }
2187
Owen Taylor3473f882001-02-23 17:55:21 +00002188 xmlFree(obj);
2189}
2190
2191/************************************************************************
2192 * *
2193 * Routines to handle XPath contexts *
2194 * *
2195 ************************************************************************/
2196
2197/**
2198 * xmlXPathNewContext:
2199 * @doc: the XML document
2200 *
2201 * Create a new xmlXPathContext
2202 *
2203 * Returns the xmlXPathContext just allocated.
2204 */
2205xmlXPathContextPtr
2206xmlXPathNewContext(xmlDocPtr doc) {
2207 xmlXPathContextPtr ret;
2208
2209 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2210 if (ret == NULL) {
2211 xmlGenericError(xmlGenericErrorContext,
2212 "xmlXPathNewContext: out of memory\n");
2213 return(NULL);
2214 }
2215 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2216 ret->doc = doc;
2217 ret->node = NULL;
2218
2219 ret->varHash = NULL;
2220
2221 ret->nb_types = 0;
2222 ret->max_types = 0;
2223 ret->types = NULL;
2224
2225 ret->funcHash = xmlHashCreate(0);
2226
2227 ret->nb_axis = 0;
2228 ret->max_axis = 0;
2229 ret->axis = NULL;
2230
2231 ret->nsHash = NULL;
2232 ret->user = NULL;
2233
2234 ret->contextSize = -1;
2235 ret->proximityPosition = -1;
2236
2237 xmlXPathRegisterAllFunctions(ret);
2238
2239 return(ret);
2240}
2241
2242/**
2243 * xmlXPathFreeContext:
2244 * @ctxt: the context to free
2245 *
2246 * Free up an xmlXPathContext
2247 */
2248void
2249xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2250 xmlXPathRegisteredNsCleanup(ctxt);
2251 xmlXPathRegisteredFuncsCleanup(ctxt);
2252 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002253 xmlFree(ctxt);
2254}
2255
2256/************************************************************************
2257 * *
2258 * Routines to handle XPath parser contexts *
2259 * *
2260 ************************************************************************/
2261
2262#define CHECK_CTXT(ctxt) \
2263 if (ctxt == NULL) { \
2264 xmlGenericError(xmlGenericErrorContext, \
2265 "%s:%d Internal error: ctxt == NULL\n", \
2266 __FILE__, __LINE__); \
2267 } \
2268
2269
2270#define CHECK_CONTEXT(ctxt) \
2271 if (ctxt == NULL) { \
2272 xmlGenericError(xmlGenericErrorContext, \
2273 "%s:%d Internal error: no context\n", \
2274 __FILE__, __LINE__); \
2275 } \
2276 else if (ctxt->doc == NULL) { \
2277 xmlGenericError(xmlGenericErrorContext, \
2278 "%s:%d Internal error: no document\n", \
2279 __FILE__, __LINE__); \
2280 } \
2281 else if (ctxt->doc->children == NULL) { \
2282 xmlGenericError(xmlGenericErrorContext, \
2283 "%s:%d Internal error: document without root\n", \
2284 __FILE__, __LINE__); \
2285 } \
2286
2287
2288/**
2289 * xmlXPathNewParserContext:
2290 * @str: the XPath expression
2291 * @ctxt: the XPath context
2292 *
2293 * Create a new xmlXPathParserContext
2294 *
2295 * Returns the xmlXPathParserContext just allocated.
2296 */
2297xmlXPathParserContextPtr
2298xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2299 xmlXPathParserContextPtr ret;
2300
2301 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2302 if (ret == NULL) {
2303 xmlGenericError(xmlGenericErrorContext,
2304 "xmlXPathNewParserContext: out of memory\n");
2305 return(NULL);
2306 }
2307 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2308 ret->cur = ret->base = str;
2309 ret->context = ctxt;
2310
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002311 ret->comp = xmlXPathNewCompExpr();
2312 if (ret->comp == NULL) {
2313 xmlFree(ret->valueTab);
2314 xmlFree(ret);
2315 return(NULL);
2316 }
2317
2318 return(ret);
2319}
2320
2321/**
2322 * xmlXPathCompParserContext:
2323 * @comp: the XPath compiled expression
2324 * @ctxt: the XPath context
2325 *
2326 * Create a new xmlXPathParserContext when processing a compiled expression
2327 *
2328 * Returns the xmlXPathParserContext just allocated.
2329 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002330static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002331xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2332 xmlXPathParserContextPtr ret;
2333
2334 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2335 if (ret == NULL) {
2336 xmlGenericError(xmlGenericErrorContext,
2337 "xmlXPathNewParserContext: out of memory\n");
2338 return(NULL);
2339 }
2340 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2341
Owen Taylor3473f882001-02-23 17:55:21 +00002342 /* Allocate the value stack */
2343 ret->valueTab = (xmlXPathObjectPtr *)
2344 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002345 if (ret->valueTab == NULL) {
2346 xmlFree(ret);
2347 xmlGenericError(xmlGenericErrorContext,
2348 "xmlXPathNewParserContext: out of memory\n");
2349 return(NULL);
2350 }
Owen Taylor3473f882001-02-23 17:55:21 +00002351 ret->valueNr = 0;
2352 ret->valueMax = 10;
2353 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002354
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002355 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002356 ret->comp = comp;
2357
Owen Taylor3473f882001-02-23 17:55:21 +00002358 return(ret);
2359}
2360
2361/**
2362 * xmlXPathFreeParserContext:
2363 * @ctxt: the context to free
2364 *
2365 * Free up an xmlXPathParserContext
2366 */
2367void
2368xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2369 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002370 xmlFree(ctxt->valueTab);
2371 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002372 if (ctxt->comp)
2373 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002374 xmlFree(ctxt);
2375}
2376
2377/************************************************************************
2378 * *
2379 * The implicit core function library *
2380 * *
2381 ************************************************************************/
2382
2383/*
2384 * Auto-pop and cast to a number
2385 */
2386void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
2387
2388
2389#define POP_FLOAT \
2390 arg = valuePop(ctxt); \
2391 if (arg == NULL) { \
2392 XP_ERROR(XPATH_INVALID_OPERAND); \
2393 } \
2394 if (arg->type != XPATH_NUMBER) { \
2395 valuePush(ctxt, arg); \
2396 xmlXPathNumberFunction(ctxt, 1); \
2397 arg = valuePop(ctxt); \
2398 }
2399
2400/**
2401 * xmlXPathCompareNodeSetFloat:
2402 * @ctxt: the XPath Parser context
2403 * @inf: less than (1) or greater than (0)
2404 * @strict: is the comparison strict
2405 * @arg: the node set
2406 * @f: the value
2407 *
2408 * Implement the compare operation between a nodeset and a number
2409 * @ns < @val (1, 1, ...
2410 * @ns <= @val (1, 0, ...
2411 * @ns > @val (0, 1, ...
2412 * @ns >= @val (0, 0, ...
2413 *
2414 * If one object to be compared is a node-set and the other is a number,
2415 * then the comparison will be true if and only if there is a node in the
2416 * node-set such that the result of performing the comparison on the number
2417 * to be compared and on the result of converting the string-value of that
2418 * node to a number using the number function is true.
2419 *
2420 * Returns 0 or 1 depending on the results of the test.
2421 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002422static int
Owen Taylor3473f882001-02-23 17:55:21 +00002423xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2424 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2425 int i, ret = 0;
2426 xmlNodeSetPtr ns;
2427 xmlChar *str2;
2428
2429 if ((f == NULL) || (arg == NULL) ||
2430 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2431 xmlXPathFreeObject(arg);
2432 xmlXPathFreeObject(f);
2433 return(0);
2434 }
2435 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002436 if (ns != NULL) {
2437 for (i = 0;i < ns->nodeNr;i++) {
2438 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2439 if (str2 != NULL) {
2440 valuePush(ctxt,
2441 xmlXPathNewString(str2));
2442 xmlFree(str2);
2443 xmlXPathNumberFunction(ctxt, 1);
2444 valuePush(ctxt, xmlXPathObjectCopy(f));
2445 ret = xmlXPathCompareValues(ctxt, inf, strict);
2446 if (ret)
2447 break;
2448 }
2449 }
Owen Taylor3473f882001-02-23 17:55:21 +00002450 }
2451 xmlXPathFreeObject(arg);
2452 xmlXPathFreeObject(f);
2453 return(ret);
2454}
2455
2456/**
2457 * xmlXPathCompareNodeSetString:
2458 * @ctxt: the XPath Parser context
2459 * @inf: less than (1) or greater than (0)
2460 * @strict: is the comparison strict
2461 * @arg: the node set
2462 * @s: the value
2463 *
2464 * Implement the compare operation between a nodeset and a string
2465 * @ns < @val (1, 1, ...
2466 * @ns <= @val (1, 0, ...
2467 * @ns > @val (0, 1, ...
2468 * @ns >= @val (0, 0, ...
2469 *
2470 * If one object to be compared is a node-set and the other is a string,
2471 * then the comparison will be true if and only if there is a node in
2472 * the node-set such that the result of performing the comparison on the
2473 * string-value of the node and the other string is true.
2474 *
2475 * Returns 0 or 1 depending on the results of the test.
2476 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002477static int
Owen Taylor3473f882001-02-23 17:55:21 +00002478xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2479 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2480 int i, ret = 0;
2481 xmlNodeSetPtr ns;
2482 xmlChar *str2;
2483
2484 if ((s == NULL) || (arg == NULL) ||
2485 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2486 xmlXPathFreeObject(arg);
2487 xmlXPathFreeObject(s);
2488 return(0);
2489 }
2490 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002491 if (ns != NULL) {
2492 for (i = 0;i < ns->nodeNr;i++) {
2493 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2494 if (str2 != NULL) {
2495 valuePush(ctxt,
2496 xmlXPathNewString(str2));
2497 xmlFree(str2);
2498 valuePush(ctxt, xmlXPathObjectCopy(s));
2499 ret = xmlXPathCompareValues(ctxt, inf, strict);
2500 if (ret)
2501 break;
2502 }
2503 }
Owen Taylor3473f882001-02-23 17:55:21 +00002504 }
2505 xmlXPathFreeObject(arg);
2506 xmlXPathFreeObject(s);
2507 return(ret);
2508}
2509
2510/**
2511 * xmlXPathCompareNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00002512 * @op: less than (-1), equal (0) or greater than (1)
2513 * @strict: is the comparison strict
2514 * @arg1: the fist node set object
2515 * @arg2: the second node set object
2516 *
2517 * Implement the compare operation on nodesets:
2518 *
2519 * If both objects to be compared are node-sets, then the comparison
2520 * will be true if and only if there is a node in the first node-set
2521 * and a node in the second node-set such that the result of performing
2522 * the comparison on the string-values of the two nodes is true.
2523 * ....
2524 * When neither object to be compared is a node-set and the operator
2525 * is <=, <, >= or >, then the objects are compared by converting both
2526 * objects to numbers and comparing the numbers according to IEEE 754.
2527 * ....
2528 * The number function converts its argument to a number as follows:
2529 * - a string that consists of optional whitespace followed by an
2530 * optional minus sign followed by a Number followed by whitespace
2531 * is converted to the IEEE 754 number that is nearest (according
2532 * to the IEEE 754 round-to-nearest rule) to the mathematical value
2533 * represented by the string; any other string is converted to NaN
2534 *
2535 * Conclusion all nodes need to be converted first to their string value
2536 * and then the comparison must be done when possible
2537 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002538static int
2539xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00002540 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2541 int i, j, init = 0;
2542 double val1;
2543 double *values2;
2544 int ret = 0;
2545 xmlChar *str;
2546 xmlNodeSetPtr ns1;
2547 xmlNodeSetPtr ns2;
2548
2549 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002550 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
2551 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002552 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002553 }
Owen Taylor3473f882001-02-23 17:55:21 +00002554 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002555 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
2556 xmlXPathFreeObject(arg1);
2557 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002558 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002559 }
Owen Taylor3473f882001-02-23 17:55:21 +00002560
2561 ns1 = arg1->nodesetval;
2562 ns2 = arg2->nodesetval;
2563
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002564 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002565 xmlXPathFreeObject(arg1);
2566 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002567 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002568 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002569 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002570 xmlXPathFreeObject(arg1);
2571 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002572 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002573 }
Owen Taylor3473f882001-02-23 17:55:21 +00002574
2575 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
2576 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002577 xmlXPathFreeObject(arg1);
2578 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002579 return(0);
2580 }
2581 for (i = 0;i < ns1->nodeNr;i++) {
2582 str = xmlNodeGetContent(ns1->nodeTab[i]);
2583 if (str == NULL)
2584 continue;
2585 val1 = xmlXPathStringEvalNumber(str);
2586 xmlFree(str);
2587 if (isnan(val1))
2588 continue;
2589 for (j = 0;j < ns2->nodeNr;j++) {
2590 if (init == 0) {
2591 str = xmlNodeGetContent(ns2->nodeTab[j]);
2592 if (str == NULL) {
2593 values2[j] = xmlXPathNAN;
2594 } else {
2595 values2[j] = xmlXPathStringEvalNumber(str);
2596 xmlFree(str);
2597 }
2598 }
2599 if (isnan(values2[j]))
2600 continue;
2601 if (inf && strict)
2602 ret = (val1 < values2[j]);
2603 else if (inf && !strict)
2604 ret = (val1 <= values2[j]);
2605 else if (!inf && strict)
2606 ret = (val1 > values2[j]);
2607 else if (!inf && !strict)
2608 ret = (val1 >= values2[j]);
2609 if (ret)
2610 break;
2611 }
2612 if (ret)
2613 break;
2614 init = 1;
2615 }
2616 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002617 xmlXPathFreeObject(arg1);
2618 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002619 return(ret);
2620 return(0);
2621}
2622
2623/**
2624 * xmlXPathCompareNodeSetValue:
2625 * @ctxt: the XPath Parser context
2626 * @inf: less than (1) or greater than (0)
2627 * @strict: is the comparison strict
2628 * @arg: the node set
2629 * @val: the value
2630 *
2631 * Implement the compare operation between a nodeset and a value
2632 * @ns < @val (1, 1, ...
2633 * @ns <= @val (1, 0, ...
2634 * @ns > @val (0, 1, ...
2635 * @ns >= @val (0, 0, ...
2636 *
2637 * If one object to be compared is a node-set and the other is a boolean,
2638 * then the comparison will be true if and only if the result of performing
2639 * the comparison on the boolean and on the result of converting
2640 * the node-set to a boolean using the boolean function is true.
2641 *
2642 * Returns 0 or 1 depending on the results of the test.
2643 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002644static int
Owen Taylor3473f882001-02-23 17:55:21 +00002645xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
2646 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
2647 if ((val == NULL) || (arg == NULL) ||
2648 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2649 return(0);
2650
2651 switch(val->type) {
2652 case XPATH_NUMBER:
2653 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
2654 case XPATH_NODESET:
2655 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002656 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00002657 case XPATH_STRING:
2658 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
2659 case XPATH_BOOLEAN:
2660 valuePush(ctxt, arg);
2661 xmlXPathBooleanFunction(ctxt, 1);
2662 valuePush(ctxt, val);
2663 return(xmlXPathCompareValues(ctxt, inf, strict));
2664 default:
2665 TODO
2666 return(0);
2667 }
2668 return(0);
2669}
2670
2671/**
2672 * xmlXPathEqualNodeSetString
2673 * @arg: the nodeset object argument
2674 * @str: the string to compare to.
2675 *
2676 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2677 * If one object to be compared is a node-set and the other is a string,
2678 * then the comparison will be true if and only if there is a node in
2679 * the node-set such that the result of performing the comparison on the
2680 * string-value of the node and the other string is true.
2681 *
2682 * Returns 0 or 1 depending on the results of the test.
2683 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002684static int
Owen Taylor3473f882001-02-23 17:55:21 +00002685xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
2686 int i;
2687 xmlNodeSetPtr ns;
2688 xmlChar *str2;
2689
2690 if ((str == NULL) || (arg == NULL) ||
2691 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2692 return(0);
2693 ns = arg->nodesetval;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002694 if (ns == NULL)
2695 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002696 if (ns->nodeNr <= 0)
2697 return(0);
2698 for (i = 0;i < ns->nodeNr;i++) {
2699 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2700 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
2701 xmlFree(str2);
2702 return(1);
2703 }
2704 if (str2 != NULL)
2705 xmlFree(str2);
2706 }
2707 return(0);
2708}
2709
2710/**
2711 * xmlXPathEqualNodeSetFloat
2712 * @arg: the nodeset object argument
2713 * @f: the float to compare to
2714 *
2715 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2716 * If one object to be compared is a node-set and the other is a number,
2717 * then the comparison will be true if and only if there is a node in
2718 * the node-set such that the result of performing the comparison on the
2719 * number to be compared and on the result of converting the string-value
2720 * of that node to a number using the number function is true.
2721 *
2722 * Returns 0 or 1 depending on the results of the test.
2723 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002724static int
Owen Taylor3473f882001-02-23 17:55:21 +00002725xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
2726 char buf[100] = "";
2727
2728 if ((arg == NULL) ||
2729 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2730 return(0);
2731
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002732 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00002733 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
2734}
2735
2736
2737/**
2738 * xmlXPathEqualNodeSets
2739 * @arg1: first nodeset object argument
2740 * @arg2: second nodeset object argument
2741 *
2742 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
2743 * If both objects to be compared are node-sets, then the comparison
2744 * will be true if and only if there is a node in the first node-set and
2745 * a node in the second node-set such that the result of performing the
2746 * comparison on the string-values of the two nodes is true.
2747 *
2748 * (needless to say, this is a costly operation)
2749 *
2750 * Returns 0 or 1 depending on the results of the test.
2751 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002752static int
Owen Taylor3473f882001-02-23 17:55:21 +00002753xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2754 int i, j;
2755 xmlChar **values1;
2756 xmlChar **values2;
2757 int ret = 0;
2758 xmlNodeSetPtr ns1;
2759 xmlNodeSetPtr ns2;
2760
2761 if ((arg1 == NULL) ||
2762 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
2763 return(0);
2764 if ((arg2 == NULL) ||
2765 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
2766 return(0);
2767
2768 ns1 = arg1->nodesetval;
2769 ns2 = arg2->nodesetval;
2770
Daniel Veillard911f49a2001-04-07 15:39:35 +00002771 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00002772 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002773 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00002774 return(0);
2775
2776 /*
2777 * check if there is a node pertaining to both sets
2778 */
2779 for (i = 0;i < ns1->nodeNr;i++)
2780 for (j = 0;j < ns2->nodeNr;j++)
2781 if (ns1->nodeTab[i] == ns2->nodeTab[j])
2782 return(1);
2783
2784 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
2785 if (values1 == NULL)
2786 return(0);
2787 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
2788 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
2789 if (values2 == NULL) {
2790 xmlFree(values1);
2791 return(0);
2792 }
2793 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
2794 for (i = 0;i < ns1->nodeNr;i++) {
2795 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
2796 for (j = 0;j < ns2->nodeNr;j++) {
2797 if (i == 0)
2798 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
2799 ret = xmlStrEqual(values1[i], values2[j]);
2800 if (ret)
2801 break;
2802 }
2803 if (ret)
2804 break;
2805 }
2806 for (i = 0;i < ns1->nodeNr;i++)
2807 if (values1[i] != NULL)
2808 xmlFree(values1[i]);
2809 for (j = 0;j < ns2->nodeNr;j++)
2810 if (values2[j] != NULL)
2811 xmlFree(values2[j]);
2812 xmlFree(values1);
2813 xmlFree(values2);
2814 return(ret);
2815}
2816
2817/**
2818 * xmlXPathEqualValues:
2819 * @ctxt: the XPath Parser context
2820 *
2821 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2822 *
2823 * Returns 0 or 1 depending on the results of the test.
2824 */
2825int
2826xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
2827 xmlXPathObjectPtr arg1, arg2;
2828 int ret = 0;
2829
2830 arg1 = valuePop(ctxt);
2831 if (arg1 == NULL)
2832 XP_ERROR0(XPATH_INVALID_OPERAND);
2833
2834 arg2 = valuePop(ctxt);
2835 if (arg2 == NULL) {
2836 xmlXPathFreeObject(arg1);
2837 XP_ERROR0(XPATH_INVALID_OPERAND);
2838 }
2839
2840 if (arg1 == arg2) {
2841#ifdef DEBUG_EXPR
2842 xmlGenericError(xmlGenericErrorContext,
2843 "Equal: by pointer\n");
2844#endif
2845 return(1);
2846 }
2847
2848 switch (arg1->type) {
2849 case XPATH_UNDEFINED:
2850#ifdef DEBUG_EXPR
2851 xmlGenericError(xmlGenericErrorContext,
2852 "Equal: undefined\n");
2853#endif
2854 break;
2855 case XPATH_XSLT_TREE:
2856 case XPATH_NODESET:
2857 switch (arg2->type) {
2858 case XPATH_UNDEFINED:
2859#ifdef DEBUG_EXPR
2860 xmlGenericError(xmlGenericErrorContext,
2861 "Equal: undefined\n");
2862#endif
2863 break;
2864 case XPATH_XSLT_TREE:
2865 case XPATH_NODESET:
2866 ret = xmlXPathEqualNodeSets(arg1, arg2);
2867 break;
2868 case XPATH_BOOLEAN:
2869 if ((arg1->nodesetval == NULL) ||
2870 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2871 else
2872 ret = 1;
2873 ret = (ret == arg2->boolval);
2874 break;
2875 case XPATH_NUMBER:
2876 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2877 break;
2878 case XPATH_STRING:
2879 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2880 break;
2881 case XPATH_USERS:
2882 case XPATH_POINT:
2883 case XPATH_RANGE:
2884 case XPATH_LOCATIONSET:
2885 TODO
2886 break;
2887 }
2888 break;
2889 case XPATH_BOOLEAN:
2890 switch (arg2->type) {
2891 case XPATH_UNDEFINED:
2892#ifdef DEBUG_EXPR
2893 xmlGenericError(xmlGenericErrorContext,
2894 "Equal: undefined\n");
2895#endif
2896 break;
2897 case XPATH_NODESET:
2898 case XPATH_XSLT_TREE:
2899 if ((arg2->nodesetval == NULL) ||
2900 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2901 else
2902 ret = 1;
2903 break;
2904 case XPATH_BOOLEAN:
2905#ifdef DEBUG_EXPR
2906 xmlGenericError(xmlGenericErrorContext,
2907 "Equal: %d boolean %d \n",
2908 arg1->boolval, arg2->boolval);
2909#endif
2910 ret = (arg1->boolval == arg2->boolval);
2911 break;
2912 case XPATH_NUMBER:
2913 if (arg2->floatval) ret = 1;
2914 else ret = 0;
2915 ret = (arg1->boolval == ret);
2916 break;
2917 case XPATH_STRING:
2918 if ((arg2->stringval == NULL) ||
2919 (arg2->stringval[0] == 0)) ret = 0;
2920 else
2921 ret = 1;
2922 ret = (arg1->boolval == ret);
2923 break;
2924 case XPATH_USERS:
2925 case XPATH_POINT:
2926 case XPATH_RANGE:
2927 case XPATH_LOCATIONSET:
2928 TODO
2929 break;
2930 }
2931 break;
2932 case XPATH_NUMBER:
2933 switch (arg2->type) {
2934 case XPATH_UNDEFINED:
2935#ifdef DEBUG_EXPR
2936 xmlGenericError(xmlGenericErrorContext,
2937 "Equal: undefined\n");
2938#endif
2939 break;
2940 case XPATH_NODESET:
2941 case XPATH_XSLT_TREE:
2942 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2943 break;
2944 case XPATH_BOOLEAN:
2945 if (arg1->floatval) ret = 1;
2946 else ret = 0;
2947 ret = (arg2->boolval == ret);
2948 break;
2949 case XPATH_STRING:
2950 valuePush(ctxt, arg2);
2951 xmlXPathNumberFunction(ctxt, 1);
2952 arg2 = valuePop(ctxt);
2953 /* no break on purpose */
2954 case XPATH_NUMBER:
2955 ret = (arg1->floatval == arg2->floatval);
2956 break;
2957 case XPATH_USERS:
2958 case XPATH_POINT:
2959 case XPATH_RANGE:
2960 case XPATH_LOCATIONSET:
2961 TODO
2962 break;
2963 }
2964 break;
2965 case XPATH_STRING:
2966 switch (arg2->type) {
2967 case XPATH_UNDEFINED:
2968#ifdef DEBUG_EXPR
2969 xmlGenericError(xmlGenericErrorContext,
2970 "Equal: undefined\n");
2971#endif
2972 break;
2973 case XPATH_NODESET:
2974 case XPATH_XSLT_TREE:
2975 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2976 break;
2977 case XPATH_BOOLEAN:
2978 if ((arg1->stringval == NULL) ||
2979 (arg1->stringval[0] == 0)) ret = 0;
2980 else
2981 ret = 1;
2982 ret = (arg2->boolval == ret);
2983 break;
2984 case XPATH_STRING:
2985 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
2986 break;
2987 case XPATH_NUMBER:
2988 valuePush(ctxt, arg1);
2989 xmlXPathNumberFunction(ctxt, 1);
2990 arg1 = valuePop(ctxt);
2991 ret = (arg1->floatval == arg2->floatval);
2992 break;
2993 case XPATH_USERS:
2994 case XPATH_POINT:
2995 case XPATH_RANGE:
2996 case XPATH_LOCATIONSET:
2997 TODO
2998 break;
2999 }
3000 break;
3001 case XPATH_USERS:
3002 case XPATH_POINT:
3003 case XPATH_RANGE:
3004 case XPATH_LOCATIONSET:
3005 TODO
3006 break;
3007 }
3008 xmlXPathFreeObject(arg1);
3009 xmlXPathFreeObject(arg2);
3010 return(ret);
3011}
3012
3013
3014/**
3015 * xmlXPathCompareValues:
3016 * @ctxt: the XPath Parser context
3017 * @inf: less than (1) or greater than (0)
3018 * @strict: is the comparison strict
3019 *
3020 * Implement the compare operation on XPath objects:
3021 * @arg1 < @arg2 (1, 1, ...
3022 * @arg1 <= @arg2 (1, 0, ...
3023 * @arg1 > @arg2 (0, 1, ...
3024 * @arg1 >= @arg2 (0, 0, ...
3025 *
3026 * When neither object to be compared is a node-set and the operator is
3027 * <=, <, >=, >, then the objects are compared by converted both objects
3028 * to numbers and comparing the numbers according to IEEE 754. The <
3029 * comparison will be true if and only if the first number is less than the
3030 * second number. The <= comparison will be true if and only if the first
3031 * number is less than or equal to the second number. The > comparison
3032 * will be true if and only if the first number is greater than the second
3033 * number. The >= comparison will be true if and only if the first number
3034 * is greater than or equal to the second number.
3035 *
3036 * Returns 1 if the comparaison succeeded, 0 if it failed
3037 */
3038int
3039xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3040 int ret = 0;
3041 xmlXPathObjectPtr arg1, arg2;
3042
3043 arg2 = valuePop(ctxt);
3044 if (arg2 == NULL) {
3045 XP_ERROR0(XPATH_INVALID_OPERAND);
3046 }
3047
3048 arg1 = valuePop(ctxt);
3049 if (arg1 == NULL) {
3050 xmlXPathFreeObject(arg2);
3051 XP_ERROR0(XPATH_INVALID_OPERAND);
3052 }
3053
3054 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3055 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003056 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003057 } else {
3058 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003059 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3060 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003061 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003062 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3063 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003064 }
3065 }
3066 return(ret);
3067 }
3068
3069 if (arg1->type != XPATH_NUMBER) {
3070 valuePush(ctxt, arg1);
3071 xmlXPathNumberFunction(ctxt, 1);
3072 arg1 = valuePop(ctxt);
3073 }
3074 if (arg1->type != XPATH_NUMBER) {
3075 xmlXPathFreeObject(arg1);
3076 xmlXPathFreeObject(arg2);
3077 XP_ERROR0(XPATH_INVALID_OPERAND);
3078 }
3079 if (arg2->type != XPATH_NUMBER) {
3080 valuePush(ctxt, arg2);
3081 xmlXPathNumberFunction(ctxt, 1);
3082 arg2 = valuePop(ctxt);
3083 }
3084 if (arg2->type != XPATH_NUMBER) {
3085 xmlXPathFreeObject(arg1);
3086 xmlXPathFreeObject(arg2);
3087 XP_ERROR0(XPATH_INVALID_OPERAND);
3088 }
3089 /*
3090 * Add tests for infinity and nan
3091 * => feedback on 3.4 for Inf and NaN
3092 */
3093 if (inf && strict)
3094 ret = (arg1->floatval < arg2->floatval);
3095 else if (inf && !strict)
3096 ret = (arg1->floatval <= arg2->floatval);
3097 else if (!inf && strict)
3098 ret = (arg1->floatval > arg2->floatval);
3099 else if (!inf && !strict)
3100 ret = (arg1->floatval >= arg2->floatval);
3101 xmlXPathFreeObject(arg1);
3102 xmlXPathFreeObject(arg2);
3103 return(ret);
3104}
3105
3106/**
3107 * xmlXPathValueFlipSign:
3108 * @ctxt: the XPath Parser context
3109 *
3110 * Implement the unary - operation on an XPath object
3111 * The numeric operators convert their operands to numbers as if
3112 * by calling the number function.
3113 */
3114void
3115xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
3116 xmlXPathObjectPtr arg;
3117
3118 POP_FLOAT
3119 arg->floatval = -arg->floatval;
3120 valuePush(ctxt, arg);
3121}
3122
3123/**
3124 * xmlXPathAddValues:
3125 * @ctxt: the XPath Parser context
3126 *
3127 * Implement the add operation on XPath objects:
3128 * The numeric operators convert their operands to numbers as if
3129 * by calling the number function.
3130 */
3131void
3132xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3133 xmlXPathObjectPtr arg;
3134 double val;
3135
3136 POP_FLOAT
3137 val = arg->floatval;
3138 xmlXPathFreeObject(arg);
3139
3140 POP_FLOAT
3141 arg->floatval += val;
3142 valuePush(ctxt, arg);
3143}
3144
3145/**
3146 * xmlXPathSubValues:
3147 * @ctxt: the XPath Parser context
3148 *
3149 * Implement the substraction operation on XPath objects:
3150 * The numeric operators convert their operands to numbers as if
3151 * by calling the number function.
3152 */
3153void
3154xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3155 xmlXPathObjectPtr arg;
3156 double val;
3157
3158 POP_FLOAT
3159 val = arg->floatval;
3160 xmlXPathFreeObject(arg);
3161
3162 POP_FLOAT
3163 arg->floatval -= val;
3164 valuePush(ctxt, arg);
3165}
3166
3167/**
3168 * xmlXPathMultValues:
3169 * @ctxt: the XPath Parser context
3170 *
3171 * Implement the multiply operation on XPath objects:
3172 * The numeric operators convert their operands to numbers as if
3173 * by calling the number function.
3174 */
3175void
3176xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3177 xmlXPathObjectPtr arg;
3178 double val;
3179
3180 POP_FLOAT
3181 val = arg->floatval;
3182 xmlXPathFreeObject(arg);
3183
3184 POP_FLOAT
3185 arg->floatval *= val;
3186 valuePush(ctxt, arg);
3187}
3188
3189/**
3190 * xmlXPathDivValues:
3191 * @ctxt: the XPath Parser context
3192 *
3193 * Implement the div operation on XPath objects @arg1 / @arg2:
3194 * The numeric operators convert their operands to numbers as if
3195 * by calling the number function.
3196 */
3197void
3198xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3199 xmlXPathObjectPtr arg;
3200 double val;
3201
3202 POP_FLOAT
3203 val = arg->floatval;
3204 xmlXPathFreeObject(arg);
3205
3206 POP_FLOAT
3207 arg->floatval /= val;
3208 valuePush(ctxt, arg);
3209}
3210
3211/**
3212 * xmlXPathModValues:
3213 * @ctxt: the XPath Parser context
3214 *
3215 * Implement the mod operation on XPath objects: @arg1 / @arg2
3216 * The numeric operators convert their operands to numbers as if
3217 * by calling the number function.
3218 */
3219void
3220xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3221 xmlXPathObjectPtr arg;
3222 int arg1, arg2;
3223
3224 POP_FLOAT
3225 arg2 = (int) arg->floatval;
3226 xmlXPathFreeObject(arg);
3227
3228 POP_FLOAT
3229 arg1 = (int) arg->floatval;
3230 arg->floatval = arg1 % arg2;
3231 valuePush(ctxt, arg);
3232}
3233
3234/************************************************************************
3235 * *
3236 * The traversal functions *
3237 * *
3238 ************************************************************************/
3239
Owen Taylor3473f882001-02-23 17:55:21 +00003240/*
3241 * A traversal function enumerates nodes along an axis.
3242 * Initially it must be called with NULL, and it indicates
3243 * termination on the axis by returning NULL.
3244 */
3245typedef xmlNodePtr (*xmlXPathTraversalFunction)
3246 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3247
3248/**
3249 * xmlXPathNextSelf:
3250 * @ctxt: the XPath Parser context
3251 * @cur: the current node in the traversal
3252 *
3253 * Traversal function for the "self" direction
3254 * The self axis contains just the context node itself
3255 *
3256 * Returns the next element following that axis
3257 */
3258xmlNodePtr
3259xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3260 if (cur == NULL)
3261 return(ctxt->context->node);
3262 return(NULL);
3263}
3264
3265/**
3266 * xmlXPathNextChild:
3267 * @ctxt: the XPath Parser context
3268 * @cur: the current node in the traversal
3269 *
3270 * Traversal function for the "child" direction
3271 * The child axis contains the children of the context node in document order.
3272 *
3273 * Returns the next element following that axis
3274 */
3275xmlNodePtr
3276xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3277 if (cur == NULL) {
3278 if (ctxt->context->node == NULL) return(NULL);
3279 switch (ctxt->context->node->type) {
3280 case XML_ELEMENT_NODE:
3281 case XML_TEXT_NODE:
3282 case XML_CDATA_SECTION_NODE:
3283 case XML_ENTITY_REF_NODE:
3284 case XML_ENTITY_NODE:
3285 case XML_PI_NODE:
3286 case XML_COMMENT_NODE:
3287 case XML_NOTATION_NODE:
3288 case XML_DTD_NODE:
3289 return(ctxt->context->node->children);
3290 case XML_DOCUMENT_NODE:
3291 case XML_DOCUMENT_TYPE_NODE:
3292 case XML_DOCUMENT_FRAG_NODE:
3293 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003294#ifdef LIBXML_DOCB_ENABLED
3295 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003296#endif
3297 return(((xmlDocPtr) ctxt->context->node)->children);
3298 case XML_ELEMENT_DECL:
3299 case XML_ATTRIBUTE_DECL:
3300 case XML_ENTITY_DECL:
3301 case XML_ATTRIBUTE_NODE:
3302 case XML_NAMESPACE_DECL:
3303 case XML_XINCLUDE_START:
3304 case XML_XINCLUDE_END:
3305 return(NULL);
3306 }
3307 return(NULL);
3308 }
3309 if ((cur->type == XML_DOCUMENT_NODE) ||
3310 (cur->type == XML_HTML_DOCUMENT_NODE))
3311 return(NULL);
3312 return(cur->next);
3313}
3314
3315/**
3316 * xmlXPathNextDescendant:
3317 * @ctxt: the XPath Parser context
3318 * @cur: the current node in the traversal
3319 *
3320 * Traversal function for the "descendant" direction
3321 * the descendant axis contains the descendants of the context node in document
3322 * order; a descendant is a child or a child of a child and so on.
3323 *
3324 * Returns the next element following that axis
3325 */
3326xmlNodePtr
3327xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3328 if (cur == NULL) {
3329 if (ctxt->context->node == NULL)
3330 return(NULL);
3331 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3332 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3333 return(NULL);
3334
3335 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3336 return(ctxt->context->doc->children);
3337 return(ctxt->context->node->children);
3338 }
3339
3340 if (cur->children != NULL)
3341 {
3342 if (cur->children->type != XML_ENTITY_DECL)
3343 return(cur->children);
3344 }
3345 if (cur->next != NULL) return(cur->next);
3346
3347 do {
3348 cur = cur->parent;
3349 if (cur == NULL) return(NULL);
3350 if (cur == ctxt->context->node) return(NULL);
3351 if (cur->next != NULL) {
3352 cur = cur->next;
3353 return(cur);
3354 }
3355 } while (cur != NULL);
3356 return(cur);
3357}
3358
3359/**
3360 * xmlXPathNextDescendantOrSelf:
3361 * @ctxt: the XPath Parser context
3362 * @cur: the current node in the traversal
3363 *
3364 * Traversal function for the "descendant-or-self" direction
3365 * the descendant-or-self axis contains the context node and the descendants
3366 * of the context node in document order; thus the context node is the first
3367 * node on the axis, and the first child of the context node is the second node
3368 * on the axis
3369 *
3370 * Returns the next element following that axis
3371 */
3372xmlNodePtr
3373xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3374 if (cur == NULL) {
3375 if (ctxt->context->node == NULL)
3376 return(NULL);
3377 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3378 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3379 return(NULL);
3380 return(ctxt->context->node);
3381 }
3382
3383 return(xmlXPathNextDescendant(ctxt, cur));
3384}
3385
3386/**
3387 * xmlXPathNextParent:
3388 * @ctxt: the XPath Parser context
3389 * @cur: the current node in the traversal
3390 *
3391 * Traversal function for the "parent" direction
3392 * The parent axis contains the parent of the context node, if there is one.
3393 *
3394 * Returns the next element following that axis
3395 */
3396xmlNodePtr
3397xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3398 /*
3399 * the parent of an attribute or namespace node is the element
3400 * to which the attribute or namespace node is attached
3401 * Namespace handling !!!
3402 */
3403 if (cur == NULL) {
3404 if (ctxt->context->node == NULL) return(NULL);
3405 switch (ctxt->context->node->type) {
3406 case XML_ELEMENT_NODE:
3407 case XML_TEXT_NODE:
3408 case XML_CDATA_SECTION_NODE:
3409 case XML_ENTITY_REF_NODE:
3410 case XML_ENTITY_NODE:
3411 case XML_PI_NODE:
3412 case XML_COMMENT_NODE:
3413 case XML_NOTATION_NODE:
3414 case XML_DTD_NODE:
3415 case XML_ELEMENT_DECL:
3416 case XML_ATTRIBUTE_DECL:
3417 case XML_XINCLUDE_START:
3418 case XML_XINCLUDE_END:
3419 case XML_ENTITY_DECL:
3420 if (ctxt->context->node->parent == NULL)
3421 return((xmlNodePtr) ctxt->context->doc);
3422 return(ctxt->context->node->parent);
3423 case XML_ATTRIBUTE_NODE: {
3424 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3425
3426 return(att->parent);
3427 }
3428 case XML_DOCUMENT_NODE:
3429 case XML_DOCUMENT_TYPE_NODE:
3430 case XML_DOCUMENT_FRAG_NODE:
3431 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003432#ifdef LIBXML_DOCB_ENABLED
3433 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003434#endif
3435 return(NULL);
3436 case XML_NAMESPACE_DECL:
3437 /*
3438 * TODO !!! may require extending struct _xmlNs with
3439 * parent field
3440 * C.f. Infoset case...
3441 */
3442 return(NULL);
3443 }
3444 }
3445 return(NULL);
3446}
3447
3448/**
3449 * xmlXPathNextAncestor:
3450 * @ctxt: the XPath Parser context
3451 * @cur: the current node in the traversal
3452 *
3453 * Traversal function for the "ancestor" direction
3454 * the ancestor axis contains the ancestors of the context node; the ancestors
3455 * of the context node consist of the parent of context node and the parent's
3456 * parent and so on; the nodes are ordered in reverse document order; thus the
3457 * parent is the first node on the axis, and the parent's parent is the second
3458 * node on the axis
3459 *
3460 * Returns the next element following that axis
3461 */
3462xmlNodePtr
3463xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3464 /*
3465 * the parent of an attribute or namespace node is the element
3466 * to which the attribute or namespace node is attached
3467 * !!!!!!!!!!!!!
3468 */
3469 if (cur == NULL) {
3470 if (ctxt->context->node == NULL) return(NULL);
3471 switch (ctxt->context->node->type) {
3472 case XML_ELEMENT_NODE:
3473 case XML_TEXT_NODE:
3474 case XML_CDATA_SECTION_NODE:
3475 case XML_ENTITY_REF_NODE:
3476 case XML_ENTITY_NODE:
3477 case XML_PI_NODE:
3478 case XML_COMMENT_NODE:
3479 case XML_DTD_NODE:
3480 case XML_ELEMENT_DECL:
3481 case XML_ATTRIBUTE_DECL:
3482 case XML_ENTITY_DECL:
3483 case XML_NOTATION_NODE:
3484 case XML_XINCLUDE_START:
3485 case XML_XINCLUDE_END:
3486 if (ctxt->context->node->parent == NULL)
3487 return((xmlNodePtr) ctxt->context->doc);
3488 return(ctxt->context->node->parent);
3489 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003490 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00003491
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003492 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003493 }
3494 case XML_DOCUMENT_NODE:
3495 case XML_DOCUMENT_TYPE_NODE:
3496 case XML_DOCUMENT_FRAG_NODE:
3497 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003498#ifdef LIBXML_DOCB_ENABLED
3499 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003500#endif
3501 return(NULL);
3502 case XML_NAMESPACE_DECL:
3503 /*
3504 * TODO !!! may require extending struct _xmlNs with
3505 * parent field
3506 * C.f. Infoset case...
3507 */
3508 return(NULL);
3509 }
3510 return(NULL);
3511 }
3512 if (cur == ctxt->context->doc->children)
3513 return((xmlNodePtr) ctxt->context->doc);
3514 if (cur == (xmlNodePtr) ctxt->context->doc)
3515 return(NULL);
3516 switch (cur->type) {
3517 case XML_ELEMENT_NODE:
3518 case XML_TEXT_NODE:
3519 case XML_CDATA_SECTION_NODE:
3520 case XML_ENTITY_REF_NODE:
3521 case XML_ENTITY_NODE:
3522 case XML_PI_NODE:
3523 case XML_COMMENT_NODE:
3524 case XML_NOTATION_NODE:
3525 case XML_DTD_NODE:
3526 case XML_ELEMENT_DECL:
3527 case XML_ATTRIBUTE_DECL:
3528 case XML_ENTITY_DECL:
3529 case XML_XINCLUDE_START:
3530 case XML_XINCLUDE_END:
3531 return(cur->parent);
3532 case XML_ATTRIBUTE_NODE: {
3533 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3534
3535 return(att->parent);
3536 }
3537 case XML_DOCUMENT_NODE:
3538 case XML_DOCUMENT_TYPE_NODE:
3539 case XML_DOCUMENT_FRAG_NODE:
3540 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003541#ifdef LIBXML_DOCB_ENABLED
3542 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003543#endif
3544 return(NULL);
3545 case XML_NAMESPACE_DECL:
3546 /*
3547 * TODO !!! may require extending struct _xmlNs with
3548 * parent field
3549 * C.f. Infoset case...
3550 */
3551 return(NULL);
3552 }
3553 return(NULL);
3554}
3555
3556/**
3557 * xmlXPathNextAncestorOrSelf:
3558 * @ctxt: the XPath Parser context
3559 * @cur: the current node in the traversal
3560 *
3561 * Traversal function for the "ancestor-or-self" direction
3562 * he ancestor-or-self axis contains the context node and ancestors of
3563 * the context node in reverse document order; thus the context node is
3564 * the first node on the axis, and the context node's parent the second;
3565 * parent here is defined the same as with the parent axis.
3566 *
3567 * Returns the next element following that axis
3568 */
3569xmlNodePtr
3570xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3571 if (cur == NULL)
3572 return(ctxt->context->node);
3573 return(xmlXPathNextAncestor(ctxt, cur));
3574}
3575
3576/**
3577 * xmlXPathNextFollowingSibling:
3578 * @ctxt: the XPath Parser context
3579 * @cur: the current node in the traversal
3580 *
3581 * Traversal function for the "following-sibling" direction
3582 * The following-sibling axis contains the following siblings of the context
3583 * node in document order.
3584 *
3585 * Returns the next element following that axis
3586 */
3587xmlNodePtr
3588xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3589 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3590 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3591 return(NULL);
3592 if (cur == (xmlNodePtr) ctxt->context->doc)
3593 return(NULL);
3594 if (cur == NULL)
3595 return(ctxt->context->node->next);
3596 return(cur->next);
3597}
3598
3599/**
3600 * xmlXPathNextPrecedingSibling:
3601 * @ctxt: the XPath Parser context
3602 * @cur: the current node in the traversal
3603 *
3604 * Traversal function for the "preceding-sibling" direction
3605 * The preceding-sibling axis contains the preceding siblings of the context
3606 * node in reverse document order; the first preceding sibling is first on the
3607 * axis; the sibling preceding that node is the second on the axis and so on.
3608 *
3609 * Returns the next element following that axis
3610 */
3611xmlNodePtr
3612xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3613 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3614 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3615 return(NULL);
3616 if (cur == (xmlNodePtr) ctxt->context->doc)
3617 return(NULL);
3618 if (cur == NULL)
3619 return(ctxt->context->node->prev);
3620 return(cur->prev);
3621}
3622
3623/**
3624 * xmlXPathNextFollowing:
3625 * @ctxt: the XPath Parser context
3626 * @cur: the current node in the traversal
3627 *
3628 * Traversal function for the "following" direction
3629 * The following axis contains all nodes in the same document as the context
3630 * node that are after the context node in document order, excluding any
3631 * descendants and excluding attribute nodes and namespace nodes; the nodes
3632 * are ordered in document order
3633 *
3634 * Returns the next element following that axis
3635 */
3636xmlNodePtr
3637xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3638 if (cur != NULL && cur->children != NULL)
3639 return cur->children ;
3640 if (cur == NULL) cur = ctxt->context->node;
3641 if (cur == NULL) return(NULL) ; /* ERROR */
3642 if (cur->next != NULL) return(cur->next) ;
3643 do {
3644 cur = cur->parent;
3645 if (cur == NULL) return(NULL);
3646 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
3647 if (cur->next != NULL) return(cur->next);
3648 } while (cur != NULL);
3649 return(cur);
3650}
3651
3652/*
3653 * xmlXPathIsAncestor:
3654 * @ancestor: the ancestor node
3655 * @node: the current node
3656 *
3657 * Check that @ancestor is a @node's ancestor
3658 *
3659 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
3660 */
3661static int
3662xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
3663 if ((ancestor == NULL) || (node == NULL)) return(0);
3664 /* nodes need to be in the same document */
3665 if (ancestor->doc != node->doc) return(0);
3666 /* avoid searching if ancestor or node is the root node */
3667 if (ancestor == (xmlNodePtr) node->doc) return(1);
3668 if (node == (xmlNodePtr) ancestor->doc) return(0);
3669 while (node->parent != NULL) {
3670 if (node->parent == ancestor)
3671 return(1);
3672 node = node->parent;
3673 }
3674 return(0);
3675}
3676
3677/**
3678 * xmlXPathNextPreceding:
3679 * @ctxt: the XPath Parser context
3680 * @cur: the current node in the traversal
3681 *
3682 * Traversal function for the "preceding" direction
3683 * the preceding axis contains all nodes in the same document as the context
3684 * node that are before the context node in document order, excluding any
3685 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
3686 * ordered in reverse document order
3687 *
3688 * Returns the next element following that axis
3689 */
3690xmlNodePtr
3691xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3692 if (cur == NULL)
3693 cur = ctxt->context->node ;
3694 do {
3695 if (cur->prev != NULL) {
3696 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
3697 ;
3698 return(cur) ;
3699 }
3700
3701 cur = cur->parent;
3702 if (cur == NULL) return(NULL);
3703 if (cur == ctxt->context->doc->children) return(NULL);
3704 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
3705 return(cur);
3706}
3707
3708/**
3709 * xmlXPathNextNamespace:
3710 * @ctxt: the XPath Parser context
3711 * @cur: the current attribute in the traversal
3712 *
3713 * Traversal function for the "namespace" direction
3714 * the namespace axis contains the namespace nodes of the context node;
3715 * the order of nodes on this axis is implementation-defined; the axis will
3716 * be empty unless the context node is an element
3717 *
3718 * Returns the next element following that axis
3719 */
3720xmlNodePtr
3721xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3722 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3723 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
3724 if (ctxt->context->namespaces != NULL)
3725 xmlFree(ctxt->context->namespaces);
3726 ctxt->context->namespaces =
3727 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
3728 if (ctxt->context->namespaces == NULL) return(NULL);
3729 ctxt->context->nsNr = 0;
3730 }
3731 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
3732}
3733
3734/**
3735 * xmlXPathNextAttribute:
3736 * @ctxt: the XPath Parser context
3737 * @cur: the current attribute in the traversal
3738 *
3739 * Traversal function for the "attribute" direction
3740 * TODO: support DTD inherited default attributes
3741 *
3742 * Returns the next element following that axis
3743 */
3744xmlNodePtr
3745xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00003746 if (ctxt->context->node == NULL)
3747 return(NULL);
3748 if (ctxt->context->node->type != XML_ELEMENT_NODE)
3749 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003750 if (cur == NULL) {
3751 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3752 return(NULL);
3753 return((xmlNodePtr)ctxt->context->node->properties);
3754 }
3755 return((xmlNodePtr)cur->next);
3756}
3757
3758/************************************************************************
3759 * *
3760 * NodeTest Functions *
3761 * *
3762 ************************************************************************/
3763
Owen Taylor3473f882001-02-23 17:55:21 +00003764#define IS_FUNCTION 200
3765
Owen Taylor3473f882001-02-23 17:55:21 +00003766
3767/************************************************************************
3768 * *
3769 * Implicit tree core function library *
3770 * *
3771 ************************************************************************/
3772
3773/**
3774 * xmlXPathRoot:
3775 * @ctxt: the XPath Parser context
3776 *
3777 * Initialize the context to the root of the document
3778 */
3779void
3780xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
3781 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
3782 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3783}
3784
3785/************************************************************************
3786 * *
3787 * The explicit core function library *
3788 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
3789 * *
3790 ************************************************************************/
3791
3792
3793/**
3794 * xmlXPathLastFunction:
3795 * @ctxt: the XPath Parser context
3796 * @nargs: the number of arguments
3797 *
3798 * Implement the last() XPath function
3799 * number last()
3800 * The last function returns the number of nodes in the context node list.
3801 */
3802void
3803xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3804 CHECK_ARITY(0);
3805 if (ctxt->context->contextSize >= 0) {
3806 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
3807#ifdef DEBUG_EXPR
3808 xmlGenericError(xmlGenericErrorContext,
3809 "last() : %d\n", ctxt->context->contextSize);
3810#endif
3811 } else {
3812 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
3813 }
3814}
3815
3816/**
3817 * xmlXPathPositionFunction:
3818 * @ctxt: the XPath Parser context
3819 * @nargs: the number of arguments
3820 *
3821 * Implement the position() XPath function
3822 * number position()
3823 * The position function returns the position of the context node in the
3824 * context node list. The first position is 1, and so the last positionr
3825 * will be equal to last().
3826 */
3827void
3828xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3829 CHECK_ARITY(0);
3830 if (ctxt->context->proximityPosition >= 0) {
3831 valuePush(ctxt,
3832 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
3833#ifdef DEBUG_EXPR
3834 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
3835 ctxt->context->proximityPosition);
3836#endif
3837 } else {
3838 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
3839 }
3840}
3841
3842/**
3843 * xmlXPathCountFunction:
3844 * @ctxt: the XPath Parser context
3845 * @nargs: the number of arguments
3846 *
3847 * Implement the count() XPath function
3848 * number count(node-set)
3849 */
3850void
3851xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3852 xmlXPathObjectPtr cur;
3853
3854 CHECK_ARITY(1);
3855 if ((ctxt->value == NULL) ||
3856 ((ctxt->value->type != XPATH_NODESET) &&
3857 (ctxt->value->type != XPATH_XSLT_TREE)))
3858 XP_ERROR(XPATH_INVALID_TYPE);
3859 cur = valuePop(ctxt);
3860
Daniel Veillard911f49a2001-04-07 15:39:35 +00003861 if ((cur == NULL) || (cur->nodesetval == NULL))
3862 valuePush(ctxt, xmlXPathNewFloat((double) 0));
3863 else
3864 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00003865 xmlXPathFreeObject(cur);
3866}
3867
3868/**
3869 * xmlXPathIdFunction:
3870 * @ctxt: the XPath Parser context
3871 * @nargs: the number of arguments
3872 *
3873 * Implement the id() XPath function
3874 * node-set id(object)
3875 * The id function selects elements by their unique ID
3876 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
3877 * then the result is the union of the result of applying id to the
3878 * string value of each of the nodes in the argument node-set. When the
3879 * argument to id is of any other type, the argument is converted to a
3880 * string as if by a call to the string function; the string is split
3881 * into a whitespace-separated list of tokens (whitespace is any sequence
3882 * of characters matching the production S); the result is a node-set
3883 * containing the elements in the same document as the context node that
3884 * have a unique ID equal to any of the tokens in the list.
3885 */
3886void
3887xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3888 const xmlChar *tokens;
3889 const xmlChar *cur;
3890 xmlChar *ID;
3891 xmlAttrPtr attr;
3892 xmlNodePtr elem = NULL;
3893 xmlXPathObjectPtr ret, obj;
3894
3895 CHECK_ARITY(1);
3896 obj = valuePop(ctxt);
3897 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3898 if (obj->type == XPATH_NODESET) {
3899 xmlXPathObjectPtr newobj;
3900 int i;
3901
3902 ret = xmlXPathNewNodeSet(NULL);
3903
Daniel Veillard911f49a2001-04-07 15:39:35 +00003904 if (obj->nodesetval != NULL) {
3905 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
3906 valuePush(ctxt,
3907 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
3908 xmlXPathStringFunction(ctxt, 1);
3909 xmlXPathIdFunction(ctxt, 1);
3910 newobj = valuePop(ctxt);
3911 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
3912 newobj->nodesetval);
3913 xmlXPathFreeObject(newobj);
3914 }
Owen Taylor3473f882001-02-23 17:55:21 +00003915 }
3916
3917 xmlXPathFreeObject(obj);
3918 valuePush(ctxt, ret);
3919 return;
3920 }
3921 if (obj->type != XPATH_STRING) {
3922 valuePush(ctxt, obj);
3923 xmlXPathStringFunction(ctxt, 1);
3924 obj = valuePop(ctxt);
3925 if (obj->type != XPATH_STRING) {
3926 xmlXPathFreeObject(obj);
3927 return;
3928 }
3929 }
3930 tokens = obj->stringval;
3931
3932 ret = xmlXPathNewNodeSet(NULL);
3933 valuePush(ctxt, ret);
3934 if (tokens == NULL) {
3935 xmlXPathFreeObject(obj);
3936 return;
3937 }
3938
3939 cur = tokens;
3940
3941 while (IS_BLANK(*cur)) cur++;
3942 while (*cur != 0) {
3943 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
3944 (*cur == '.') || (*cur == '-') ||
3945 (*cur == '_') || (*cur == ':') ||
3946 (IS_COMBINING(*cur)) ||
3947 (IS_EXTENDER(*cur)))
3948 cur++;
3949
3950 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
3951
3952 ID = xmlStrndup(tokens, cur - tokens);
3953 attr = xmlGetID(ctxt->context->doc, ID);
3954 if (attr != NULL) {
3955 elem = attr->parent;
3956 xmlXPathNodeSetAdd(ret->nodesetval, elem);
3957 }
3958 if (ID != NULL)
3959 xmlFree(ID);
3960
3961 while (IS_BLANK(*cur)) cur++;
3962 tokens = cur;
3963 }
3964 xmlXPathFreeObject(obj);
3965 return;
3966}
3967
3968/**
3969 * xmlXPathLocalNameFunction:
3970 * @ctxt: the XPath Parser context
3971 * @nargs: the number of arguments
3972 *
3973 * Implement the local-name() XPath function
3974 * string local-name(node-set?)
3975 * The local-name function returns a string containing the local part
3976 * of the name of the node in the argument node-set that is first in
3977 * document order. If the node-set is empty or the first node has no
3978 * name, an empty string is returned. If the argument is omitted it
3979 * defaults to the context node.
3980 */
3981void
3982xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3983 xmlXPathObjectPtr cur;
3984
3985 if (nargs == 0) {
3986 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3987 nargs = 1;
3988 }
3989
3990 CHECK_ARITY(1);
3991 if ((ctxt->value == NULL) ||
3992 ((ctxt->value->type != XPATH_NODESET) &&
3993 (ctxt->value->type != XPATH_XSLT_TREE)))
3994 XP_ERROR(XPATH_INVALID_TYPE);
3995 cur = valuePop(ctxt);
3996
Daniel Veillard911f49a2001-04-07 15:39:35 +00003997 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003998 valuePush(ctxt, xmlXPathNewCString(""));
3999 } else {
4000 int i = 0; /* Should be first in document order !!!!! */
4001 switch (cur->nodesetval->nodeTab[i]->type) {
4002 case XML_ELEMENT_NODE:
4003 case XML_ATTRIBUTE_NODE:
4004 case XML_PI_NODE:
4005 valuePush(ctxt,
4006 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4007 break;
4008 case XML_NAMESPACE_DECL:
4009 valuePush(ctxt, xmlXPathNewString(
4010 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4011 break;
4012 default:
4013 valuePush(ctxt, xmlXPathNewCString(""));
4014 }
4015 }
4016 xmlXPathFreeObject(cur);
4017}
4018
4019/**
4020 * xmlXPathNamespaceURIFunction:
4021 * @ctxt: the XPath Parser context
4022 * @nargs: the number of arguments
4023 *
4024 * Implement the namespace-uri() XPath function
4025 * string namespace-uri(node-set?)
4026 * The namespace-uri function returns a string containing the
4027 * namespace URI of the expanded name of the node in the argument
4028 * node-set that is first in document order. If the node-set is empty,
4029 * the first node has no name, or the expanded name has no namespace
4030 * URI, an empty string is returned. If the argument is omitted it
4031 * defaults to the context node.
4032 */
4033void
4034xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4035 xmlXPathObjectPtr cur;
4036
4037 if (nargs == 0) {
4038 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4039 nargs = 1;
4040 }
4041 CHECK_ARITY(1);
4042 if ((ctxt->value == NULL) ||
4043 ((ctxt->value->type != XPATH_NODESET) &&
4044 (ctxt->value->type != XPATH_XSLT_TREE)))
4045 XP_ERROR(XPATH_INVALID_TYPE);
4046 cur = valuePop(ctxt);
4047
Daniel Veillard911f49a2001-04-07 15:39:35 +00004048 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004049 valuePush(ctxt, xmlXPathNewCString(""));
4050 } else {
4051 int i = 0; /* Should be first in document order !!!!! */
4052 switch (cur->nodesetval->nodeTab[i]->type) {
4053 case XML_ELEMENT_NODE:
4054 case XML_ATTRIBUTE_NODE:
4055 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4056 valuePush(ctxt, xmlXPathNewCString(""));
4057 else
4058 valuePush(ctxt, xmlXPathNewString(
4059 cur->nodesetval->nodeTab[i]->ns->href));
4060 break;
4061 default:
4062 valuePush(ctxt, xmlXPathNewCString(""));
4063 }
4064 }
4065 xmlXPathFreeObject(cur);
4066}
4067
4068/**
4069 * xmlXPathNameFunction:
4070 * @ctxt: the XPath Parser context
4071 * @nargs: the number of arguments
4072 *
4073 * Implement the name() XPath function
4074 * string name(node-set?)
4075 * The name function returns a string containing a QName representing
4076 * the name of the node in the argument node-set that is first in documenti
4077 * order. The QName must represent the name with respect to the namespace
4078 * declarations in effect on the node whose name is being represented.
4079 * Typically, this will be the form in which the name occurred in the XML
4080 * source. This need not be the case if there are namespace declarations
4081 * in effect on the node that associate multiple prefixes with the same
4082 * namespace. However, an implementation may include information about
4083 * the original prefix in its representation of nodes; in this case, an
4084 * implementation can ensure that the returned string is always the same
4085 * as the QName used in the XML source. If the argument it omitted it
4086 * defaults to the context node.
4087 * Libxml keep the original prefix so the "real qualified name" used is
4088 * returned.
4089 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004090static void
Owen Taylor3473f882001-02-23 17:55:21 +00004091xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4092 xmlXPathObjectPtr cur;
4093
4094 if (nargs == 0) {
4095 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4096 nargs = 1;
4097 }
4098
4099 CHECK_ARITY(1);
4100 if ((ctxt->value == NULL) ||
4101 ((ctxt->value->type != XPATH_NODESET) &&
4102 (ctxt->value->type != XPATH_XSLT_TREE)))
4103 XP_ERROR(XPATH_INVALID_TYPE);
4104 cur = valuePop(ctxt);
4105
Daniel Veillard911f49a2001-04-07 15:39:35 +00004106 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004107 valuePush(ctxt, xmlXPathNewCString(""));
4108 } else {
4109 int i = 0; /* Should be first in document order !!!!! */
4110
4111 switch (cur->nodesetval->nodeTab[i]->type) {
4112 case XML_ELEMENT_NODE:
4113 case XML_ATTRIBUTE_NODE:
4114 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4115 valuePush(ctxt, xmlXPathNewString(
4116 cur->nodesetval->nodeTab[i]->name));
4117
4118 else {
4119 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004120 snprintf(name, sizeof(name), "%s:%s",
4121 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4122 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004123 name[sizeof(name) - 1] = 0;
4124 valuePush(ctxt, xmlXPathNewCString(name));
4125 }
4126 break;
4127 default:
4128 valuePush(ctxt,
4129 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4130 xmlXPathLocalNameFunction(ctxt, 1);
4131 }
4132 }
4133 xmlXPathFreeObject(cur);
4134}
4135
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004136
4137/**
4138 * xmlXPathConvertString:
4139 * @val: an XPath object
4140 *
4141 * Converts an existing object to its string() equivalent
4142 *
4143 * Returns the new object, the old one is freed (or the operation
4144 * is done directly on @val)
4145 */
4146xmlXPathObjectPtr
4147xmlXPathConvertString(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004148 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004149
4150 if (val == NULL)
4151 return(xmlXPathNewCString(""));
4152 switch (val->type) {
4153 case XPATH_UNDEFINED:
4154#ifdef DEBUG_EXPR
4155 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
4156#endif
4157 ret = xmlXPathNewCString("");
4158 break;
4159 case XPATH_XSLT_TREE:
4160 case XPATH_NODESET:
Daniel Veillard911f49a2001-04-07 15:39:35 +00004161 if ((val->nodesetval == NULL) || (val->nodesetval->nodeNr == 0)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004162 ret = xmlXPathNewCString("");
4163 } else {
4164 xmlChar *res;
4165
4166 xmlXPathNodeSetSort(val->nodesetval);
4167 res = xmlNodeGetContent(val->nodesetval->nodeTab[0]);
4168 /* TODO: avoid allocating res to free it */
4169 ret = xmlXPathNewString(res);
4170 if (res != NULL)
4171 xmlFree(res);
4172 }
4173 break;
4174 case XPATH_STRING:
4175 return(val);
4176 case XPATH_BOOLEAN:
4177 if (val->boolval) ret = xmlXPathNewCString("true");
4178 else ret = xmlXPathNewCString("false");
4179 break;
4180 case XPATH_NUMBER: {
4181 char buf[100];
4182
4183 xmlXPathFormatNumber(val->floatval, buf, sizeof(buf));
4184 ret = xmlXPathNewCString(buf);
4185 break;
4186 }
4187 case XPATH_USERS:
4188 case XPATH_POINT:
4189 case XPATH_RANGE:
4190 case XPATH_LOCATIONSET:
4191 TODO
4192 ret = xmlXPathNewCString("");
4193 break;
4194 }
4195 xmlXPathFreeObject(val);
4196 return(ret);
4197}
4198
Owen Taylor3473f882001-02-23 17:55:21 +00004199/**
4200 * xmlXPathStringFunction:
4201 * @ctxt: the XPath Parser context
4202 * @nargs: the number of arguments
4203 *
4204 * Implement the string() XPath function
4205 * string string(object?)
4206 * he string function converts an object to a string as follows:
4207 * - A node-set is converted to a string by returning the value of
4208 * the node in the node-set that is first in document order.
4209 * If the node-set is empty, an empty string is returned.
4210 * - A number is converted to a string as follows
4211 * + NaN is converted to the string NaN
4212 * + positive zero is converted to the string 0
4213 * + negative zero is converted to the string 0
4214 * + positive infinity is converted to the string Infinity
4215 * + negative infinity is converted to the string -Infinity
4216 * + if the number is an integer, the number is represented in
4217 * decimal form as a Number with no decimal point and no leading
4218 * zeros, preceded by a minus sign (-) if the number is negative
4219 * + otherwise, the number is represented in decimal form as a
4220 * Number including a decimal point with at least one digit
4221 * before the decimal point and at least one digit after the
4222 * decimal point, preceded by a minus sign (-) if the number
4223 * is negative; there must be no leading zeros before the decimal
4224 * point apart possibly from the one required digit immediatelyi
4225 * before the decimal point; beyond the one required digit
4226 * after the decimal point there must be as many, but only as
4227 * many, more digits as are needed to uniquely distinguish the
4228 * number from all other IEEE 754 numeric values.
4229 * - The boolean false value is converted to the string false.
4230 * The boolean true value is converted to the string true.
4231 *
4232 * If the argument is omitted, it defaults to a node-set with the
4233 * context node as its only member.
4234 */
4235void
4236xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4237 xmlXPathObjectPtr cur;
4238
4239 if (nargs == 0) {
4240 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4241 nargs = 1;
4242 }
4243
4244 CHECK_ARITY(1);
4245 cur = valuePop(ctxt);
4246 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004247 cur = xmlXPathConvertString(cur);
4248 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004249}
4250
4251/**
4252 * xmlXPathStringLengthFunction:
4253 * @ctxt: the XPath Parser context
4254 * @nargs: the number of arguments
4255 *
4256 * Implement the string-length() XPath function
4257 * number string-length(string?)
4258 * The string-length returns the number of characters in the string
4259 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4260 * the context node converted to a string, in other words the value
4261 * of the context node.
4262 */
4263void
4264xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4265 xmlXPathObjectPtr cur;
4266
4267 if (nargs == 0) {
4268 if (ctxt->context->node == NULL) {
4269 valuePush(ctxt, xmlXPathNewFloat(0));
4270 } else {
4271 xmlChar *content;
4272
4273 content = xmlNodeGetContent(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004274 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004275 xmlFree(content);
4276 }
4277 return;
4278 }
4279 CHECK_ARITY(1);
4280 CAST_TO_STRING;
4281 CHECK_TYPE(XPATH_STRING);
4282 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004283 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004284 xmlXPathFreeObject(cur);
4285}
4286
4287/**
4288 * xmlXPathConcatFunction:
4289 * @ctxt: the XPath Parser context
4290 * @nargs: the number of arguments
4291 *
4292 * Implement the concat() XPath function
4293 * string concat(string, string, string*)
4294 * The concat function returns the concatenation of its arguments.
4295 */
4296void
4297xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4298 xmlXPathObjectPtr cur, newobj;
4299 xmlChar *tmp;
4300
4301 if (nargs < 2) {
4302 CHECK_ARITY(2);
4303 }
4304
4305 CAST_TO_STRING;
4306 cur = valuePop(ctxt);
4307 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4308 xmlXPathFreeObject(cur);
4309 return;
4310 }
4311 nargs--;
4312
4313 while (nargs > 0) {
4314 CAST_TO_STRING;
4315 newobj = valuePop(ctxt);
4316 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4317 xmlXPathFreeObject(newobj);
4318 xmlXPathFreeObject(cur);
4319 XP_ERROR(XPATH_INVALID_TYPE);
4320 }
4321 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4322 newobj->stringval = cur->stringval;
4323 cur->stringval = tmp;
4324
4325 xmlXPathFreeObject(newobj);
4326 nargs--;
4327 }
4328 valuePush(ctxt, cur);
4329}
4330
4331/**
4332 * xmlXPathContainsFunction:
4333 * @ctxt: the XPath Parser context
4334 * @nargs: the number of arguments
4335 *
4336 * Implement the contains() XPath function
4337 * boolean contains(string, string)
4338 * The contains function returns true if the first argument string
4339 * contains the second argument string, and otherwise returns false.
4340 */
4341void
4342xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4343 xmlXPathObjectPtr hay, needle;
4344
4345 CHECK_ARITY(2);
4346 CAST_TO_STRING;
4347 CHECK_TYPE(XPATH_STRING);
4348 needle = valuePop(ctxt);
4349 CAST_TO_STRING;
4350 hay = valuePop(ctxt);
4351 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4352 xmlXPathFreeObject(hay);
4353 xmlXPathFreeObject(needle);
4354 XP_ERROR(XPATH_INVALID_TYPE);
4355 }
4356 if (xmlStrstr(hay->stringval, needle->stringval))
4357 valuePush(ctxt, xmlXPathNewBoolean(1));
4358 else
4359 valuePush(ctxt, xmlXPathNewBoolean(0));
4360 xmlXPathFreeObject(hay);
4361 xmlXPathFreeObject(needle);
4362}
4363
4364/**
4365 * xmlXPathStartsWithFunction:
4366 * @ctxt: the XPath Parser context
4367 * @nargs: the number of arguments
4368 *
4369 * Implement the starts-with() XPath function
4370 * boolean starts-with(string, string)
4371 * The starts-with function returns true if the first argument string
4372 * starts with the second argument string, and otherwise returns false.
4373 */
4374void
4375xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4376 xmlXPathObjectPtr hay, needle;
4377 int n;
4378
4379 CHECK_ARITY(2);
4380 CAST_TO_STRING;
4381 CHECK_TYPE(XPATH_STRING);
4382 needle = valuePop(ctxt);
4383 CAST_TO_STRING;
4384 hay = valuePop(ctxt);
4385 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4386 xmlXPathFreeObject(hay);
4387 xmlXPathFreeObject(needle);
4388 XP_ERROR(XPATH_INVALID_TYPE);
4389 }
4390 n = xmlStrlen(needle->stringval);
4391 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4392 valuePush(ctxt, xmlXPathNewBoolean(0));
4393 else
4394 valuePush(ctxt, xmlXPathNewBoolean(1));
4395 xmlXPathFreeObject(hay);
4396 xmlXPathFreeObject(needle);
4397}
4398
4399/**
4400 * xmlXPathSubstringFunction:
4401 * @ctxt: the XPath Parser context
4402 * @nargs: the number of arguments
4403 *
4404 * Implement the substring() XPath function
4405 * string substring(string, number, number?)
4406 * The substring function returns the substring of the first argument
4407 * starting at the position specified in the second argument with
4408 * length specified in the third argument. For example,
4409 * substring("12345",2,3) returns "234". If the third argument is not
4410 * specified, it returns the substring starting at the position specified
4411 * in the second argument and continuing to the end of the string. For
4412 * example, substring("12345",2) returns "2345". More precisely, each
4413 * character in the string (see [3.6 Strings]) is considered to have a
4414 * numeric position: the position of the first character is 1, the position
4415 * of the second character is 2 and so on. The returned substring contains
4416 * those characters for which the position of the character is greater than
4417 * or equal to the second argument and, if the third argument is specified,
4418 * less than the sum of the second and third arguments; the comparisons
4419 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4420 * - substring("12345", 1.5, 2.6) returns "234"
4421 * - substring("12345", 0, 3) returns "12"
4422 * - substring("12345", 0 div 0, 3) returns ""
4423 * - substring("12345", 1, 0 div 0) returns ""
4424 * - substring("12345", -42, 1 div 0) returns "12345"
4425 * - substring("12345", -1 div 0, 1 div 0) returns ""
4426 */
4427void
4428xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4429 xmlXPathObjectPtr str, start, len;
4430 double le, in;
4431 int i, l;
4432 xmlChar *ret;
4433
4434 /*
Daniel Veillarde043ee12001-04-16 14:08:07 +00004435 * TODO: need to be converted to UTF8 strings
Owen Taylor3473f882001-02-23 17:55:21 +00004436 */
4437 if (nargs < 2) {
4438 CHECK_ARITY(2);
4439 }
4440 if (nargs > 3) {
4441 CHECK_ARITY(3);
4442 }
4443 if (nargs == 3) {
4444 CAST_TO_NUMBER;
4445 CHECK_TYPE(XPATH_NUMBER);
4446 len = valuePop(ctxt);
4447 le = len->floatval;
4448 xmlXPathFreeObject(len);
4449 } else {
4450 le = 2000000000;
4451 }
4452 CAST_TO_NUMBER;
4453 CHECK_TYPE(XPATH_NUMBER);
4454 start = valuePop(ctxt);
4455 in = start->floatval;
4456 xmlXPathFreeObject(start);
4457 CAST_TO_STRING;
4458 CHECK_TYPE(XPATH_STRING);
4459 str = valuePop(ctxt);
4460 le += in;
4461
4462 /* integer index of the first char */
4463 i = (int) in;
4464 if (((double)i) != in) i++;
4465
4466 /* integer index of the last char */
4467 l = (int) le;
4468 if (((double)l) != le) l++;
4469
4470 /* back to a zero based len */
4471 i--;
4472 l--;
4473
4474 /* check against the string len */
4475 if (l > 1024) {
4476 l = xmlStrlen(str->stringval);
4477 }
4478 if (i < 0) {
4479 i = 0;
4480 }
4481
4482 /* number of chars to copy */
4483 l -= i;
4484
4485 ret = xmlStrsub(str->stringval, i, l);
4486 if (ret == NULL)
4487 valuePush(ctxt, xmlXPathNewCString(""));
4488 else {
4489 valuePush(ctxt, xmlXPathNewString(ret));
4490 xmlFree(ret);
4491 }
4492 xmlXPathFreeObject(str);
4493}
4494
4495/**
4496 * xmlXPathSubstringBeforeFunction:
4497 * @ctxt: the XPath Parser context
4498 * @nargs: the number of arguments
4499 *
4500 * Implement the substring-before() XPath function
4501 * string substring-before(string, string)
4502 * The substring-before function returns the substring of the first
4503 * argument string that precedes the first occurrence of the second
4504 * argument string in the first argument string, or the empty string
4505 * if the first argument string does not contain the second argument
4506 * string. For example, substring-before("1999/04/01","/") returns 1999.
4507 */
4508void
4509xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4510 xmlXPathObjectPtr str;
4511 xmlXPathObjectPtr find;
4512 xmlBufferPtr target;
4513 const xmlChar *point;
4514 int offset;
4515
4516 CHECK_ARITY(2);
4517 CAST_TO_STRING;
4518 find = valuePop(ctxt);
4519 CAST_TO_STRING;
4520 str = valuePop(ctxt);
4521
4522 target = xmlBufferCreate();
4523 if (target) {
4524 point = xmlStrstr(str->stringval, find->stringval);
4525 if (point) {
4526 offset = (int)(point - str->stringval);
4527 xmlBufferAdd(target, str->stringval, offset);
4528 }
4529 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4530 xmlBufferFree(target);
4531 }
4532
4533 xmlXPathFreeObject(str);
4534 xmlXPathFreeObject(find);
4535}
4536
4537/**
4538 * xmlXPathSubstringAfterFunction:
4539 * @ctxt: the XPath Parser context
4540 * @nargs: the number of arguments
4541 *
4542 * Implement the substring-after() XPath function
4543 * string substring-after(string, string)
4544 * The substring-after function returns the substring of the first
4545 * argument string that follows the first occurrence of the second
4546 * argument string in the first argument string, or the empty stringi
4547 * if the first argument string does not contain the second argument
4548 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4549 * and substring-after("1999/04/01","19") returns 99/04/01.
4550 */
4551void
4552xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4553 xmlXPathObjectPtr str;
4554 xmlXPathObjectPtr find;
4555 xmlBufferPtr target;
4556 const xmlChar *point;
4557 int offset;
4558
4559 CHECK_ARITY(2);
4560 CAST_TO_STRING;
4561 find = valuePop(ctxt);
4562 CAST_TO_STRING;
4563 str = valuePop(ctxt);
4564
4565 target = xmlBufferCreate();
4566 if (target) {
4567 point = xmlStrstr(str->stringval, find->stringval);
4568 if (point) {
4569 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4570 xmlBufferAdd(target, &str->stringval[offset],
4571 xmlStrlen(str->stringval) - offset);
4572 }
4573 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4574 xmlBufferFree(target);
4575 }
4576
4577 xmlXPathFreeObject(str);
4578 xmlXPathFreeObject(find);
4579}
4580
4581/**
4582 * xmlXPathNormalizeFunction:
4583 * @ctxt: the XPath Parser context
4584 * @nargs: the number of arguments
4585 *
4586 * Implement the normalize-space() XPath function
4587 * string normalize-space(string?)
4588 * The normalize-space function returns the argument string with white
4589 * space normalized by stripping leading and trailing whitespace
4590 * and replacing sequences of whitespace characters by a single
4591 * space. Whitespace characters are the same allowed by the S production
4592 * in XML. If the argument is omitted, it defaults to the context
4593 * node converted to a string, in other words the value of the context node.
4594 */
4595void
4596xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4597 xmlXPathObjectPtr obj = NULL;
4598 xmlChar *source = NULL;
4599 xmlBufferPtr target;
4600 xmlChar blank;
4601
4602 if (nargs == 0) {
4603 /* Use current context node */
4604 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4605 xmlXPathStringFunction(ctxt, 1);
4606 nargs = 1;
4607 }
4608
4609 CHECK_ARITY(1);
4610 CAST_TO_STRING;
4611 CHECK_TYPE(XPATH_STRING);
4612 obj = valuePop(ctxt);
4613 source = obj->stringval;
4614
4615 target = xmlBufferCreate();
4616 if (target && source) {
4617
4618 /* Skip leading whitespaces */
4619 while (IS_BLANK(*source))
4620 source++;
4621
4622 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4623 blank = 0;
4624 while (*source) {
4625 if (IS_BLANK(*source)) {
4626 blank = *source;
4627 } else {
4628 if (blank) {
4629 xmlBufferAdd(target, &blank, 1);
4630 blank = 0;
4631 }
4632 xmlBufferAdd(target, source, 1);
4633 }
4634 source++;
4635 }
4636
4637 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4638 xmlBufferFree(target);
4639 }
4640 xmlXPathFreeObject(obj);
4641}
4642
4643/**
4644 * xmlXPathTranslateFunction:
4645 * @ctxt: the XPath Parser context
4646 * @nargs: the number of arguments
4647 *
4648 * Implement the translate() XPath function
4649 * string translate(string, string, string)
4650 * The translate function returns the first argument string with
4651 * occurrences of characters in the second argument string replaced
4652 * by the character at the corresponding position in the third argument
4653 * string. For example, translate("bar","abc","ABC") returns the string
4654 * BAr. If there is a character in the second argument string with no
4655 * character at a corresponding position in the third argument string
4656 * (because the second argument string is longer than the third argument
4657 * string), then occurrences of that character in the first argument
4658 * string are removed. For example, translate("--aaa--","abc-","ABC")
4659 * returns "AAA". If a character occurs more than once in second
4660 * argument string, then the first occurrence determines the replacement
4661 * character. If the third argument string is longer than the second
4662 * argument string, then excess characters are ignored.
4663 */
4664void
4665xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00004666 xmlXPathObjectPtr str;
4667 xmlXPathObjectPtr from;
4668 xmlXPathObjectPtr to;
4669 xmlBufferPtr target;
4670 int i, offset, max;
4671 xmlChar ch;
4672 const xmlChar *point;
Owen Taylor3473f882001-02-23 17:55:21 +00004673
Daniel Veillarde043ee12001-04-16 14:08:07 +00004674 /*
4675 * TODO: need to be converted to UTF8 strings
4676 */
4677 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00004678
Daniel Veillarde043ee12001-04-16 14:08:07 +00004679 CAST_TO_STRING;
4680 to = valuePop(ctxt);
4681 CAST_TO_STRING;
4682 from = valuePop(ctxt);
4683 CAST_TO_STRING;
4684 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004685
Daniel Veillarde043ee12001-04-16 14:08:07 +00004686 target = xmlBufferCreate();
4687 if (target) {
4688 max = xmlStrlen(to->stringval);
4689 for (i = 0; (ch = str->stringval[i]); i++) {
4690 point = xmlStrchr(from->stringval, ch);
4691 if (point) {
4692 offset = (int)(point - from->stringval);
4693 if (offset < max)
4694 xmlBufferAdd(target, &to->stringval[offset], 1);
4695 } else
4696 xmlBufferAdd(target, &ch, 1);
4697 }
Owen Taylor3473f882001-02-23 17:55:21 +00004698 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00004699 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4700 xmlBufferFree(target);
4701 xmlXPathFreeObject(str);
4702 xmlXPathFreeObject(from);
4703 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00004704}
4705
4706/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004707 * xmlXPathConvertBoolean:
4708 * @val: an XPath object
4709 *
4710 * Converts an existing object to its boolean() equivalent
4711 *
4712 * Returns the new object, the old one is freed (or the operation
4713 * is done directly on @val)
4714 */
4715xmlXPathObjectPtr
4716xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4717 int res = 0;
4718
4719 if (val == NULL)
4720 return(NULL);
4721 switch (val->type) {
4722 case XPATH_NODESET:
4723 case XPATH_XSLT_TREE:
4724 if ((val->nodesetval == NULL) ||
4725 (val->nodesetval->nodeNr == 0)) res = 0;
4726 else
4727 res = 1;
4728 break;
4729 case XPATH_STRING:
4730 if ((val->stringval == NULL) ||
4731 (val->stringval[0] == 0)) res = 0;
4732 else
4733 res = 1;
4734 break;
4735 case XPATH_BOOLEAN:
4736 return(val);
4737 case XPATH_NUMBER:
4738 if (val->floatval) res = 1;
4739 break;
4740 default:
4741 STRANGE
4742 }
4743 xmlXPathFreeObject(val);
4744 return(xmlXPathNewBoolean(res));
4745}
4746
4747/**
Owen Taylor3473f882001-02-23 17:55:21 +00004748 * xmlXPathBooleanFunction:
4749 * @ctxt: the XPath Parser context
4750 * @nargs: the number of arguments
4751 *
4752 * Implement the boolean() XPath function
4753 * boolean boolean(object)
4754 * he boolean function converts its argument to a boolean as follows:
4755 * - a number is true if and only if it is neither positive or
4756 * negative zero nor NaN
4757 * - a node-set is true if and only if it is non-empty
4758 * - a string is true if and only if its length is non-zero
4759 */
4760void
4761xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4762 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00004763
4764 CHECK_ARITY(1);
4765 cur = valuePop(ctxt);
4766 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004767 cur = xmlXPathConvertBoolean(cur);
4768 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004769}
4770
4771/**
4772 * xmlXPathNotFunction:
4773 * @ctxt: the XPath Parser context
4774 * @nargs: the number of arguments
4775 *
4776 * Implement the not() XPath function
4777 * boolean not(boolean)
4778 * The not function returns true if its argument is false,
4779 * and false otherwise.
4780 */
4781void
4782xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4783 CHECK_ARITY(1);
4784 CAST_TO_BOOLEAN;
4785 CHECK_TYPE(XPATH_BOOLEAN);
4786 ctxt->value->boolval = ! ctxt->value->boolval;
4787}
4788
4789/**
4790 * xmlXPathTrueFunction:
4791 * @ctxt: the XPath Parser context
4792 * @nargs: the number of arguments
4793 *
4794 * Implement the true() XPath function
4795 * boolean true()
4796 */
4797void
4798xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4799 CHECK_ARITY(0);
4800 valuePush(ctxt, xmlXPathNewBoolean(1));
4801}
4802
4803/**
4804 * xmlXPathFalseFunction:
4805 * @ctxt: the XPath Parser context
4806 * @nargs: the number of arguments
4807 *
4808 * Implement the false() XPath function
4809 * boolean false()
4810 */
4811void
4812xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4813 CHECK_ARITY(0);
4814 valuePush(ctxt, xmlXPathNewBoolean(0));
4815}
4816
4817/**
4818 * xmlXPathLangFunction:
4819 * @ctxt: the XPath Parser context
4820 * @nargs: the number of arguments
4821 *
4822 * Implement the lang() XPath function
4823 * boolean lang(string)
4824 * The lang function returns true or false depending on whether the
4825 * language of the context node as specified by xml:lang attributes
4826 * is the same as or is a sublanguage of the language specified by
4827 * the argument string. The language of the context node is determined
4828 * by the value of the xml:lang attribute on the context node, or, if
4829 * the context node has no xml:lang attribute, by the value of the
4830 * xml:lang attribute on the nearest ancestor of the context node that
4831 * has an xml:lang attribute. If there is no such attribute, then lang
4832 * returns false. If there is such an attribute, then lang returns
4833 * true if the attribute value is equal to the argument ignoring case,
4834 * or if there is some suffix starting with - such that the attribute
4835 * value is equal to the argument ignoring that suffix of the attribute
4836 * value and ignoring case.
4837 */
4838void
4839xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4840 xmlXPathObjectPtr val;
4841 const xmlChar *theLang;
4842 const xmlChar *lang;
4843 int ret = 0;
4844 int i;
4845
4846 CHECK_ARITY(1);
4847 CAST_TO_STRING;
4848 CHECK_TYPE(XPATH_STRING);
4849 val = valuePop(ctxt);
4850 lang = val->stringval;
4851 theLang = xmlNodeGetLang(ctxt->context->node);
4852 if ((theLang != NULL) && (lang != NULL)) {
4853 for (i = 0;lang[i] != 0;i++)
4854 if (toupper(lang[i]) != toupper(theLang[i]))
4855 goto not_equal;
4856 ret = 1;
4857 }
4858not_equal:
4859 xmlXPathFreeObject(val);
4860 valuePush(ctxt, xmlXPathNewBoolean(ret));
4861}
4862
4863/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004864 * xmlXPathConvertNumber:
4865 * @val: an XPath object
4866 *
4867 * Converts an existing object to its number() equivalent
4868 *
4869 * Returns the new object, the old one is freed (or the operation
4870 * is done directly on @val)
4871 */
4872xmlXPathObjectPtr
4873xmlXPathConvertNumber(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004874 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004875 double res;
4876
4877 if (val == NULL)
4878 return(xmlXPathNewFloat(0.0));
4879 switch (val->type) {
4880 case XPATH_UNDEFINED:
4881#ifdef DEBUG_EXPR
4882 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
4883#endif
4884 ret = xmlXPathNewFloat(0.0);
4885 break;
4886 case XPATH_XSLT_TREE:
4887 case XPATH_NODESET:
4888 val = xmlXPathConvertString(val);
4889 /* no break on purpose */
4890 case XPATH_STRING:
4891 res = xmlXPathStringEvalNumber(val->stringval);
4892 ret = xmlXPathNewFloat(res);
4893 break;
4894 case XPATH_BOOLEAN:
4895 if (val->boolval) ret = xmlXPathNewFloat(1.0);
4896 else ret = xmlXPathNewFloat(0.0);
4897 break;
4898 case XPATH_NUMBER:
4899 return(val);
4900 case XPATH_USERS:
4901 case XPATH_POINT:
4902 case XPATH_RANGE:
4903 case XPATH_LOCATIONSET:
4904 TODO
4905 ret = xmlXPathNewFloat(0.0);
4906 break;
4907 }
4908 xmlXPathFreeObject(val);
4909 return(ret);
4910}
4911
4912/**
Owen Taylor3473f882001-02-23 17:55:21 +00004913 * xmlXPathNumberFunction:
4914 * @ctxt: the XPath Parser context
4915 * @nargs: the number of arguments
4916 *
4917 * Implement the number() XPath function
4918 * number number(object?)
4919 */
4920void
4921xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4922 xmlXPathObjectPtr cur;
4923 double res;
4924
4925 if (nargs == 0) {
4926 if (ctxt->context->node == NULL) {
4927 valuePush(ctxt, xmlXPathNewFloat(0.0));
4928 } else {
4929 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
4930
4931 res = xmlXPathStringEvalNumber(content);
4932 valuePush(ctxt, xmlXPathNewFloat(res));
4933 xmlFree(content);
4934 }
4935 return;
4936 }
4937
4938 CHECK_ARITY(1);
4939 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004940 cur = xmlXPathConvertNumber(cur);
4941 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004942}
4943
4944/**
4945 * xmlXPathSumFunction:
4946 * @ctxt: the XPath Parser context
4947 * @nargs: the number of arguments
4948 *
4949 * Implement the sum() XPath function
4950 * number sum(node-set)
4951 * The sum function returns the sum of the values of the nodes in
4952 * the argument node-set.
4953 */
4954void
4955xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4956 xmlXPathObjectPtr cur;
4957 int i;
4958
4959 CHECK_ARITY(1);
4960 if ((ctxt->value == NULL) ||
4961 ((ctxt->value->type != XPATH_NODESET) &&
4962 (ctxt->value->type != XPATH_XSLT_TREE)))
4963 XP_ERROR(XPATH_INVALID_TYPE);
4964 cur = valuePop(ctxt);
4965
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004966 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004967 valuePush(ctxt, xmlXPathNewFloat(0.0));
4968 } else {
4969 valuePush(ctxt,
4970 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
4971 xmlXPathNumberFunction(ctxt, 1);
4972 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
4973 valuePush(ctxt,
4974 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4975 xmlXPathAddValues(ctxt);
4976 }
4977 }
4978 xmlXPathFreeObject(cur);
4979}
4980
4981/**
4982 * xmlXPathFloorFunction:
4983 * @ctxt: the XPath Parser context
4984 * @nargs: the number of arguments
4985 *
4986 * Implement the floor() XPath function
4987 * number floor(number)
4988 * The floor function returns the largest (closest to positive infinity)
4989 * number that is not greater than the argument and that is an integer.
4990 */
4991void
4992xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4993 CHECK_ARITY(1);
4994 CAST_TO_NUMBER;
4995 CHECK_TYPE(XPATH_NUMBER);
4996#if 0
4997 ctxt->value->floatval = floor(ctxt->value->floatval);
4998#else
4999 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5000 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5001#endif
5002}
5003
5004/**
5005 * xmlXPathCeilingFunction:
5006 * @ctxt: the XPath Parser context
5007 * @nargs: the number of arguments
5008 *
5009 * Implement the ceiling() XPath function
5010 * number ceiling(number)
5011 * The ceiling function returns the smallest (closest to negative infinity)
5012 * number that is not less than the argument and that is an integer.
5013 */
5014void
5015xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5016 double f;
5017
5018 CHECK_ARITY(1);
5019 CAST_TO_NUMBER;
5020 CHECK_TYPE(XPATH_NUMBER);
5021
5022#if 0
5023 ctxt->value->floatval = ceil(ctxt->value->floatval);
5024#else
5025 f = (double)((int) ctxt->value->floatval);
5026 if (f != ctxt->value->floatval)
5027 ctxt->value->floatval = f + 1;
5028#endif
5029}
5030
5031/**
5032 * xmlXPathRoundFunction:
5033 * @ctxt: the XPath Parser context
5034 * @nargs: the number of arguments
5035 *
5036 * Implement the round() XPath function
5037 * number round(number)
5038 * The round function returns the number that is closest to the
5039 * argument and that is an integer. If there are two such numbers,
5040 * then the one that is even is returned.
5041 */
5042void
5043xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5044 double f;
5045
5046 CHECK_ARITY(1);
5047 CAST_TO_NUMBER;
5048 CHECK_TYPE(XPATH_NUMBER);
5049
5050 if ((ctxt->value->floatval == xmlXPathNAN) ||
5051 (ctxt->value->floatval == xmlXPathPINF) ||
5052 (ctxt->value->floatval == xmlXPathNINF) ||
5053 (ctxt->value->floatval == 0.0))
5054 return;
5055
5056#if 0
5057 f = floor(ctxt->value->floatval);
5058#else
5059 f = (double)((int) ctxt->value->floatval);
5060#endif
5061 if (ctxt->value->floatval < f + 0.5)
5062 ctxt->value->floatval = f;
5063 else
5064 ctxt->value->floatval = f + 1;
5065}
5066
5067/************************************************************************
5068 * *
5069 * The Parser *
5070 * *
5071 ************************************************************************/
5072
5073/*
5074 * a couple of forward declarations since we use a recursive call based
5075 * implementation.
5076 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005077static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005078static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005079static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005080#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005081static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5082#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005083#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005084static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005085#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005086static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5087 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005088
5089/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005090 * xmlXPathCurrentChar:
5091 * @ctxt: the XPath parser context
5092 * @cur: pointer to the beginning of the char
5093 * @len: pointer to the length of the char read
5094 *
5095 * The current char value, if using UTF-8 this may actaully span multiple
5096 * bytes in the input buffer.
5097 *
5098 * Returns the current char value and its lenght
5099 */
5100
5101static int
5102xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5103 unsigned char c;
5104 unsigned int val;
5105 const xmlChar *cur;
5106
5107 if (ctxt == NULL)
5108 return(0);
5109 cur = ctxt->cur;
5110
5111 /*
5112 * We are supposed to handle UTF8, check it's valid
5113 * From rfc2044: encoding of the Unicode values on UTF-8:
5114 *
5115 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5116 * 0000 0000-0000 007F 0xxxxxxx
5117 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5118 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5119 *
5120 * Check for the 0x110000 limit too
5121 */
5122 c = *cur;
5123 if (c & 0x80) {
5124 if ((cur[1] & 0xc0) != 0x80)
5125 goto encoding_error;
5126 if ((c & 0xe0) == 0xe0) {
5127
5128 if ((cur[2] & 0xc0) != 0x80)
5129 goto encoding_error;
5130 if ((c & 0xf0) == 0xf0) {
5131 if (((c & 0xf8) != 0xf0) ||
5132 ((cur[3] & 0xc0) != 0x80))
5133 goto encoding_error;
5134 /* 4-byte code */
5135 *len = 4;
5136 val = (cur[0] & 0x7) << 18;
5137 val |= (cur[1] & 0x3f) << 12;
5138 val |= (cur[2] & 0x3f) << 6;
5139 val |= cur[3] & 0x3f;
5140 } else {
5141 /* 3-byte code */
5142 *len = 3;
5143 val = (cur[0] & 0xf) << 12;
5144 val |= (cur[1] & 0x3f) << 6;
5145 val |= cur[2] & 0x3f;
5146 }
5147 } else {
5148 /* 2-byte code */
5149 *len = 2;
5150 val = (cur[0] & 0x1f) << 6;
5151 val |= cur[1] & 0x3f;
5152 }
5153 if (!IS_CHAR(val)) {
5154 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5155 }
5156 return(val);
5157 } else {
5158 /* 1-byte code */
5159 *len = 1;
5160 return((int) *cur);
5161 }
5162encoding_error:
5163 /*
5164 * If we detect an UTF8 error that probably mean that the
5165 * input encoding didn't get properly advertized in the
5166 * declaration header. Report the error and switch the encoding
5167 * to ISO-Latin-1 (if you don't like this policy, just declare the
5168 * encoding !)
5169 */
5170 XP_ERROR0(XPATH_ENCODING_ERROR);
5171 *len = 1;
5172 return((int) *cur);
5173}
5174
5175/**
Owen Taylor3473f882001-02-23 17:55:21 +00005176 * xmlXPathParseNCName:
5177 * @ctxt: the XPath Parser context
5178 *
5179 * parse an XML namespace non qualified name.
5180 *
5181 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5182 *
5183 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5184 * CombiningChar | Extender
5185 *
5186 * Returns the namespace name or NULL
5187 */
5188
5189xmlChar *
5190xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005191 const xmlChar *in;
5192 xmlChar *ret;
5193 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005194
Daniel Veillard2156a562001-04-28 12:24:34 +00005195 /*
5196 * Accelerator for simple ASCII names
5197 */
5198 in = ctxt->cur;
5199 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5200 ((*in >= 0x41) && (*in <= 0x5A)) ||
5201 (*in == '_')) {
5202 in++;
5203 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5204 ((*in >= 0x41) && (*in <= 0x5A)) ||
5205 ((*in >= 0x30) && (*in <= 0x39)) ||
5206 (*in == '_'))
5207 in++;
5208 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5209 (*in == '[') || (*in == ']') || (*in == ':') ||
5210 (*in == '@') || (*in == '*')) {
5211 count = in - ctxt->cur;
5212 if (count == 0)
5213 return(NULL);
5214 ret = xmlStrndup(ctxt->cur, count);
5215 ctxt->cur = in;
5216 return(ret);
5217 }
5218 }
5219 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005220}
5221
Daniel Veillard2156a562001-04-28 12:24:34 +00005222
Owen Taylor3473f882001-02-23 17:55:21 +00005223/**
5224 * xmlXPathParseQName:
5225 * @ctxt: the XPath Parser context
5226 * @prefix: a xmlChar **
5227 *
5228 * parse an XML qualified name
5229 *
5230 * [NS 5] QName ::= (Prefix ':')? LocalPart
5231 *
5232 * [NS 6] Prefix ::= NCName
5233 *
5234 * [NS 7] LocalPart ::= NCName
5235 *
5236 * Returns the function returns the local part, and prefix is updated
5237 * to get the Prefix if any.
5238 */
5239
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005240static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005241xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5242 xmlChar *ret = NULL;
5243
5244 *prefix = NULL;
5245 ret = xmlXPathParseNCName(ctxt);
5246 if (CUR == ':') {
5247 *prefix = ret;
5248 NEXT;
5249 ret = xmlXPathParseNCName(ctxt);
5250 }
5251 return(ret);
5252}
5253
5254/**
5255 * xmlXPathParseName:
5256 * @ctxt: the XPath Parser context
5257 *
5258 * parse an XML name
5259 *
5260 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5261 * CombiningChar | Extender
5262 *
5263 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5264 *
5265 * Returns the namespace name or NULL
5266 */
5267
5268xmlChar *
5269xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005270 const xmlChar *in;
5271 xmlChar *ret;
5272 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005273
Daniel Veillard61d80a22001-04-27 17:13:01 +00005274 /*
5275 * Accelerator for simple ASCII names
5276 */
5277 in = ctxt->cur;
5278 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5279 ((*in >= 0x41) && (*in <= 0x5A)) ||
5280 (*in == '_') || (*in == ':')) {
5281 in++;
5282 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5283 ((*in >= 0x41) && (*in <= 0x5A)) ||
5284 ((*in >= 0x30) && (*in <= 0x39)) ||
5285 (*in == '_') || (*in == ':'))
5286 in++;
5287 if ((*in == ' ') || (*in == '>') || (*in == '/')) {
5288 count = in - ctxt->cur;
5289 ret = xmlStrndup(ctxt->cur, count);
5290 ctxt->cur = in;
5291 return(ret);
5292 }
5293 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005294 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005295}
5296
Daniel Veillard61d80a22001-04-27 17:13:01 +00005297static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005298xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005299 xmlChar buf[XML_MAX_NAMELEN + 5];
5300 int len = 0, l;
5301 int c;
5302
5303 /*
5304 * Handler for more complex cases
5305 */
5306 c = CUR_CHAR(l);
5307 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005308 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5309 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005310 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005311 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005312 return(NULL);
5313 }
5314
5315 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5316 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5317 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005318 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005319 (IS_COMBINING(c)) ||
5320 (IS_EXTENDER(c)))) {
5321 COPY_BUF(l,buf,len,c);
5322 NEXTL(l);
5323 c = CUR_CHAR(l);
5324 if (len >= XML_MAX_NAMELEN) {
5325 /*
5326 * Okay someone managed to make a huge name, so he's ready to pay
5327 * for the processing speed.
5328 */
5329 xmlChar *buffer;
5330 int max = len * 2;
5331
5332 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5333 if (buffer == NULL) {
5334 XP_ERROR0(XPATH_MEMORY_ERROR);
5335 }
5336 memcpy(buffer, buf, len);
5337 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5338 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005339 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005340 (IS_COMBINING(c)) ||
5341 (IS_EXTENDER(c))) {
5342 if (len + 10 > max) {
5343 max *= 2;
5344 buffer = (xmlChar *) xmlRealloc(buffer,
5345 max * sizeof(xmlChar));
5346 XP_ERROR0(XPATH_MEMORY_ERROR);
5347 if (buffer == NULL) {
5348 XP_ERROR0(XPATH_MEMORY_ERROR);
5349 }
5350 }
5351 COPY_BUF(l,buffer,len,c);
5352 NEXTL(l);
5353 c = CUR_CHAR(l);
5354 }
5355 buffer[len] = 0;
5356 return(buffer);
5357 }
5358 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005359 if (len == 0)
5360 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005361 return(xmlStrndup(buf, len));
5362}
Owen Taylor3473f882001-02-23 17:55:21 +00005363/**
5364 * xmlXPathStringEvalNumber:
5365 * @str: A string to scan
5366 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005367 * [30a] Float ::= Number ('e' Digits?)?
5368 *
Owen Taylor3473f882001-02-23 17:55:21 +00005369 * [30] Number ::= Digits ('.' Digits?)?
5370 * | '.' Digits
5371 * [31] Digits ::= [0-9]+
5372 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005373 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005374 * In complement of the Number expression, this function also handles
5375 * negative values : '-' Number.
5376 *
5377 * Returns the double value.
5378 */
5379double
5380xmlXPathStringEvalNumber(const xmlChar *str) {
5381 const xmlChar *cur = str;
5382 double ret = 0.0;
5383 double mult = 1;
5384 int ok = 0;
5385 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005386 int exponent = 0;
5387 int is_exponent_negative = 0;
5388
Owen Taylor3473f882001-02-23 17:55:21 +00005389 while (IS_BLANK(*cur)) cur++;
5390 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5391 return(xmlXPathNAN);
5392 }
5393 if (*cur == '-') {
5394 isneg = 1;
5395 cur++;
5396 }
5397 while ((*cur >= '0') && (*cur <= '9')) {
5398 ret = ret * 10 + (*cur - '0');
5399 ok = 1;
5400 cur++;
5401 }
5402 if (*cur == '.') {
5403 cur++;
5404 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5405 return(xmlXPathNAN);
5406 }
5407 while ((*cur >= '0') && (*cur <= '9')) {
5408 mult /= 10;
5409 ret = ret + (*cur - '0') * mult;
5410 cur++;
5411 }
5412 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005413 if ((*cur == 'e') || (*cur == 'E')) {
5414 cur++;
5415 if (*cur == '-') {
5416 is_exponent_negative = 1;
5417 cur++;
5418 }
5419 while ((*cur >= '0') && (*cur <= '9')) {
5420 exponent = exponent * 10 + (*cur - '0');
5421 cur++;
5422 }
5423 }
Owen Taylor3473f882001-02-23 17:55:21 +00005424 while (IS_BLANK(*cur)) cur++;
5425 if (*cur != 0) return(xmlXPathNAN);
5426 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005427 if (is_exponent_negative) exponent = -exponent;
5428 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005429 return(ret);
5430}
5431
5432/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005433 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005434 * @ctxt: the XPath Parser context
5435 *
5436 * [30] Number ::= Digits ('.' Digits?)?
5437 * | '.' Digits
5438 * [31] Digits ::= [0-9]+
5439 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005440 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005441 *
5442 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005443static void
5444xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005445 double ret = 0.0;
5446 double mult = 1;
5447 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005448 int exponent = 0;
5449 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005450
5451 CHECK_ERROR;
5452 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5453 XP_ERROR(XPATH_NUMBER_ERROR);
5454 }
5455 while ((CUR >= '0') && (CUR <= '9')) {
5456 ret = ret * 10 + (CUR - '0');
5457 ok = 1;
5458 NEXT;
5459 }
5460 if (CUR == '.') {
5461 NEXT;
5462 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5463 XP_ERROR(XPATH_NUMBER_ERROR);
5464 }
5465 while ((CUR >= '0') && (CUR <= '9')) {
5466 mult /= 10;
5467 ret = ret + (CUR - '0') * mult;
5468 NEXT;
5469 }
5470 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005471 if ((CUR == 'e') || (CUR == 'E')) {
5472 NEXT;
5473 if (CUR == '-') {
5474 is_exponent_negative = 1;
5475 NEXT;
5476 }
5477 while ((CUR >= '0') && (CUR <= '9')) {
5478 exponent = exponent * 10 + (CUR - '0');
5479 NEXT;
5480 }
5481 }
5482 if (is_exponent_negative)
5483 exponent = -exponent;
5484 ret *= pow(10.0, (double)exponent);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005485 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5486 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005487}
5488
5489/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005490 * xmlXPathParseLiteral:
5491 * @ctxt: the XPath Parser context
5492 *
5493 * Parse a Literal
5494 *
5495 * [29] Literal ::= '"' [^"]* '"'
5496 * | "'" [^']* "'"
5497 *
5498 * Returns the value found or NULL in case of error
5499 */
5500static xmlChar *
5501xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5502 const xmlChar *q;
5503 xmlChar *ret = NULL;
5504
5505 if (CUR == '"') {
5506 NEXT;
5507 q = CUR_PTR;
5508 while ((IS_CHAR(CUR)) && (CUR != '"'))
5509 NEXT;
5510 if (!IS_CHAR(CUR)) {
5511 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5512 } else {
5513 ret = xmlStrndup(q, CUR_PTR - q);
5514 NEXT;
5515 }
5516 } else if (CUR == '\'') {
5517 NEXT;
5518 q = CUR_PTR;
5519 while ((IS_CHAR(CUR)) && (CUR != '\''))
5520 NEXT;
5521 if (!IS_CHAR(CUR)) {
5522 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5523 } else {
5524 ret = xmlStrndup(q, CUR_PTR - q);
5525 NEXT;
5526 }
5527 } else {
5528 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5529 }
5530 return(ret);
5531}
5532
5533/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005534 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005535 * @ctxt: the XPath Parser context
5536 *
5537 * Parse a Literal and push it on the stack.
5538 *
5539 * [29] Literal ::= '"' [^"]* '"'
5540 * | "'" [^']* "'"
5541 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005542 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005543 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005544static void
5545xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005546 const xmlChar *q;
5547 xmlChar *ret = NULL;
5548
5549 if (CUR == '"') {
5550 NEXT;
5551 q = CUR_PTR;
5552 while ((IS_CHAR(CUR)) && (CUR != '"'))
5553 NEXT;
5554 if (!IS_CHAR(CUR)) {
5555 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5556 } else {
5557 ret = xmlStrndup(q, CUR_PTR - q);
5558 NEXT;
5559 }
5560 } else if (CUR == '\'') {
5561 NEXT;
5562 q = CUR_PTR;
5563 while ((IS_CHAR(CUR)) && (CUR != '\''))
5564 NEXT;
5565 if (!IS_CHAR(CUR)) {
5566 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5567 } else {
5568 ret = xmlStrndup(q, CUR_PTR - q);
5569 NEXT;
5570 }
5571 } else {
5572 XP_ERROR(XPATH_START_LITERAL_ERROR);
5573 }
5574 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005575 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5576 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005577 xmlFree(ret);
5578}
5579
5580/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005581 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005582 * @ctxt: the XPath Parser context
5583 *
5584 * Parse a VariableReference, evaluate it and push it on the stack.
5585 *
5586 * The variable bindings consist of a mapping from variable names
5587 * to variable values. The value of a variable is an object, which
5588 * of any of the types that are possible for the value of an expression,
5589 * and may also be of additional types not specified here.
5590 *
5591 * Early evaluation is possible since:
5592 * The variable bindings [...] used to evaluate a subexpression are
5593 * always the same as those used to evaluate the containing expression.
5594 *
5595 * [36] VariableReference ::= '$' QName
5596 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005597static void
5598xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005599 xmlChar *name;
5600 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005601
5602 SKIP_BLANKS;
5603 if (CUR != '$') {
5604 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5605 }
5606 NEXT;
5607 name = xmlXPathParseQName(ctxt, &prefix);
5608 if (name == NULL) {
5609 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5610 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005611 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005612 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5613 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005614 SKIP_BLANKS;
5615}
5616
5617/**
5618 * xmlXPathIsNodeType:
5619 * @ctxt: the XPath Parser context
5620 * @name: a name string
5621 *
5622 * Is the name given a NodeType one.
5623 *
5624 * [38] NodeType ::= 'comment'
5625 * | 'text'
5626 * | 'processing-instruction'
5627 * | 'node'
5628 *
5629 * Returns 1 if true 0 otherwise
5630 */
5631int
5632xmlXPathIsNodeType(const xmlChar *name) {
5633 if (name == NULL)
5634 return(0);
5635
5636 if (xmlStrEqual(name, BAD_CAST "comment"))
5637 return(1);
5638 if (xmlStrEqual(name, BAD_CAST "text"))
5639 return(1);
5640 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5641 return(1);
5642 if (xmlStrEqual(name, BAD_CAST "node"))
5643 return(1);
5644 return(0);
5645}
5646
5647/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005648 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005649 * @ctxt: the XPath Parser context
5650 *
5651 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5652 * [17] Argument ::= Expr
5653 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005654 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00005655 * pushed on the stack
5656 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005657static void
5658xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005659 xmlChar *name;
5660 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005661 int nbargs = 0;
5662
5663 name = xmlXPathParseQName(ctxt, &prefix);
5664 if (name == NULL) {
5665 XP_ERROR(XPATH_EXPR_ERROR);
5666 }
5667 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005668#ifdef DEBUG_EXPR
5669 if (prefix == NULL)
5670 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5671 name);
5672 else
5673 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5674 prefix, name);
5675#endif
5676
Owen Taylor3473f882001-02-23 17:55:21 +00005677 if (CUR != '(') {
5678 XP_ERROR(XPATH_EXPR_ERROR);
5679 }
5680 NEXT;
5681 SKIP_BLANKS;
5682
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005683 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005684 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005685 int op1 = ctxt->comp->last;
5686 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005687 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005688 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005689 nbargs++;
5690 if (CUR == ')') break;
5691 if (CUR != ',') {
5692 XP_ERROR(XPATH_EXPR_ERROR);
5693 }
5694 NEXT;
5695 SKIP_BLANKS;
5696 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005697 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
5698 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005699 NEXT;
5700 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005701}
5702
5703/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005704 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005705 * @ctxt: the XPath Parser context
5706 *
5707 * [15] PrimaryExpr ::= VariableReference
5708 * | '(' Expr ')'
5709 * | Literal
5710 * | Number
5711 * | FunctionCall
5712 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005713 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005714 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005715static void
5716xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005717 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005718 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005719 else if (CUR == '(') {
5720 NEXT;
5721 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005722 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005723 if (CUR != ')') {
5724 XP_ERROR(XPATH_EXPR_ERROR);
5725 }
5726 NEXT;
5727 SKIP_BLANKS;
5728 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005729 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005730 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005731 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005732 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005733 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005734 }
5735 SKIP_BLANKS;
5736}
5737
5738/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005739 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005740 * @ctxt: the XPath Parser context
5741 *
5742 * [20] FilterExpr ::= PrimaryExpr
5743 * | FilterExpr Predicate
5744 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005745 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005746 * Square brackets are used to filter expressions in the same way that
5747 * they are used in location paths. It is an error if the expression to
5748 * be filtered does not evaluate to a node-set. The context node list
5749 * used for evaluating the expression in square brackets is the node-set
5750 * to be filtered listed in document order.
5751 */
5752
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005753static void
5754xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
5755 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005756 CHECK_ERROR;
5757 SKIP_BLANKS;
5758
5759 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005760 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00005761 SKIP_BLANKS;
5762 }
5763
5764
5765}
5766
5767/**
5768 * xmlXPathScanName:
5769 * @ctxt: the XPath Parser context
5770 *
5771 * Trickery: parse an XML name but without consuming the input flow
5772 * Needed to avoid insanity in the parser state.
5773 *
5774 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5775 * CombiningChar | Extender
5776 *
5777 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5778 *
5779 * [6] Names ::= Name (S Name)*
5780 *
5781 * Returns the Name parsed or NULL
5782 */
5783
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005784static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005785xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
5786 xmlChar buf[XML_MAX_NAMELEN];
5787 int len = 0;
5788
5789 SKIP_BLANKS;
5790 if (!IS_LETTER(CUR) && (CUR != '_') &&
5791 (CUR != ':')) {
5792 return(NULL);
5793 }
5794
5795 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5796 (NXT(len) == '.') || (NXT(len) == '-') ||
5797 (NXT(len) == '_') || (NXT(len) == ':') ||
5798 (IS_COMBINING(NXT(len))) ||
5799 (IS_EXTENDER(NXT(len)))) {
5800 buf[len] = NXT(len);
5801 len++;
5802 if (len >= XML_MAX_NAMELEN) {
5803 xmlGenericError(xmlGenericErrorContext,
5804 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5805 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5806 (NXT(len) == '.') || (NXT(len) == '-') ||
5807 (NXT(len) == '_') || (NXT(len) == ':') ||
5808 (IS_COMBINING(NXT(len))) ||
5809 (IS_EXTENDER(NXT(len))))
5810 len++;
5811 break;
5812 }
5813 }
5814 return(xmlStrndup(buf, len));
5815}
5816
5817/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005818 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005819 * @ctxt: the XPath Parser context
5820 *
5821 * [19] PathExpr ::= LocationPath
5822 * | FilterExpr
5823 * | FilterExpr '/' RelativeLocationPath
5824 * | FilterExpr '//' RelativeLocationPath
5825 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005826 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005827 * The / operator and // operators combine an arbitrary expression
5828 * and a relative location path. It is an error if the expression
5829 * does not evaluate to a node-set.
5830 * The / operator does composition in the same way as when / is
5831 * used in a location path. As in location paths, // is short for
5832 * /descendant-or-self::node()/.
5833 */
5834
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005835static void
5836xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005837 int lc = 1; /* Should we branch to LocationPath ? */
5838 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5839
5840 SKIP_BLANKS;
5841 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5842 (CUR == '\'') || (CUR == '"')) {
5843 lc = 0;
5844 } else if (CUR == '*') {
5845 /* relative or absolute location path */
5846 lc = 1;
5847 } else if (CUR == '/') {
5848 /* relative or absolute location path */
5849 lc = 1;
5850 } else if (CUR == '@') {
5851 /* relative abbreviated attribute location path */
5852 lc = 1;
5853 } else if (CUR == '.') {
5854 /* relative abbreviated attribute location path */
5855 lc = 1;
5856 } else {
5857 /*
5858 * Problem is finding if we have a name here whether it's:
5859 * - a nodetype
5860 * - a function call in which case it's followed by '('
5861 * - an axis in which case it's followed by ':'
5862 * - a element name
5863 * We do an a priori analysis here rather than having to
5864 * maintain parsed token content through the recursive function
5865 * calls. This looks uglier but makes the code quite easier to
5866 * read/write/debug.
5867 */
5868 SKIP_BLANKS;
5869 name = xmlXPathScanName(ctxt);
5870 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
5871#ifdef DEBUG_STEP
5872 xmlGenericError(xmlGenericErrorContext,
5873 "PathExpr: Axis\n");
5874#endif
5875 lc = 1;
5876 xmlFree(name);
5877 } else if (name != NULL) {
5878 int len =xmlStrlen(name);
5879 int blank = 0;
5880
5881
5882 while (NXT(len) != 0) {
5883 if (NXT(len) == '/') {
5884 /* element name */
5885#ifdef DEBUG_STEP
5886 xmlGenericError(xmlGenericErrorContext,
5887 "PathExpr: AbbrRelLocation\n");
5888#endif
5889 lc = 1;
5890 break;
5891 } else if (IS_BLANK(NXT(len))) {
5892 /* skip to next */
5893 blank = 1;
5894 } else if (NXT(len) == ':') {
5895#ifdef DEBUG_STEP
5896 xmlGenericError(xmlGenericErrorContext,
5897 "PathExpr: AbbrRelLocation\n");
5898#endif
5899 lc = 1;
5900 break;
5901 } else if ((NXT(len) == '(')) {
5902 /* Note Type or Function */
5903 if (xmlXPathIsNodeType(name)) {
5904#ifdef DEBUG_STEP
5905 xmlGenericError(xmlGenericErrorContext,
5906 "PathExpr: Type search\n");
5907#endif
5908 lc = 1;
5909 } else {
5910#ifdef DEBUG_STEP
5911 xmlGenericError(xmlGenericErrorContext,
5912 "PathExpr: function call\n");
5913#endif
5914 lc = 0;
5915 }
5916 break;
5917 } else if ((NXT(len) == '[')) {
5918 /* element name */
5919#ifdef DEBUG_STEP
5920 xmlGenericError(xmlGenericErrorContext,
5921 "PathExpr: AbbrRelLocation\n");
5922#endif
5923 lc = 1;
5924 break;
5925 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5926 (NXT(len) == '=')) {
5927 lc = 1;
5928 break;
5929 } else {
5930 lc = 1;
5931 break;
5932 }
5933 len++;
5934 }
5935 if (NXT(len) == 0) {
5936#ifdef DEBUG_STEP
5937 xmlGenericError(xmlGenericErrorContext,
5938 "PathExpr: AbbrRelLocation\n");
5939#endif
5940 /* element name */
5941 lc = 1;
5942 }
5943 xmlFree(name);
5944 } else {
5945 /* make sure all cases are covered explicitely */
5946 XP_ERROR(XPATH_EXPR_ERROR);
5947 }
5948 }
5949
5950 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005951 if (CUR == '/') {
5952 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
5953 } else {
5954 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005955 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005956 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005957 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005958 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005959 CHECK_ERROR;
5960 if ((CUR == '/') && (NXT(1) == '/')) {
5961 SKIP(2);
5962 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005963
5964 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
5965 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5966 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
5967
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005968 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005969 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005970 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005971 }
5972 }
5973 SKIP_BLANKS;
5974}
5975
5976/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005977 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005978 * @ctxt: the XPath Parser context
5979 *
5980 * [18] UnionExpr ::= PathExpr
5981 * | UnionExpr '|' PathExpr
5982 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005983 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005984 */
5985
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005986static void
5987xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
5988 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005989 CHECK_ERROR;
5990 SKIP_BLANKS;
5991 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005992 int op1 = ctxt->comp->last;
5993 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005994
5995 NEXT;
5996 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005997 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005998
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005999 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6000
Owen Taylor3473f882001-02-23 17:55:21 +00006001 SKIP_BLANKS;
6002 }
Owen Taylor3473f882001-02-23 17:55:21 +00006003}
6004
6005/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006006 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006007 * @ctxt: the XPath Parser context
6008 *
6009 * [27] UnaryExpr ::= UnionExpr
6010 * | '-' UnaryExpr
6011 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006012 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006013 */
6014
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006015static void
6016xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006017 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006018 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006019
6020 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006021 while (CUR == '-') {
6022 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006023 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006024 NEXT;
6025 SKIP_BLANKS;
6026 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006027
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006028 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006029 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006030 if (found) {
6031 if (minus)
6032 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6033 else
6034 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006035 }
6036}
6037
6038/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006039 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006040 * @ctxt: the XPath Parser context
6041 *
6042 * [26] MultiplicativeExpr ::= UnaryExpr
6043 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6044 * | MultiplicativeExpr 'div' UnaryExpr
6045 * | MultiplicativeExpr 'mod' UnaryExpr
6046 * [34] MultiplyOperator ::= '*'
6047 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006048 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006049 */
6050
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006051static void
6052xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6053 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006054 CHECK_ERROR;
6055 SKIP_BLANKS;
6056 while ((CUR == '*') ||
6057 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6058 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6059 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006060 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006061
6062 if (CUR == '*') {
6063 op = 0;
6064 NEXT;
6065 } else if (CUR == 'd') {
6066 op = 1;
6067 SKIP(3);
6068 } else if (CUR == 'm') {
6069 op = 2;
6070 SKIP(3);
6071 }
6072 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006073 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006074 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006075 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006076 SKIP_BLANKS;
6077 }
6078}
6079
6080/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006081 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006082 * @ctxt: the XPath Parser context
6083 *
6084 * [25] AdditiveExpr ::= MultiplicativeExpr
6085 * | AdditiveExpr '+' MultiplicativeExpr
6086 * | AdditiveExpr '-' MultiplicativeExpr
6087 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006088 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006089 */
6090
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006091static void
6092xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006093
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006094 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006095 CHECK_ERROR;
6096 SKIP_BLANKS;
6097 while ((CUR == '+') || (CUR == '-')) {
6098 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006099 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006100
6101 if (CUR == '+') plus = 1;
6102 else plus = 0;
6103 NEXT;
6104 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006105 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006106 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006107 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006108 SKIP_BLANKS;
6109 }
6110}
6111
6112/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006113 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006114 * @ctxt: the XPath Parser context
6115 *
6116 * [24] RelationalExpr ::= AdditiveExpr
6117 * | RelationalExpr '<' AdditiveExpr
6118 * | RelationalExpr '>' AdditiveExpr
6119 * | RelationalExpr '<=' AdditiveExpr
6120 * | RelationalExpr '>=' AdditiveExpr
6121 *
6122 * A <= B > C is allowed ? Answer from James, yes with
6123 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6124 * which is basically what got implemented.
6125 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006126 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006127 * on the stack
6128 */
6129
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006130static void
6131xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6132 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006133 CHECK_ERROR;
6134 SKIP_BLANKS;
6135 while ((CUR == '<') ||
6136 (CUR == '>') ||
6137 ((CUR == '<') && (NXT(1) == '=')) ||
6138 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006139 int inf, strict;
6140 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006141
6142 if (CUR == '<') inf = 1;
6143 else inf = 0;
6144 if (NXT(1) == '=') strict = 0;
6145 else strict = 1;
6146 NEXT;
6147 if (!strict) NEXT;
6148 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006149 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006150 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006151 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006152 SKIP_BLANKS;
6153 }
6154}
6155
6156/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006157 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006158 * @ctxt: the XPath Parser context
6159 *
6160 * [23] EqualityExpr ::= RelationalExpr
6161 * | EqualityExpr '=' RelationalExpr
6162 * | EqualityExpr '!=' RelationalExpr
6163 *
6164 * A != B != C is allowed ? Answer from James, yes with
6165 * (RelationalExpr = RelationalExpr) = RelationalExpr
6166 * (RelationalExpr != RelationalExpr) != RelationalExpr
6167 * which is basically what got implemented.
6168 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006169 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006170 *
6171 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006172static void
6173xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6174 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006175 CHECK_ERROR;
6176 SKIP_BLANKS;
6177 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006178 int eq;
6179 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006180
6181 if (CUR == '=') eq = 1;
6182 else eq = 0;
6183 NEXT;
6184 if (!eq) NEXT;
6185 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006186 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006187 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006188 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006189 SKIP_BLANKS;
6190 }
6191}
6192
6193/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006194 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006195 * @ctxt: the XPath Parser context
6196 *
6197 * [22] AndExpr ::= EqualityExpr
6198 * | AndExpr 'and' EqualityExpr
6199 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006200 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006201 *
6202 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006203static void
6204xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6205 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006206 CHECK_ERROR;
6207 SKIP_BLANKS;
6208 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006209 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006210 SKIP(3);
6211 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006212 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006213 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006214 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006215 SKIP_BLANKS;
6216 }
6217}
6218
6219/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006220 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006221 * @ctxt: the XPath Parser context
6222 *
6223 * [14] Expr ::= OrExpr
6224 * [21] OrExpr ::= AndExpr
6225 * | OrExpr 'or' AndExpr
6226 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006227 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006228 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006229static void
6230xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6231 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006232 CHECK_ERROR;
6233 SKIP_BLANKS;
6234 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006235 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006236 SKIP(2);
6237 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006238 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006239 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006240 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6241 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006242 SKIP_BLANKS;
6243 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006244 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6245 /* more ops could be optimized too */
6246 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6247 }
Owen Taylor3473f882001-02-23 17:55:21 +00006248}
6249
6250/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006251 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006252 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006253 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006254 *
6255 * [8] Predicate ::= '[' PredicateExpr ']'
6256 * [9] PredicateExpr ::= Expr
6257 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006258 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006259 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006260static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006261xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006262 int op1 = ctxt->comp->last;
6263
6264 SKIP_BLANKS;
6265 if (CUR != '[') {
6266 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6267 }
6268 NEXT;
6269 SKIP_BLANKS;
6270
6271 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006272 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006273 CHECK_ERROR;
6274
6275 if (CUR != ']') {
6276 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6277 }
6278
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006279 if (filter)
6280 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6281 else
6282 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006283
6284 NEXT;
6285 SKIP_BLANKS;
6286}
6287
6288/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006289 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006290 * @ctxt: the XPath Parser context
6291 * @test: pointer to a xmlXPathTestVal
6292 * @type: pointer to a xmlXPathTypeVal
6293 * @prefix: placeholder for a possible name prefix
6294 *
6295 * [7] NodeTest ::= NameTest
6296 * | NodeType '(' ')'
6297 * | 'processing-instruction' '(' Literal ')'
6298 *
6299 * [37] NameTest ::= '*'
6300 * | NCName ':' '*'
6301 * | QName
6302 * [38] NodeType ::= 'comment'
6303 * | 'text'
6304 * | 'processing-instruction'
6305 * | 'node'
6306 *
6307 * Returns the name found and update @test, @type and @prefix appropriately
6308 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006309static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006310xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6311 xmlXPathTypeVal *type, const xmlChar **prefix,
6312 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006313 int blanks;
6314
6315 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6316 STRANGE;
6317 return(NULL);
6318 }
6319 *type = 0;
6320 *test = 0;
6321 *prefix = NULL;
6322 SKIP_BLANKS;
6323
6324 if ((name == NULL) && (CUR == '*')) {
6325 /*
6326 * All elements
6327 */
6328 NEXT;
6329 *test = NODE_TEST_ALL;
6330 return(NULL);
6331 }
6332
6333 if (name == NULL)
6334 name = xmlXPathParseNCName(ctxt);
6335 if (name == NULL) {
6336 XP_ERROR0(XPATH_EXPR_ERROR);
6337 }
6338
6339 blanks = IS_BLANK(CUR);
6340 SKIP_BLANKS;
6341 if (CUR == '(') {
6342 NEXT;
6343 /*
6344 * NodeType or PI search
6345 */
6346 if (xmlStrEqual(name, BAD_CAST "comment"))
6347 *type = NODE_TYPE_COMMENT;
6348 else if (xmlStrEqual(name, BAD_CAST "node"))
6349 *type = NODE_TYPE_NODE;
6350 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6351 *type = NODE_TYPE_PI;
6352 else if (xmlStrEqual(name, BAD_CAST "text"))
6353 *type = NODE_TYPE_TEXT;
6354 else {
6355 if (name != NULL)
6356 xmlFree(name);
6357 XP_ERROR0(XPATH_EXPR_ERROR);
6358 }
6359
6360 *test = NODE_TEST_TYPE;
6361
6362 SKIP_BLANKS;
6363 if (*type == NODE_TYPE_PI) {
6364 /*
6365 * Specific case: search a PI by name.
6366 */
Owen Taylor3473f882001-02-23 17:55:21 +00006367 if (name != NULL)
6368 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006369 name = NULL;
6370 if (CUR != ')') {
6371 name = xmlXPathParseLiteral(ctxt);
6372 CHECK_ERROR 0;
6373 SKIP_BLANKS;
6374 }
Owen Taylor3473f882001-02-23 17:55:21 +00006375 }
6376 if (CUR != ')') {
6377 if (name != NULL)
6378 xmlFree(name);
6379 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6380 }
6381 NEXT;
6382 return(name);
6383 }
6384 *test = NODE_TEST_NAME;
6385 if ((!blanks) && (CUR == ':')) {
6386 NEXT;
6387
6388 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006389 * Since currently the parser context don't have a
6390 * namespace list associated:
6391 * The namespace name for this prefix can be computed
6392 * only at evaluation time. The compilation is done
6393 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006394 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006395#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006396 *prefix = xmlXPathNsLookup(ctxt->context, name);
6397 if (name != NULL)
6398 xmlFree(name);
6399 if (*prefix == NULL) {
6400 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6401 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006402#else
6403 *prefix = name;
6404#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006405
6406 if (CUR == '*') {
6407 /*
6408 * All elements
6409 */
6410 NEXT;
6411 *test = NODE_TEST_ALL;
6412 return(NULL);
6413 }
6414
6415 name = xmlXPathParseNCName(ctxt);
6416 if (name == NULL) {
6417 XP_ERROR0(XPATH_EXPR_ERROR);
6418 }
6419 }
6420 return(name);
6421}
6422
6423/**
6424 * xmlXPathIsAxisName:
6425 * @name: a preparsed name token
6426 *
6427 * [6] AxisName ::= 'ancestor'
6428 * | 'ancestor-or-self'
6429 * | 'attribute'
6430 * | 'child'
6431 * | 'descendant'
6432 * | 'descendant-or-self'
6433 * | 'following'
6434 * | 'following-sibling'
6435 * | 'namespace'
6436 * | 'parent'
6437 * | 'preceding'
6438 * | 'preceding-sibling'
6439 * | 'self'
6440 *
6441 * Returns the axis or 0
6442 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006443static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006444xmlXPathIsAxisName(const xmlChar *name) {
6445 xmlXPathAxisVal ret = 0;
6446 switch (name[0]) {
6447 case 'a':
6448 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6449 ret = AXIS_ANCESTOR;
6450 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6451 ret = AXIS_ANCESTOR_OR_SELF;
6452 if (xmlStrEqual(name, BAD_CAST "attribute"))
6453 ret = AXIS_ATTRIBUTE;
6454 break;
6455 case 'c':
6456 if (xmlStrEqual(name, BAD_CAST "child"))
6457 ret = AXIS_CHILD;
6458 break;
6459 case 'd':
6460 if (xmlStrEqual(name, BAD_CAST "descendant"))
6461 ret = AXIS_DESCENDANT;
6462 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6463 ret = AXIS_DESCENDANT_OR_SELF;
6464 break;
6465 case 'f':
6466 if (xmlStrEqual(name, BAD_CAST "following"))
6467 ret = AXIS_FOLLOWING;
6468 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6469 ret = AXIS_FOLLOWING_SIBLING;
6470 break;
6471 case 'n':
6472 if (xmlStrEqual(name, BAD_CAST "namespace"))
6473 ret = AXIS_NAMESPACE;
6474 break;
6475 case 'p':
6476 if (xmlStrEqual(name, BAD_CAST "parent"))
6477 ret = AXIS_PARENT;
6478 if (xmlStrEqual(name, BAD_CAST "preceding"))
6479 ret = AXIS_PRECEDING;
6480 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6481 ret = AXIS_PRECEDING_SIBLING;
6482 break;
6483 case 's':
6484 if (xmlStrEqual(name, BAD_CAST "self"))
6485 ret = AXIS_SELF;
6486 break;
6487 }
6488 return(ret);
6489}
6490
6491/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006492 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006493 * @ctxt: the XPath Parser context
6494 *
6495 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6496 * | AbbreviatedStep
6497 *
6498 * [12] AbbreviatedStep ::= '.' | '..'
6499 *
6500 * [5] AxisSpecifier ::= AxisName '::'
6501 * | AbbreviatedAxisSpecifier
6502 *
6503 * [13] AbbreviatedAxisSpecifier ::= '@'?
6504 *
6505 * Modified for XPtr range support as:
6506 *
6507 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6508 * | AbbreviatedStep
6509 * | 'range-to' '(' Expr ')' Predicate*
6510 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006511 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006512 * A location step of . is short for self::node(). This is
6513 * particularly useful in conjunction with //. For example, the
6514 * location path .//para is short for
6515 * self::node()/descendant-or-self::node()/child::para
6516 * and so will select all para descendant elements of the context
6517 * node.
6518 * Similarly, a location step of .. is short for parent::node().
6519 * For example, ../title is short for parent::node()/child::title
6520 * and so will select the title children of the parent of the context
6521 * node.
6522 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006523static void
6524xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006525#ifdef LIBXML_XPTR_ENABLED
6526 int rangeto = 0;
6527 int op2 = -1;
6528#endif
6529
Owen Taylor3473f882001-02-23 17:55:21 +00006530 SKIP_BLANKS;
6531 if ((CUR == '.') && (NXT(1) == '.')) {
6532 SKIP(2);
6533 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006534 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6535 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006536 } else if (CUR == '.') {
6537 NEXT;
6538 SKIP_BLANKS;
6539 } else {
6540 xmlChar *name = NULL;
6541 const xmlChar *prefix = NULL;
6542 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006543 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006544 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006545 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006546
6547 /*
6548 * The modification needed for XPointer change to the production
6549 */
6550#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006551 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006552 name = xmlXPathParseNCName(ctxt);
6553 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006554 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006555 xmlFree(name);
6556 SKIP_BLANKS;
6557 if (CUR != '(') {
6558 XP_ERROR(XPATH_EXPR_ERROR);
6559 }
6560 NEXT;
6561 SKIP_BLANKS;
6562
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006563 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006564 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006565 CHECK_ERROR;
6566
6567 SKIP_BLANKS;
6568 if (CUR != ')') {
6569 XP_ERROR(XPATH_EXPR_ERROR);
6570 }
6571 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006572 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006573 goto eval_predicates;
6574 }
6575 }
6576#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006577 if (CUR == '*') {
6578 axis = AXIS_CHILD;
6579 } else {
6580 if (name == NULL)
6581 name = xmlXPathParseNCName(ctxt);
6582 if (name != NULL) {
6583 axis = xmlXPathIsAxisName(name);
6584 if (axis != 0) {
6585 SKIP_BLANKS;
6586 if ((CUR == ':') && (NXT(1) == ':')) {
6587 SKIP(2);
6588 xmlFree(name);
6589 name = NULL;
6590 } else {
6591 /* an element name can conflict with an axis one :-\ */
6592 axis = AXIS_CHILD;
6593 }
Owen Taylor3473f882001-02-23 17:55:21 +00006594 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00006595 axis = AXIS_CHILD;
6596 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006597 } else if (CUR == '@') {
6598 NEXT;
6599 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00006600 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00006601 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00006602 }
Owen Taylor3473f882001-02-23 17:55:21 +00006603 }
6604
6605 CHECK_ERROR;
6606
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006607 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006608 if (test == 0)
6609 return;
6610
6611#ifdef DEBUG_STEP
6612 xmlGenericError(xmlGenericErrorContext,
6613 "Basis : computing new set\n");
6614#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006615
Owen Taylor3473f882001-02-23 17:55:21 +00006616#ifdef DEBUG_STEP
6617 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006618 if (ctxt->value == NULL)
6619 xmlGenericError(xmlGenericErrorContext, "no value\n");
6620 else if (ctxt->value->nodesetval == NULL)
6621 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6622 else
6623 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006624#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006625
6626eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006627 op1 = ctxt->comp->last;
6628 ctxt->comp->last = -1;
6629
Owen Taylor3473f882001-02-23 17:55:21 +00006630 SKIP_BLANKS;
6631 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006632 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006633 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006634
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006635#ifdef LIBXML_XPTR_ENABLED
6636 if (rangeto) {
6637 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
6638 } else
6639#endif
6640 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
6641 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006642
Owen Taylor3473f882001-02-23 17:55:21 +00006643 }
6644#ifdef DEBUG_STEP
6645 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006646 if (ctxt->value == NULL)
6647 xmlGenericError(xmlGenericErrorContext, "no value\n");
6648 else if (ctxt->value->nodesetval == NULL)
6649 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6650 else
6651 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6652 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006653#endif
6654}
6655
6656/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006657 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006658 * @ctxt: the XPath Parser context
6659 *
6660 * [3] RelativeLocationPath ::= Step
6661 * | RelativeLocationPath '/' Step
6662 * | AbbreviatedRelativeLocationPath
6663 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6664 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006665 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00006666 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006667static void
Owen Taylor3473f882001-02-23 17:55:21 +00006668#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006669xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006670#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006671xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006672#endif
6673(xmlXPathParserContextPtr ctxt) {
6674 SKIP_BLANKS;
6675 if ((CUR == '/') && (NXT(1) == '/')) {
6676 SKIP(2);
6677 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006678 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6679 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006680 } else if (CUR == '/') {
6681 NEXT;
6682 SKIP_BLANKS;
6683 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006684 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006685 SKIP_BLANKS;
6686 while (CUR == '/') {
6687 if ((CUR == '/') && (NXT(1) == '/')) {
6688 SKIP(2);
6689 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006690 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00006691 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006692 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006693 } else if (CUR == '/') {
6694 NEXT;
6695 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006696 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006697 }
6698 SKIP_BLANKS;
6699 }
6700}
6701
6702/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006703 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006704 * @ctxt: the XPath Parser context
6705 *
6706 * [1] LocationPath ::= RelativeLocationPath
6707 * | AbsoluteLocationPath
6708 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6709 * | AbbreviatedAbsoluteLocationPath
6710 * [10] AbbreviatedAbsoluteLocationPath ::=
6711 * '//' RelativeLocationPath
6712 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006713 * Compile a location path
6714 *
Owen Taylor3473f882001-02-23 17:55:21 +00006715 * // is short for /descendant-or-self::node()/. For example,
6716 * //para is short for /descendant-or-self::node()/child::para and
6717 * so will select any para element in the document (even a para element
6718 * that is a document element will be selected by //para since the
6719 * document element node is a child of the root node); div//para is
6720 * short for div/descendant-or-self::node()/child::para and so will
6721 * select all para descendants of div children.
6722 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006723static void
6724xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006725 SKIP_BLANKS;
6726 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006727 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006728 } else {
6729 while (CUR == '/') {
6730 if ((CUR == '/') && (NXT(1) == '/')) {
6731 SKIP(2);
6732 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006733 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6734 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006735 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006736 } else if (CUR == '/') {
6737 NEXT;
6738 SKIP_BLANKS;
6739 if (CUR != 0)
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006740 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006741 }
6742 }
6743 }
6744}
6745
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006746/************************************************************************
6747 * *
6748 * XPath precompiled expression evaluation *
6749 * *
6750 ************************************************************************/
6751
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006752static void
6753xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
6754
6755/**
6756 * xmlXPathNodeCollectAndTest:
6757 * @ctxt: the XPath Parser context
6758 * @op: the XPath precompiled step operation
6759 *
6760 * This is the function implementing a step: based on the current list
6761 * of nodes, it builds up a new list, looking at all nodes under that
6762 * axis and selecting them it also do the predicate filtering
6763 *
6764 * Pushes the new NodeSet resulting from the search.
6765 */
6766static void
6767xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
6768 xmlXPathStepOpPtr op) {
6769 xmlXPathAxisVal axis = op->value;
6770 xmlXPathTestVal test = op->value2;
6771 xmlXPathTypeVal type = op->value3;
6772 const xmlChar *prefix = op->value4;
6773 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006774 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006775
6776#ifdef DEBUG_STEP
6777 int n = 0, t = 0;
6778#endif
6779 int i;
6780 xmlNodeSetPtr ret, list;
6781 xmlXPathTraversalFunction next = NULL;
6782 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
6783 xmlNodePtr cur = NULL;
6784 xmlXPathObjectPtr obj;
6785 xmlNodeSetPtr nodelist;
6786 xmlNodePtr tmp;
6787
6788 CHECK_TYPE(XPATH_NODESET);
6789 obj = valuePop(ctxt);
6790 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006791 if (prefix != NULL) {
6792 URI = xmlXPathNsLookup(ctxt->context, prefix);
6793 if (URI == NULL)
6794 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
6795 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006796
6797#ifdef DEBUG_STEP
6798 xmlGenericError(xmlGenericErrorContext,
6799 "new step : ");
6800#endif
6801 switch (axis) {
6802 case AXIS_ANCESTOR:
6803#ifdef DEBUG_STEP
6804 xmlGenericError(xmlGenericErrorContext,
6805 "axis 'ancestors' ");
6806#endif
6807 next = xmlXPathNextAncestor; break;
6808 case AXIS_ANCESTOR_OR_SELF:
6809#ifdef DEBUG_STEP
6810 xmlGenericError(xmlGenericErrorContext,
6811 "axis 'ancestors-or-self' ");
6812#endif
6813 next = xmlXPathNextAncestorOrSelf; break;
6814 case AXIS_ATTRIBUTE:
6815#ifdef DEBUG_STEP
6816 xmlGenericError(xmlGenericErrorContext,
6817 "axis 'attributes' ");
6818#endif
6819 next = xmlXPathNextAttribute; break;
6820 break;
6821 case AXIS_CHILD:
6822#ifdef DEBUG_STEP
6823 xmlGenericError(xmlGenericErrorContext,
6824 "axis 'child' ");
6825#endif
6826 next = xmlXPathNextChild; break;
6827 case AXIS_DESCENDANT:
6828#ifdef DEBUG_STEP
6829 xmlGenericError(xmlGenericErrorContext,
6830 "axis 'descendant' ");
6831#endif
6832 next = xmlXPathNextDescendant; break;
6833 case AXIS_DESCENDANT_OR_SELF:
6834#ifdef DEBUG_STEP
6835 xmlGenericError(xmlGenericErrorContext,
6836 "axis 'descendant-or-self' ");
6837#endif
6838 next = xmlXPathNextDescendantOrSelf; break;
6839 case AXIS_FOLLOWING:
6840#ifdef DEBUG_STEP
6841 xmlGenericError(xmlGenericErrorContext,
6842 "axis 'following' ");
6843#endif
6844 next = xmlXPathNextFollowing; break;
6845 case AXIS_FOLLOWING_SIBLING:
6846#ifdef DEBUG_STEP
6847 xmlGenericError(xmlGenericErrorContext,
6848 "axis 'following-siblings' ");
6849#endif
6850 next = xmlXPathNextFollowingSibling; break;
6851 case AXIS_NAMESPACE:
6852#ifdef DEBUG_STEP
6853 xmlGenericError(xmlGenericErrorContext,
6854 "axis 'namespace' ");
6855#endif
6856 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
6857 break;
6858 case AXIS_PARENT:
6859#ifdef DEBUG_STEP
6860 xmlGenericError(xmlGenericErrorContext,
6861 "axis 'parent' ");
6862#endif
6863 next = xmlXPathNextParent; break;
6864 case AXIS_PRECEDING:
6865#ifdef DEBUG_STEP
6866 xmlGenericError(xmlGenericErrorContext,
6867 "axis 'preceding' ");
6868#endif
6869 next = xmlXPathNextPreceding; break;
6870 case AXIS_PRECEDING_SIBLING:
6871#ifdef DEBUG_STEP
6872 xmlGenericError(xmlGenericErrorContext,
6873 "axis 'preceding-sibling' ");
6874#endif
6875 next = xmlXPathNextPrecedingSibling; break;
6876 case AXIS_SELF:
6877#ifdef DEBUG_STEP
6878 xmlGenericError(xmlGenericErrorContext,
6879 "axis 'self' ");
6880#endif
6881 next = xmlXPathNextSelf; break;
6882 }
6883 if (next == NULL)
6884 return;
6885
6886 nodelist = obj->nodesetval;
6887 if (nodelist == NULL) {
6888 xmlXPathFreeObject(obj);
6889 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
6890 return;
6891 }
6892 addNode = xmlXPathNodeSetAddUnique;
6893 ret = NULL;
6894#ifdef DEBUG_STEP
6895 xmlGenericError(xmlGenericErrorContext,
6896 " context contains %d nodes\n",
6897 nodelist->nodeNr);
6898 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006899 case NODE_TEST_NONE:
6900 xmlGenericError(xmlGenericErrorContext,
6901 " searching for none !!!\n");
6902 break;
6903 case NODE_TEST_TYPE:
6904 xmlGenericError(xmlGenericErrorContext,
6905 " searching for type %d\n", type);
6906 break;
6907 case NODE_TEST_PI:
6908 xmlGenericError(xmlGenericErrorContext,
6909 " searching for PI !!!\n");
6910 break;
6911 case NODE_TEST_ALL:
6912 xmlGenericError(xmlGenericErrorContext,
6913 " searching for *\n");
6914 break;
6915 case NODE_TEST_NS:
6916 xmlGenericError(xmlGenericErrorContext,
6917 " searching for namespace %s\n",
6918 prefix);
6919 break;
6920 case NODE_TEST_NAME:
6921 xmlGenericError(xmlGenericErrorContext,
6922 " searching for name %s\n", name);
6923 if (prefix != NULL)
6924 xmlGenericError(xmlGenericErrorContext,
6925 " with namespace %s\n",
6926 prefix);
6927 break;
6928 }
6929 xmlGenericError(xmlGenericErrorContext, "Testing : ");
6930#endif
6931 /*
6932 * 2.3 Node Tests
6933 * - For the attribute axis, the principal node type is attribute.
6934 * - For the namespace axis, the principal node type is namespace.
6935 * - For other axes, the principal node type is element.
6936 *
6937 * A node test * is true for any node of the
6938 * principal node type. For example, child::* willi
6939 * select all element children of the context node
6940 */
6941 tmp = ctxt->context->node;
6942 for (i = 0;i < nodelist->nodeNr; i++) {
6943 ctxt->context->node = nodelist->nodeTab[i];
6944
6945 cur = NULL;
6946 list = xmlXPathNodeSetCreate(NULL);
6947 do {
6948 cur = next(ctxt, cur);
6949 if (cur == NULL) break;
6950#ifdef DEBUG_STEP
6951 t++;
6952 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
6953#endif
6954 switch (test) {
6955 case NODE_TEST_NONE:
6956 ctxt->context->node = tmp;
6957 STRANGE
6958 return;
6959 case NODE_TEST_TYPE:
6960 if ((cur->type == type) ||
6961 ((type == NODE_TYPE_NODE) &&
6962 ((cur->type == XML_DOCUMENT_NODE) ||
6963 (cur->type == XML_HTML_DOCUMENT_NODE) ||
6964 (cur->type == XML_ELEMENT_NODE) ||
6965 (cur->type == XML_PI_NODE) ||
6966 (cur->type == XML_COMMENT_NODE) ||
6967 (cur->type == XML_CDATA_SECTION_NODE) ||
6968 (cur->type == XML_TEXT_NODE)))) {
6969#ifdef DEBUG_STEP
6970 n++;
6971#endif
6972 addNode(list, cur);
6973 }
6974 break;
6975 case NODE_TEST_PI:
6976 if (cur->type == XML_PI_NODE) {
6977 if ((name != NULL) &&
6978 (!xmlStrEqual(name, cur->name)))
6979 break;
6980#ifdef DEBUG_STEP
6981 n++;
6982#endif
6983 addNode(list, cur);
6984 }
6985 break;
6986 case NODE_TEST_ALL:
6987 if (axis == AXIS_ATTRIBUTE) {
6988 if (cur->type == XML_ATTRIBUTE_NODE) {
6989#ifdef DEBUG_STEP
6990 n++;
6991#endif
6992 addNode(list, cur);
6993 }
6994 } else if (axis == AXIS_NAMESPACE) {
6995 if (cur->type == XML_NAMESPACE_DECL) {
6996#ifdef DEBUG_STEP
6997 n++;
6998#endif
6999 addNode(list, cur);
7000 }
7001 } else {
7002 if ((cur->type == XML_ELEMENT_NODE) ||
7003 (cur->type == XML_DOCUMENT_NODE) ||
7004 (cur->type == XML_HTML_DOCUMENT_NODE)) {
7005 if (prefix == NULL) {
7006#ifdef DEBUG_STEP
7007 n++;
7008#endif
7009 addNode(list, cur);
7010 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007011 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007012 cur->ns->href))) {
7013#ifdef DEBUG_STEP
7014 n++;
7015#endif
7016 addNode(list, cur);
7017 }
7018 }
7019 }
7020 break;
7021 case NODE_TEST_NS: {
7022 TODO;
7023 break;
7024 }
7025 case NODE_TEST_NAME:
7026 switch (cur->type) {
7027 case XML_ELEMENT_NODE:
7028 if (xmlStrEqual(name, cur->name)) {
7029 if (prefix == NULL) {
7030 if ((cur->ns == NULL) ||
7031 (cur->ns->prefix == NULL)) {
7032#ifdef DEBUG_STEP
7033 n++;
7034#endif
7035 addNode(list, cur);
7036 }
7037 } else {
7038 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007039 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007040 cur->ns->href))) {
7041#ifdef DEBUG_STEP
7042 n++;
7043#endif
7044 addNode(list, cur);
7045 }
7046 }
7047 }
7048 break;
7049 case XML_ATTRIBUTE_NODE: {
7050 xmlAttrPtr attr = (xmlAttrPtr) cur;
7051 if (xmlStrEqual(name, attr->name)) {
7052 if (prefix == NULL) {
7053 if ((attr->ns == NULL) ||
7054 (attr->ns->prefix == NULL)) {
7055#ifdef DEBUG_STEP
7056 n++;
7057#endif
7058 addNode(list, (xmlNodePtr) attr);
7059 }
7060 } else {
7061 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007062 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007063 attr->ns->href))) {
7064#ifdef DEBUG_STEP
7065 n++;
7066#endif
7067 addNode(list, (xmlNodePtr) attr);
7068 }
7069 }
7070 }
7071 break;
7072 }
7073 case XML_NAMESPACE_DECL: {
7074 TODO;
7075 break;
7076 }
7077 default:
7078 break;
7079 }
7080 break;
7081 }
7082 } while (cur != NULL);
7083
7084 /*
7085 * If there is some predicate filtering do it now
7086 */
7087 if (op->ch2 != -1) {
7088 xmlXPathObjectPtr obj2;
7089
7090 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7091 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7092 CHECK_TYPE(XPATH_NODESET);
7093 obj2 = valuePop(ctxt);
7094 list = obj2->nodesetval;
7095 obj2->nodesetval = NULL;
7096 xmlXPathFreeObject(obj2);
7097 }
7098 if (ret == NULL) {
7099 ret = list;
7100 } else {
7101 ret = xmlXPathNodeSetMerge(ret, list);
7102 xmlXPathFreeNodeSet(list);
7103 }
7104 }
7105 ctxt->context->node = tmp;
7106#ifdef DEBUG_STEP
7107 xmlGenericError(xmlGenericErrorContext,
7108 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7109#endif
7110 xmlXPathFreeObject(obj);
7111 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7112}
7113
Owen Taylor3473f882001-02-23 17:55:21 +00007114/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007115 * xmlXPathCompOpEval:
7116 * @ctxt: the XPath parser context with the compiled expression
7117 * @op: an XPath compiled operation
7118 *
7119 * Evaluate the Precompiled XPath operation
7120 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007121static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007122xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7123 int equal, ret;
7124 xmlXPathCompExprPtr comp;
7125 xmlXPathObjectPtr arg1, arg2;
7126
7127 comp = ctxt->comp;
7128 switch (op->op) {
7129 case XPATH_OP_END:
7130 return;
7131 case XPATH_OP_AND:
7132 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7133 xmlXPathBooleanFunction(ctxt, 1);
7134 if (ctxt->value->boolval == 0)
7135 return;
7136 arg2 = valuePop(ctxt);
7137 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7138 xmlXPathBooleanFunction(ctxt, 1);
7139 arg1 = valuePop(ctxt);
7140 arg1->boolval &= arg2->boolval;
7141 valuePush(ctxt, arg1);
7142 xmlXPathFreeObject(arg2);
7143 return;
7144 case XPATH_OP_OR:
7145 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7146 xmlXPathBooleanFunction(ctxt, 1);
7147 if (ctxt->value->boolval == 1)
7148 return;
7149 arg2 = valuePop(ctxt);
7150 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7151 xmlXPathBooleanFunction(ctxt, 1);
7152 arg1 = valuePop(ctxt);
7153 arg1->boolval |= arg2->boolval;
7154 valuePush(ctxt, arg1);
7155 xmlXPathFreeObject(arg2);
7156 return;
7157 case XPATH_OP_EQUAL:
7158 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7159 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7160 equal = xmlXPathEqualValues(ctxt);
7161 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7162 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7163 return;
7164 case XPATH_OP_CMP:
7165 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7166 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7167 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7168 valuePush(ctxt, xmlXPathNewBoolean(ret));
7169 return;
7170 case XPATH_OP_PLUS:
7171 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7172 if (op->ch2 != -1)
7173 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7174 if (op->value == 0) xmlXPathSubValues(ctxt);
7175 else if (op->value == 1) xmlXPathAddValues(ctxt);
7176 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7177 else if (op->value == 3) {
7178 xmlXPathObjectPtr arg;
7179
7180 POP_FLOAT
7181 valuePush(ctxt, arg);
7182 }
7183 return;
7184 case XPATH_OP_MULT:
7185 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7186 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7187 if (op->value == 0) xmlXPathMultValues(ctxt);
7188 else if (op->value == 1) xmlXPathDivValues(ctxt);
7189 else if (op->value == 2) xmlXPathModValues(ctxt);
7190 return;
7191 case XPATH_OP_UNION:
7192 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7193 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7194 CHECK_TYPE(XPATH_NODESET);
7195 arg2 = valuePop(ctxt);
7196
7197 CHECK_TYPE(XPATH_NODESET);
7198 arg1 = valuePop(ctxt);
7199
7200 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7201 arg2->nodesetval);
7202 valuePush(ctxt, arg1);
7203 xmlXPathFreeObject(arg2);
7204 return;
7205 case XPATH_OP_ROOT:
7206 xmlXPathRoot(ctxt);
7207 return;
7208 case XPATH_OP_NODE:
7209 if (op->ch1 != -1)
7210 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7211 if (op->ch2 != -1)
7212 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7213 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7214 return;
7215 case XPATH_OP_RESET:
7216 if (op->ch1 != -1)
7217 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7218 if (op->ch2 != -1)
7219 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7220 ctxt->context->node = NULL;
7221 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007222 case XPATH_OP_COLLECT: {
7223 if (op->ch1 == -1)
7224 return;
7225
7226 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7227 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007228 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007229 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007230 case XPATH_OP_VALUE:
7231 valuePush(ctxt,
7232 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7233 return;
7234 case XPATH_OP_VARIABLE: {
7235 if (op->ch1 != -1)
7236 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7237 if (op->value5 == NULL)
7238 valuePush(ctxt,
7239 xmlXPathVariableLookup(ctxt->context, op->value4));
7240 else {
7241 const xmlChar *URI;
7242 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7243 if (URI == NULL) {
7244 xmlGenericError(xmlGenericErrorContext,
7245 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7246 op->value4, op->value5);
7247 return;
7248 }
7249 valuePush(ctxt,
7250 xmlXPathVariableLookupNS(ctxt->context,
7251 op->value4, URI));
7252 }
7253 return;
7254 }
7255 case XPATH_OP_FUNCTION: {
7256 xmlXPathFunction func;
7257
7258 if (op->ch1 != -1)
7259 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007260 if (op->cache != NULL)
7261 func = (xmlXPathFunction) op->cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007262 else {
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007263 if (op->value5 == NULL)
7264 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7265 else {
7266 const xmlChar *URI;
7267 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7268 if (URI == NULL) {
7269 xmlGenericError(xmlGenericErrorContext,
7270 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7271 op->value4, op->value5);
7272 return;
7273 }
7274 func = xmlXPathFunctionLookupNS(ctxt->context,
7275 op->value4, URI);
7276 }
7277 if (func == NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007278 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007279 "xmlXPathRunEval: function %s not found\n",
7280 op->value4);
7281 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007282 return;
7283 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007284 op->cache = (void *) func;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007285 }
7286 func(ctxt, op->value);
7287 return;
7288 }
7289 case XPATH_OP_ARG:
7290 if (op->ch1 != -1)
7291 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7292 if (op->ch2 != -1)
7293 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7294 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007295 case XPATH_OP_PREDICATE:
7296 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007297 xmlXPathObjectPtr res;
7298 xmlXPathObjectPtr obj, tmp;
7299 xmlNodeSetPtr newset = NULL;
7300 xmlNodeSetPtr oldset;
7301 xmlNodePtr oldnode;
7302 int i;
7303
7304 if (op->ch1 != -1)
7305 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7306 if (op->ch2 == -1)
7307 return;
7308
7309 oldnode = ctxt->context->node;
7310
7311#ifdef LIBXML_XPTR_ENABLED
7312 /*
7313 * Hum are we filtering the result of an XPointer expression
7314 */
7315 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007316 xmlLocationSetPtr newlocset = NULL;
7317 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007318
7319 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007320 * Extract the old locset, and then evaluate the result of the
7321 * expression for all the element in the locset. use it to grow
7322 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007323 */
7324 CHECK_TYPE(XPATH_LOCATIONSET);
7325 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007326 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007327 ctxt->context->node = NULL;
7328
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007329 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007330 ctxt->context->contextSize = 0;
7331 ctxt->context->proximityPosition = 0;
7332 if (op->ch2 != -1)
7333 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7334 res = valuePop(ctxt);
7335 if (res != NULL)
7336 xmlXPathFreeObject(res);
7337 valuePush(ctxt, obj);
7338 CHECK_ERROR;
7339 return;
7340 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007341 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007342
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007343 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007344 /*
7345 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007346 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007347 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007348 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007349 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7350 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007351 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007352 ctxt->context->proximityPosition = i + 1;
7353
7354 if (op->ch2 != -1)
7355 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7356 CHECK_ERROR;
7357
7358 /*
7359 * The result of the evaluation need to be tested to
7360 * decided whether the filter succeeded or not
7361 */
7362 res = valuePop(ctxt);
7363 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007364 xmlXPtrLocationSetAdd(newlocset,
7365 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007366 }
7367
7368 /*
7369 * Cleanup
7370 */
7371 if (res != NULL)
7372 xmlXPathFreeObject(res);
7373 if (ctxt->value == tmp) {
7374 res = valuePop(ctxt);
7375 xmlXPathFreeObject(res);
7376 }
7377
7378 ctxt->context->node = NULL;
7379 }
7380
7381 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007382 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007383 */
7384 xmlXPathFreeObject(obj);
7385 ctxt->context->node = NULL;
7386 ctxt->context->contextSize = -1;
7387 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007388 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007389 ctxt->context->node = oldnode;
7390 return;
7391 }
7392#endif /* LIBXML_XPTR_ENABLED */
7393
7394 /*
7395 * Extract the old set, and then evaluate the result of the
7396 * expression for all the element in the set. use it to grow
7397 * up a new set.
7398 */
7399 CHECK_TYPE(XPATH_NODESET);
7400 obj = valuePop(ctxt);
7401 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007402
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007403 oldnode = ctxt->context->node;
7404 ctxt->context->node = NULL;
7405
7406 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7407 ctxt->context->contextSize = 0;
7408 ctxt->context->proximityPosition = 0;
7409 if (op->ch2 != -1)
7410 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7411 res = valuePop(ctxt);
7412 if (res != NULL)
7413 xmlXPathFreeObject(res);
7414 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007415 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007416 CHECK_ERROR;
7417 } else {
7418 /*
7419 * Initialize the new set.
7420 */
7421 newset = xmlXPathNodeSetCreate(NULL);
7422
7423 for (i = 0; i < oldset->nodeNr; i++) {
7424 /*
7425 * Run the evaluation with a node list made of
7426 * a single item in the nodeset.
7427 */
7428 ctxt->context->node = oldset->nodeTab[i];
7429 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7430 valuePush(ctxt, tmp);
7431 ctxt->context->contextSize = oldset->nodeNr;
7432 ctxt->context->proximityPosition = i + 1;
7433
7434 if (op->ch2 != -1)
7435 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7436 CHECK_ERROR;
7437
7438 /*
7439 * The result of the evaluation need to be tested to
7440 * decided whether the filter succeeded or not
7441 */
7442 res = valuePop(ctxt);
7443 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7444 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7445 }
7446
7447 /*
7448 * Cleanup
7449 */
7450 if (res != NULL)
7451 xmlXPathFreeObject(res);
7452 if (ctxt->value == tmp) {
7453 res = valuePop(ctxt);
7454 xmlXPathFreeObject(res);
7455 }
7456
7457 ctxt->context->node = NULL;
7458 }
7459
7460 /*
7461 * The result is used as the new evaluation set.
7462 */
7463 xmlXPathFreeObject(obj);
7464 ctxt->context->node = NULL;
7465 ctxt->context->contextSize = -1;
7466 ctxt->context->proximityPosition = -1;
7467 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7468 }
7469 ctxt->context->node = oldnode;
7470 return;
7471 }
7472 case XPATH_OP_SORT:
7473 if (op->ch1 != -1)
7474 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7475 if ((ctxt->value != NULL) &&
7476 (ctxt->value->type == XPATH_NODESET) &&
7477 (ctxt->value->nodesetval != NULL))
7478 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7479 return;
7480#ifdef LIBXML_XPTR_ENABLED
7481 case XPATH_OP_RANGETO: {
7482 xmlXPathObjectPtr range;
7483 xmlXPathObjectPtr res, obj;
7484 xmlXPathObjectPtr tmp;
7485 xmlLocationSetPtr newset = NULL;
7486 xmlNodeSetPtr oldset;
7487 int i;
7488
7489 if (op->ch1 != -1)
7490 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7491 if (op->ch2 == -1)
7492 return;
7493
7494 CHECK_TYPE(XPATH_NODESET);
7495 obj = valuePop(ctxt);
7496 oldset = obj->nodesetval;
7497 ctxt->context->node = NULL;
7498
7499 newset = xmlXPtrLocationSetCreate(NULL);
7500
Daniel Veillard911f49a2001-04-07 15:39:35 +00007501 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007502 for (i = 0; i < oldset->nodeNr; i++) {
7503 /*
7504 * Run the evaluation with a node list made of a single item
7505 * in the nodeset.
7506 */
7507 ctxt->context->node = oldset->nodeTab[i];
7508 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7509 valuePush(ctxt, tmp);
7510
7511 if (op->ch2 != -1)
7512 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7513 CHECK_ERROR;
7514
7515 /*
7516 * The result of the evaluation need to be tested to
7517 * decided whether the filter succeeded or not
7518 */
7519 res = valuePop(ctxt);
7520 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7521 if (range != NULL) {
7522 xmlXPtrLocationSetAdd(newset, range);
7523 }
7524
7525 /*
7526 * Cleanup
7527 */
7528 if (res != NULL)
7529 xmlXPathFreeObject(res);
7530 if (ctxt->value == tmp) {
7531 res = valuePop(ctxt);
7532 xmlXPathFreeObject(res);
7533 }
7534
7535 ctxt->context->node = NULL;
7536 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007537 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007538
7539 /*
7540 * The result is used as the new evaluation set.
7541 */
7542 xmlXPathFreeObject(obj);
7543 ctxt->context->node = NULL;
7544 ctxt->context->contextSize = -1;
7545 ctxt->context->proximityPosition = -1;
7546 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7547 return;
7548 }
7549#endif /* LIBXML_XPTR_ENABLED */
7550 }
7551 xmlGenericError(xmlGenericErrorContext,
7552 "XPath: unknown precompiled operation %d\n",
7553 op->op);
7554 return;
7555}
7556
7557/**
7558 * xmlXPathRunEval:
7559 * @ctxt: the XPath parser context with the compiled expression
7560 *
7561 * Evaluate the Precompiled XPath expression in the given context.
7562 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007563static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007564xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7565 xmlXPathCompExprPtr comp;
7566
7567 if ((ctxt == NULL) || (ctxt->comp == NULL))
7568 return;
7569
7570 if (ctxt->valueTab == NULL) {
7571 /* Allocate the value stack */
7572 ctxt->valueTab = (xmlXPathObjectPtr *)
7573 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7574 if (ctxt->valueTab == NULL) {
7575 xmlFree(ctxt);
7576 xmlGenericError(xmlGenericErrorContext,
7577 "xmlXPathRunEval: out of memory\n");
7578 return;
7579 }
7580 ctxt->valueNr = 0;
7581 ctxt->valueMax = 10;
7582 ctxt->value = NULL;
7583 }
7584 comp = ctxt->comp;
7585 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7586}
7587
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007588/************************************************************************
7589 * *
7590 * Public interfaces *
7591 * *
7592 ************************************************************************/
7593
7594/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007595 * xmlXPathEvalPredicate:
7596 * @ctxt: the XPath context
7597 * @res: the Predicate Expression evaluation result
7598 *
7599 * Evaluate a predicate result for the current node.
7600 * A PredicateExpr is evaluated by evaluating the Expr and converting
7601 * the result to a boolean. If the result is a number, the result will
7602 * be converted to true if the number is equal to the position of the
7603 * context node in the context node list (as returned by the position
7604 * function) and will be converted to false otherwise; if the result
7605 * is not a number, then the result will be converted as if by a call
7606 * to the boolean function.
7607 *
7608 * Return 1 if predicate is true, 0 otherwise
7609 */
7610int
7611xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7612 if (res == NULL) return(0);
7613 switch (res->type) {
7614 case XPATH_BOOLEAN:
7615 return(res->boolval);
7616 case XPATH_NUMBER:
7617 return(res->floatval == ctxt->proximityPosition);
7618 case XPATH_NODESET:
7619 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007620 if (res->nodesetval == NULL)
7621 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007622 return(res->nodesetval->nodeNr != 0);
7623 case XPATH_STRING:
7624 return((res->stringval != NULL) &&
7625 (xmlStrlen(res->stringval) != 0));
7626 default:
7627 STRANGE
7628 }
7629 return(0);
7630}
7631
7632/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007633 * xmlXPathEvaluatePredicateResult:
7634 * @ctxt: the XPath Parser context
7635 * @res: the Predicate Expression evaluation result
7636 *
7637 * Evaluate a predicate result for the current node.
7638 * A PredicateExpr is evaluated by evaluating the Expr and converting
7639 * the result to a boolean. If the result is a number, the result will
7640 * be converted to true if the number is equal to the position of the
7641 * context node in the context node list (as returned by the position
7642 * function) and will be converted to false otherwise; if the result
7643 * is not a number, then the result will be converted as if by a call
7644 * to the boolean function.
7645 *
7646 * Return 1 if predicate is true, 0 otherwise
7647 */
7648int
7649xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
7650 xmlXPathObjectPtr res) {
7651 if (res == NULL) return(0);
7652 switch (res->type) {
7653 case XPATH_BOOLEAN:
7654 return(res->boolval);
7655 case XPATH_NUMBER:
7656 return(res->floatval == ctxt->context->proximityPosition);
7657 case XPATH_NODESET:
7658 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00007659 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00007660 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007661 return(res->nodesetval->nodeNr != 0);
7662 case XPATH_STRING:
7663 return((res->stringval != NULL) &&
7664 (xmlStrlen(res->stringval) != 0));
7665 default:
7666 STRANGE
7667 }
7668 return(0);
7669}
7670
7671/**
7672 * xmlXPathCompile:
7673 * @str: the XPath expression
7674 *
7675 * Compile an XPath expression
7676 *
7677 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7678 * the caller has to free the object.
7679 */
7680xmlXPathCompExprPtr
7681xmlXPathCompile(const xmlChar *str) {
7682 xmlXPathParserContextPtr ctxt;
7683 xmlXPathCompExprPtr comp;
7684
7685 xmlXPathInit();
7686
7687 ctxt = xmlXPathNewParserContext(str, NULL);
7688 xmlXPathCompileExpr(ctxt);
7689
Daniel Veillard40af6492001-04-22 08:50:55 +00007690 if (*ctxt->cur != 0) {
7691 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7692 comp = NULL;
7693 } else {
7694 comp = ctxt->comp;
7695 ctxt->comp = NULL;
7696 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007697 xmlXPathFreeParserContext(ctxt);
7698 return(comp);
7699}
7700
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007701/**
7702 * xmlXPathCompiledEval:
7703 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00007704 * @ctx: the XPath context
7705 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007706 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00007707 *
7708 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7709 * the caller has to free the object.
7710 */
7711xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007712xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00007713 xmlXPathParserContextPtr ctxt;
7714 xmlXPathObjectPtr res, tmp, init = NULL;
7715 int stack = 0;
7716
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007717 if ((comp == NULL) || (ctx == NULL))
7718 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007719 xmlXPathInit();
7720
7721 CHECK_CONTEXT(ctx)
7722
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007723 ctxt = xmlXPathCompParserContext(comp, ctx);
7724 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007725
7726 if (ctxt->value == NULL) {
7727 xmlGenericError(xmlGenericErrorContext,
7728 "xmlXPathEval: evaluation failed\n");
7729 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007730 } else {
7731 res = valuePop(ctxt);
7732 }
7733
7734 do {
7735 tmp = valuePop(ctxt);
7736 if (tmp != NULL) {
7737 if (tmp != init)
7738 stack++;
7739 xmlXPathFreeObject(tmp);
7740 }
7741 } while (tmp != NULL);
7742 if ((stack != 0) && (res != NULL)) {
7743 xmlGenericError(xmlGenericErrorContext,
7744 "xmlXPathEval: %d object left on the stack\n",
7745 stack);
7746 }
7747 if (ctxt->error != XPATH_EXPRESSION_OK) {
7748 xmlXPathFreeObject(res);
7749 res = NULL;
7750 }
7751
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007752
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007753 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007754 xmlXPathFreeParserContext(ctxt);
7755 return(res);
7756}
7757
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007758/**
7759 * xmlXPathEvalExpr:
7760 * @ctxt: the XPath Parser context
7761 *
7762 * Parse and evaluate an XPath expression in the given context,
7763 * then push the result on the context stack
7764 */
7765void
7766xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
7767 xmlXPathCompileExpr(ctxt);
7768 xmlXPathRunEval(ctxt);
7769}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007770
7771/**
7772 * xmlXPathEval:
7773 * @str: the XPath expression
7774 * @ctx: the XPath context
7775 *
7776 * Evaluate the XPath Location Path in the given context.
7777 *
7778 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7779 * the caller has to free the object.
7780 */
7781xmlXPathObjectPtr
7782xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
7783 xmlXPathParserContextPtr ctxt;
7784 xmlXPathObjectPtr res, tmp, init = NULL;
7785 int stack = 0;
7786
7787 xmlXPathInit();
7788
7789 CHECK_CONTEXT(ctx)
7790
7791 ctxt = xmlXPathNewParserContext(str, ctx);
7792 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007793
7794 if (ctxt->value == NULL) {
7795 xmlGenericError(xmlGenericErrorContext,
7796 "xmlXPathEval: evaluation failed\n");
7797 res = NULL;
7798 } else if (*ctxt->cur != 0) {
7799 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7800 res = NULL;
7801 } else {
7802 res = valuePop(ctxt);
7803 }
7804
7805 do {
7806 tmp = valuePop(ctxt);
7807 if (tmp != NULL) {
7808 if (tmp != init)
7809 stack++;
7810 xmlXPathFreeObject(tmp);
7811 }
7812 } while (tmp != NULL);
7813 if ((stack != 0) && (res != NULL)) {
7814 xmlGenericError(xmlGenericErrorContext,
7815 "xmlXPathEval: %d object left on the stack\n",
7816 stack);
7817 }
7818 if (ctxt->error != XPATH_EXPRESSION_OK) {
7819 xmlXPathFreeObject(res);
7820 res = NULL;
7821 }
7822
Owen Taylor3473f882001-02-23 17:55:21 +00007823 xmlXPathFreeParserContext(ctxt);
7824 return(res);
7825}
7826
7827/**
7828 * xmlXPathEvalExpression:
7829 * @str: the XPath expression
7830 * @ctxt: the XPath context
7831 *
7832 * Evaluate the XPath expression in the given context.
7833 *
7834 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
7835 * the caller has to free the object.
7836 */
7837xmlXPathObjectPtr
7838xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
7839 xmlXPathParserContextPtr pctxt;
7840 xmlXPathObjectPtr res, tmp;
7841 int stack = 0;
7842
7843 xmlXPathInit();
7844
7845 CHECK_CONTEXT(ctxt)
7846
7847 pctxt = xmlXPathNewParserContext(str, ctxt);
7848 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007849
7850 if (*pctxt->cur != 0) {
7851 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7852 res = NULL;
7853 } else {
7854 res = valuePop(pctxt);
7855 }
7856 do {
7857 tmp = valuePop(pctxt);
7858 if (tmp != NULL) {
7859 xmlXPathFreeObject(tmp);
7860 stack++;
7861 }
7862 } while (tmp != NULL);
7863 if ((stack != 0) && (res != NULL)) {
7864 xmlGenericError(xmlGenericErrorContext,
7865 "xmlXPathEvalExpression: %d object left on the stack\n",
7866 stack);
7867 }
7868 xmlXPathFreeParserContext(pctxt);
7869 return(res);
7870}
7871
7872/**
7873 * xmlXPathRegisterAllFunctions:
7874 * @ctxt: the XPath context
7875 *
7876 * Registers all default XPath functions in this context
7877 */
7878void
7879xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
7880{
7881 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
7882 xmlXPathBooleanFunction);
7883 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
7884 xmlXPathCeilingFunction);
7885 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
7886 xmlXPathCountFunction);
7887 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
7888 xmlXPathConcatFunction);
7889 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
7890 xmlXPathContainsFunction);
7891 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
7892 xmlXPathIdFunction);
7893 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
7894 xmlXPathFalseFunction);
7895 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
7896 xmlXPathFloorFunction);
7897 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
7898 xmlXPathLastFunction);
7899 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
7900 xmlXPathLangFunction);
7901 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
7902 xmlXPathLocalNameFunction);
7903 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
7904 xmlXPathNotFunction);
7905 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
7906 xmlXPathNameFunction);
7907 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
7908 xmlXPathNamespaceURIFunction);
7909 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
7910 xmlXPathNormalizeFunction);
7911 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
7912 xmlXPathNumberFunction);
7913 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
7914 xmlXPathPositionFunction);
7915 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
7916 xmlXPathRoundFunction);
7917 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
7918 xmlXPathStringFunction);
7919 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
7920 xmlXPathStringLengthFunction);
7921 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
7922 xmlXPathStartsWithFunction);
7923 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
7924 xmlXPathSubstringFunction);
7925 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
7926 xmlXPathSubstringBeforeFunction);
7927 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
7928 xmlXPathSubstringAfterFunction);
7929 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
7930 xmlXPathSumFunction);
7931 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
7932 xmlXPathTrueFunction);
7933 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
7934 xmlXPathTranslateFunction);
7935}
7936
7937#endif /* LIBXML_XPATH_ENABLED */