blob: 23910635f3eee7c2c27c466a31160fea4a977ee1 [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
42
43#include <libxml/xmlmemory.h>
44#include <libxml/tree.h>
45#include <libxml/valid.h>
46#include <libxml/xpath.h>
47#include <libxml/xpathInternals.h>
48#include <libxml/parserInternals.h>
49#include <libxml/hash.h>
50#ifdef LIBXML_XPTR_ENABLED
51#include <libxml/xpointer.h>
52#endif
53#ifdef LIBXML_DEBUG_ENABLED
54#include <libxml/debugXML.h>
55#endif
56#include <libxml/xmlerror.h>
57
58/* #define DEBUG */
59/* #define DEBUG_STEP */
60/* #define DEBUG_EXPR */
61
62void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
63double xmlXPathStringEvalNumber(const xmlChar *str);
64
Daniel Veillard9e7160d2001-03-18 23:17:47 +000065/************************************************************************
66 * *
67 * Floating point stuff *
68 * *
69 ************************************************************************/
70
Owen Taylor3473f882001-02-23 17:55:21 +000071/*
Owen Taylor3473f882001-02-23 17:55:21 +000072 * The lack of portability of this section of the libc is annoying !
73 */
74double xmlXPathNAN = 0;
75double xmlXPathPINF = 1;
76double xmlXPathNINF = -1;
77
78#ifndef isinf
79#ifndef HAVE_ISINF
80
81#if HAVE_FPCLASS
82
83int isinf(double d) {
84 fpclass_t type = fpclass(d);
85 switch (type) {
86 case FP_NINF:
87 return(-1);
88 case FP_PINF:
89 return(1);
90 }
91 return(0);
92}
93
94#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
95
96#if HAVE_FP_CLASS_H
97#include <fp_class.h>
98#endif
99
100int isinf(double d) {
101#if HAVE_FP_CLASS
102 int fpclass = fp_class(d);
103#else
104 int fpclass = fp_class_d(d);
105#endif
106 if (fpclass == FP_POS_INF)
107 return(1);
108 if (fpclass == FP_NEG_INF)
109 return(-1);
110 return(0);
111}
112
113#elif defined(HAVE_CLASS)
114
115int isinf(double d) {
116 int fpclass = class(d);
117 if (fpclass == FP_PLUS_INF)
118 return(1);
119 if (fpclass == FP_MINUS_INF)
120 return(-1);
121 return(0);
122}
123#elif defined(finite) || defined(HAVE_FINITE)
124int isinf(double x) { return !finite(x) && x==x; }
125#elif defined(HUGE_VAL)
126int isinf(double x)
127{
128 if (x == HUGE_VAL)
129 return(1);
130 if (x == -HUGE_VAL)
131 return(-1);
132 return(0);
133}
134#endif
135
136#endif /* ! HAVE_ISINF */
137#endif /* ! defined(isinf) */
138
139#ifndef isnan
140#ifndef HAVE_ISNAN
141
142#ifdef HAVE_ISNAND
143#define isnan(f) isnand(f)
144#endif /* HAVE_iSNAND */
145
146#endif /* ! HAVE_iSNAN */
147#endif /* ! defined(isnan) */
148
149/**
150 * xmlXPathInit:
151 *
152 * Initialize the XPath environment
153 */
154void
155xmlXPathInit(void) {
156 static int initialized = 0;
157
158 if (initialized) return;
159
Daniel Veillard61d80a22001-04-27 17:13:01 +0000160#ifdef XPATH_USE_DIVISION_SHORTCUTS
161 xmlXPathNAN = 0;
162 xmlXPathNAN /= 0.0;
163 xmlXPathPINF = 1;
164 xmlXPathPINF /= 0.0;
165 xmlXPathNINF = -1;
166 xmlXPathNINF /= 0.0;
167#else
Daniel Veillard1731d6a2001-04-10 16:38:06 +0000168 xmlXPathNAN = 0.0 / 0.0;
Daniel Veillard1731d6a2001-04-10 16:38:06 +0000169 xmlXPathPINF = 1 / 0.0;
Daniel Veillard1731d6a2001-04-10 16:38:06 +0000170 xmlXPathNINF = -1 / 0.0;
Daniel Veillard61d80a22001-04-27 17:13:01 +0000171#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000172
173 initialized = 1;
174}
175
176/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000177 * *
178 * Parser Types *
179 * *
180 ************************************************************************/
181
182/*
183 * Types are private:
184 */
185
186typedef enum {
187 XPATH_OP_END=0,
188 XPATH_OP_AND,
189 XPATH_OP_OR,
190 XPATH_OP_EQUAL,
191 XPATH_OP_CMP,
192 XPATH_OP_PLUS,
193 XPATH_OP_MULT,
194 XPATH_OP_UNION,
195 XPATH_OP_ROOT,
196 XPATH_OP_NODE,
197 XPATH_OP_RESET,
198 XPATH_OP_COLLECT,
199 XPATH_OP_VALUE,
200 XPATH_OP_VARIABLE,
201 XPATH_OP_FUNCTION,
202 XPATH_OP_ARG,
203 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000204 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000205 XPATH_OP_SORT
206#ifdef LIBXML_XPTR_ENABLED
207 ,XPATH_OP_RANGETO
208#endif
209} xmlXPathOp;
210
211typedef enum {
212 AXIS_ANCESTOR = 1,
213 AXIS_ANCESTOR_OR_SELF,
214 AXIS_ATTRIBUTE,
215 AXIS_CHILD,
216 AXIS_DESCENDANT,
217 AXIS_DESCENDANT_OR_SELF,
218 AXIS_FOLLOWING,
219 AXIS_FOLLOWING_SIBLING,
220 AXIS_NAMESPACE,
221 AXIS_PARENT,
222 AXIS_PRECEDING,
223 AXIS_PRECEDING_SIBLING,
224 AXIS_SELF
225} xmlXPathAxisVal;
226
227typedef enum {
228 NODE_TEST_NONE = 0,
229 NODE_TEST_TYPE = 1,
230 NODE_TEST_PI = 2,
231 NODE_TEST_ALL = 3,
232 NODE_TEST_NS = 4,
233 NODE_TEST_NAME = 5
234} xmlXPathTestVal;
235
236typedef enum {
237 NODE_TYPE_NODE = 0,
238 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
239 NODE_TYPE_TEXT = XML_TEXT_NODE,
240 NODE_TYPE_PI = XML_PI_NODE
241} xmlXPathTypeVal;
242
243
244typedef struct _xmlXPathStepOp xmlXPathStepOp;
245typedef xmlXPathStepOp *xmlXPathStepOpPtr;
246struct _xmlXPathStepOp {
247 xmlXPathOp op;
248 int ch1;
249 int ch2;
250 int value;
251 int value2;
252 int value3;
253 void *value4;
254 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000255 void *cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000256};
257
258struct _xmlXPathCompExpr {
259 int nbStep;
260 int maxStep;
261 xmlXPathStepOp *steps; /* ops for computation */
262 int last;
263};
264
265/************************************************************************
266 * *
267 * Parser Type functions *
268 * *
269 ************************************************************************/
270
271/**
272 * xmlXPathNewCompExpr:
273 *
274 * Create a new Xpath component
275 *
276 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
277 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000278static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000279xmlXPathNewCompExpr(void) {
280 xmlXPathCompExprPtr cur;
281
282 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
283 if (cur == NULL) {
284 xmlGenericError(xmlGenericErrorContext,
285 "xmlXPathNewCompExpr : malloc failed\n");
286 return(NULL);
287 }
288 memset(cur, 0, sizeof(xmlXPathCompExpr));
289 cur->maxStep = 10;
290 cur->nbStep = 0;
291 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
292 sizeof(xmlXPathStepOp));
293 if (cur->steps == NULL) {
294 xmlGenericError(xmlGenericErrorContext,
295 "xmlXPathNewCompExpr : malloc failed\n");
296 xmlFree(cur);
297 return(NULL);
298 }
299 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
300 cur->last = -1;
301 return(cur);
302}
303
304/**
305 * xmlXPathFreeCompExpr:
306 * @comp: an XPATH comp
307 *
308 * Free up the memory allocated by @comp
309 */
310void
311xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) {
312 xmlXPathStepOpPtr op;
313 int i;
314
315 if (comp == NULL)
316 return;
317 for (i = 0;i < comp->nbStep;i++) {
318 op = &comp->steps[i];
319 if (op->value4 != NULL) {
320 if (op->op == XPATH_OP_VALUE)
321 xmlXPathFreeObject(op->value4);
322 else
323 xmlFree(op->value4);
324 }
325 if (op->value5 != NULL)
326 xmlFree(op->value5);
327 }
328 if (comp->steps != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000329 xmlFree(comp->steps);
330 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000331 xmlFree(comp);
332}
333
334/**
335 * xmlXPathCompExprAdd:
336 * @comp: the compiled expression
337 * @ch1: first child index
338 * @ch2: second child index
339 * @op: an op
340 * @value: the first int value
341 * @value2: the second int value
342 * @value3: the third int value
343 * @value4: the first string value
344 * @value5: the second string value
345 *
346 * Add an step to an XPath Compiled Expression
347 *
348 * Returns -1 in case of failure, the index otherwise
349 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000350static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000351xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
352 xmlXPathOp op, int value,
353 int value2, int value3, void *value4, void *value5) {
354 if (comp->nbStep >= comp->maxStep) {
355 xmlXPathStepOp *real;
356
357 comp->maxStep *= 2;
358 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
359 comp->maxStep * sizeof(xmlXPathStepOp));
360 if (real == NULL) {
361 comp->maxStep /= 2;
362 xmlGenericError(xmlGenericErrorContext,
363 "xmlXPathCompExprAdd : realloc failed\n");
364 return(-1);
365 }
366 comp->steps = real;
367 }
368 comp->last = comp->nbStep;
369 comp->steps[comp->nbStep].ch1 = ch1;
370 comp->steps[comp->nbStep].ch2 = ch2;
371 comp->steps[comp->nbStep].op = op;
372 comp->steps[comp->nbStep].value = value;
373 comp->steps[comp->nbStep].value2 = value2;
374 comp->steps[comp->nbStep].value3 = value3;
375 comp->steps[comp->nbStep].value4 = value4;
376 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000377 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000378 return(comp->nbStep++);
379}
380
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000381#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
382 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
383 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000384#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
385 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
386 (op), (val), (val2), (val3), (val4), (val5))
387
388#define PUSH_LEAVE_EXPR(op, val, val2) \
389xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
390
391#define PUSH_UNARY_EXPR(op, ch, val, val2) \
392xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
393
394#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
395xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
396
397/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000398 * *
399 * Debugging related functions *
400 * *
401 ************************************************************************/
402
403#define TODO \
404 xmlGenericError(xmlGenericErrorContext, \
405 "Unimplemented block at %s:%d\n", \
406 __FILE__, __LINE__);
407
408#define STRANGE \
409 xmlGenericError(xmlGenericErrorContext, \
410 "Internal error at %s:%d\n", \
411 __FILE__, __LINE__);
412
413#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000414static void
415xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000416 int i;
417 char shift[100];
418
419 for (i = 0;((i < depth) && (i < 25));i++)
420 shift[2 * i] = shift[2 * i + 1] = ' ';
421 shift[2 * i] = shift[2 * i + 1] = 0;
422 if (cur == NULL) {
423 fprintf(output, shift);
424 fprintf(output, "Node is NULL !\n");
425 return;
426
427 }
428
429 if ((cur->type == XML_DOCUMENT_NODE) ||
430 (cur->type == XML_HTML_DOCUMENT_NODE)) {
431 fprintf(output, shift);
432 fprintf(output, " /\n");
433 } else if (cur->type == XML_ATTRIBUTE_NODE)
434 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
435 else
436 xmlDebugDumpOneNode(output, cur, depth);
437}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000438static void
439xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000440 xmlNodePtr tmp;
441 int i;
442 char shift[100];
443
444 for (i = 0;((i < depth) && (i < 25));i++)
445 shift[2 * i] = shift[2 * i + 1] = ' ';
446 shift[2 * i] = shift[2 * i + 1] = 0;
447 if (cur == NULL) {
448 fprintf(output, shift);
449 fprintf(output, "Node is NULL !\n");
450 return;
451
452 }
453
454 while (cur != NULL) {
455 tmp = cur;
456 cur = cur->next;
457 xmlDebugDumpOneNode(output, tmp, depth);
458 }
459}
Owen Taylor3473f882001-02-23 17:55:21 +0000460
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000461static void
462xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000463 int i;
464 char shift[100];
465
466 for (i = 0;((i < depth) && (i < 25));i++)
467 shift[2 * i] = shift[2 * i + 1] = ' ';
468 shift[2 * i] = shift[2 * i + 1] = 0;
469
470 if (cur == NULL) {
471 fprintf(output, shift);
472 fprintf(output, "NodeSet is NULL !\n");
473 return;
474
475 }
476
Daniel Veillard911f49a2001-04-07 15:39:35 +0000477 if (cur != NULL) {
478 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
479 for (i = 0;i < cur->nodeNr;i++) {
480 fprintf(output, shift);
481 fprintf(output, "%d", i + 1);
482 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
483 }
Owen Taylor3473f882001-02-23 17:55:21 +0000484 }
485}
486
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000487static void
488xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +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) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
497 fprintf(output, shift);
498 fprintf(output, "Value Tree is NULL !\n");
499 return;
500
501 }
502
503 fprintf(output, shift);
504 fprintf(output, "%d", i + 1);
505 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
506}
Owen Taylor3473f882001-02-23 17:55:21 +0000507#if defined(LIBXML_XPTR_ENABLED)
508void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000509static void
510xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000511 int i;
512 char shift[100];
513
514 for (i = 0;((i < depth) && (i < 25));i++)
515 shift[2 * i] = shift[2 * i + 1] = ' ';
516 shift[2 * i] = shift[2 * i + 1] = 0;
517
518 if (cur == NULL) {
519 fprintf(output, shift);
520 fprintf(output, "LocationSet is NULL !\n");
521 return;
522
523 }
524
525 for (i = 0;i < cur->locNr;i++) {
526 fprintf(output, shift);
527 fprintf(output, "%d : ", i + 1);
528 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
529 }
530}
531#endif
532
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000533/**
534 * xmlXPathDebugDumpObject:
535 * @output: the FILE * to dump the output
536 * @cur: the object to inspect
537 * @depth: indentation level
538 *
539 * Dump the content of the object for debugging purposes
540 */
541void
542xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000543 int i;
544 char shift[100];
545
546 for (i = 0;((i < depth) && (i < 25));i++)
547 shift[2 * i] = shift[2 * i + 1] = ' ';
548 shift[2 * i] = shift[2 * i + 1] = 0;
549
550 fprintf(output, shift);
551
552 if (cur == NULL) {
553 fprintf(output, "Object is empty (NULL)\n");
554 return;
555 }
556 switch(cur->type) {
557 case XPATH_UNDEFINED:
558 fprintf(output, "Object is uninitialized\n");
559 break;
560 case XPATH_NODESET:
561 fprintf(output, "Object is a Node Set :\n");
562 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
563 break;
564 case XPATH_XSLT_TREE:
565 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000566 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000567 break;
568 case XPATH_BOOLEAN:
569 fprintf(output, "Object is a Boolean : ");
570 if (cur->boolval) fprintf(output, "true\n");
571 else fprintf(output, "false\n");
572 break;
573 case XPATH_NUMBER:
574 fprintf(output, "Object is a number : %0g\n", cur->floatval);
575 break;
576 case XPATH_STRING:
577 fprintf(output, "Object is a string : ");
578 xmlDebugDumpString(output, cur->stringval);
579 fprintf(output, "\n");
580 break;
581 case XPATH_POINT:
582 fprintf(output, "Object is a point : index %d in node", cur->index);
583 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
584 fprintf(output, "\n");
585 break;
586 case XPATH_RANGE:
587 if ((cur->user2 == NULL) ||
588 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
589 fprintf(output, "Object is a collapsed range :\n");
590 fprintf(output, shift);
591 if (cur->index >= 0)
592 fprintf(output, "index %d in ", cur->index);
593 fprintf(output, "node\n");
594 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
595 depth + 1);
596 } else {
597 fprintf(output, "Object is a range :\n");
598 fprintf(output, shift);
599 fprintf(output, "From ");
600 if (cur->index >= 0)
601 fprintf(output, "index %d in ", cur->index);
602 fprintf(output, "node\n");
603 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
604 depth + 1);
605 fprintf(output, shift);
606 fprintf(output, "To ");
607 if (cur->index2 >= 0)
608 fprintf(output, "index %d in ", cur->index2);
609 fprintf(output, "node\n");
610 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
611 depth + 1);
612 fprintf(output, "\n");
613 }
614 break;
615 case XPATH_LOCATIONSET:
616#if defined(LIBXML_XPTR_ENABLED)
617 fprintf(output, "Object is a Location Set:\n");
618 xmlXPathDebugDumpLocationSet(output,
619 (xmlLocationSetPtr) cur->user, depth);
620#endif
621 break;
622 case XPATH_USERS:
623 fprintf(output, "Object is user defined\n");
624 break;
625 }
626}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000627
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000628static void
629xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000630 xmlXPathStepOpPtr op, int depth) {
631 int i;
632 char shift[100];
633
634 for (i = 0;((i < depth) && (i < 25));i++)
635 shift[2 * i] = shift[2 * i + 1] = ' ';
636 shift[2 * i] = shift[2 * i + 1] = 0;
637
638 fprintf(output, shift);
639 if (op == NULL) {
640 fprintf(output, "Step is NULL\n");
641 return;
642 }
643 switch (op->op) {
644 case XPATH_OP_END:
645 fprintf(output, "END"); break;
646 case XPATH_OP_AND:
647 fprintf(output, "AND"); break;
648 case XPATH_OP_OR:
649 fprintf(output, "OR"); break;
650 case XPATH_OP_EQUAL:
651 if (op->value)
652 fprintf(output, "EQUAL =");
653 else
654 fprintf(output, "EQUAL !=");
655 break;
656 case XPATH_OP_CMP:
657 if (op->value)
658 fprintf(output, "CMP <");
659 else
660 fprintf(output, "CMP >");
661 if (!op->value2)
662 fprintf(output, "=");
663 break;
664 case XPATH_OP_PLUS:
665 if (op->value == 0)
666 fprintf(output, "PLUS -");
667 else if (op->value == 1)
668 fprintf(output, "PLUS +");
669 else if (op->value == 2)
670 fprintf(output, "PLUS unary -");
671 else if (op->value == 3)
672 fprintf(output, "PLUS unary - -");
673 break;
674 case XPATH_OP_MULT:
675 if (op->value == 0)
676 fprintf(output, "MULT *");
677 else if (op->value == 1)
678 fprintf(output, "MULT div");
679 else
680 fprintf(output, "MULT mod");
681 break;
682 case XPATH_OP_UNION:
683 fprintf(output, "UNION"); break;
684 case XPATH_OP_ROOT:
685 fprintf(output, "ROOT"); break;
686 case XPATH_OP_NODE:
687 fprintf(output, "NODE"); break;
688 case XPATH_OP_RESET:
689 fprintf(output, "RESET"); break;
690 case XPATH_OP_SORT:
691 fprintf(output, "SORT"); break;
692 case XPATH_OP_COLLECT: {
693 xmlXPathAxisVal axis = op->value;
694 xmlXPathTestVal test = op->value2;
695 xmlXPathTypeVal type = op->value3;
696 const xmlChar *prefix = op->value4;
697 const xmlChar *name = op->value5;
698
699 fprintf(output, "COLLECT ");
700 switch (axis) {
701 case AXIS_ANCESTOR:
702 fprintf(output, " 'ancestors' "); break;
703 case AXIS_ANCESTOR_OR_SELF:
704 fprintf(output, " 'ancestors-or-self' "); break;
705 case AXIS_ATTRIBUTE:
706 fprintf(output, " 'attributes' "); break;
707 case AXIS_CHILD:
708 fprintf(output, " 'child' "); break;
709 case AXIS_DESCENDANT:
710 fprintf(output, " 'descendant' "); break;
711 case AXIS_DESCENDANT_OR_SELF:
712 fprintf(output, " 'descendant-or-self' "); break;
713 case AXIS_FOLLOWING:
714 fprintf(output, " 'following' "); break;
715 case AXIS_FOLLOWING_SIBLING:
716 fprintf(output, " 'following-siblings' "); break;
717 case AXIS_NAMESPACE:
718 fprintf(output, " 'namespace' "); break;
719 case AXIS_PARENT:
720 fprintf(output, " 'parent' "); break;
721 case AXIS_PRECEDING:
722 fprintf(output, " 'preceding' "); break;
723 case AXIS_PRECEDING_SIBLING:
724 fprintf(output, " 'preceding-sibling' "); break;
725 case AXIS_SELF:
726 fprintf(output, " 'self' "); break;
727 }
728 switch (test) {
729 case NODE_TEST_NONE:
730 fprintf(output, "'none' "); break;
731 case NODE_TEST_TYPE:
732 fprintf(output, "'type' "); break;
733 case NODE_TEST_PI:
734 fprintf(output, "'PI' "); break;
735 case NODE_TEST_ALL:
736 fprintf(output, "'all' "); break;
737 case NODE_TEST_NS:
738 fprintf(output, "'namespace' "); break;
739 case NODE_TEST_NAME:
740 fprintf(output, "'name' "); break;
741 }
742 switch (type) {
743 case NODE_TYPE_NODE:
744 fprintf(output, "'node' "); break;
745 case NODE_TYPE_COMMENT:
746 fprintf(output, "'comment' "); break;
747 case NODE_TYPE_TEXT:
748 fprintf(output, "'text' "); break;
749 case NODE_TYPE_PI:
750 fprintf(output, "'PI' "); break;
751 }
752 if (prefix != NULL)
753 fprintf(output, "%s:", prefix);
754 if (name != NULL)
755 fprintf(output, "%s", name);
756 break;
757
758 }
759 case XPATH_OP_VALUE: {
760 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
761
762 fprintf(output, "ELEM ");
763 xmlXPathDebugDumpObject(output, object, 0);
764 goto finish;
765 }
766 case XPATH_OP_VARIABLE: {
767 const xmlChar *prefix = op->value5;
768 const xmlChar *name = op->value4;
769
770 if (prefix != NULL)
771 fprintf(output, "VARIABLE %s:%s", prefix, name);
772 else
773 fprintf(output, "VARIABLE %s", name);
774 break;
775 }
776 case XPATH_OP_FUNCTION: {
777 int nbargs = op->value;
778 const xmlChar *prefix = op->value5;
779 const xmlChar *name = op->value4;
780
781 if (prefix != NULL)
782 fprintf(output, "FUNCTION %s:%s(%d args)",
783 prefix, name, nbargs);
784 else
785 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
786 break;
787 }
788 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
789 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000790 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000791#ifdef LIBXML_XPTR_ENABLED
792 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
793#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000794 default:
795 fprintf(output, "UNKNOWN %d\n", op->op); return;
796 }
797 fprintf(output, "\n");
798finish:
799 if (op->ch1 >= 0)
800 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
801 if (op->ch2 >= 0)
802 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
803}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000804
805void
806xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
807 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000808 int i;
809 char shift[100];
810
811 for (i = 0;((i < depth) && (i < 25));i++)
812 shift[2 * i] = shift[2 * i + 1] = ' ';
813 shift[2 * i] = shift[2 * i + 1] = 0;
814
815 fprintf(output, shift);
816
817 if (comp == NULL) {
818 fprintf(output, "Compiled Expression is NULL\n");
819 return;
820 }
821 fprintf(output, "Compiled Expression : %d elements\n",
822 comp->nbStep);
823 i = comp->last;
824 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
825}
Owen Taylor3473f882001-02-23 17:55:21 +0000826#endif
827
828/************************************************************************
829 * *
830 * Parser stacks related functions and macros *
831 * *
832 ************************************************************************/
833
834/*
835 * Generic function for accessing stacks in the Parser Context
836 */
837
838#define PUSH_AND_POP(type, name) \
839extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
840 if (ctxt->name##Nr >= ctxt->name##Max) { \
841 ctxt->name##Max *= 2; \
842 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
843 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
844 if (ctxt->name##Tab == NULL) { \
845 xmlGenericError(xmlGenericErrorContext, \
846 "realloc failed !\n"); \
847 return(0); \
848 } \
849 } \
850 ctxt->name##Tab[ctxt->name##Nr] = value; \
851 ctxt->name = value; \
852 return(ctxt->name##Nr++); \
853} \
854extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
855 type ret; \
856 if (ctxt->name##Nr <= 0) return(0); \
857 ctxt->name##Nr--; \
858 if (ctxt->name##Nr > 0) \
859 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
860 else \
861 ctxt->name = NULL; \
862 ret = ctxt->name##Tab[ctxt->name##Nr]; \
863 ctxt->name##Tab[ctxt->name##Nr] = 0; \
864 return(ret); \
865} \
866
867PUSH_AND_POP(xmlXPathObjectPtr, value)
868
869/*
870 * Macros for accessing the content. Those should be used only by the parser,
871 * and not exported.
872 *
873 * Dirty macros, i.e. one need to make assumption on the context to use them
874 *
875 * CUR_PTR return the current pointer to the xmlChar to be parsed.
876 * CUR returns the current xmlChar value, i.e. a 8 bit value
877 * in ISO-Latin or UTF-8.
878 * This should be used internally by the parser
879 * only to compare to ASCII values otherwise it would break when
880 * running with UTF-8 encoding.
881 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
882 * to compare on ASCII based substring.
883 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
884 * strings within the parser.
885 * CURRENT Returns the current char value, with the full decoding of
886 * UTF-8 if we are using this mode. It returns an int.
887 * NEXT Skip to the next character, this does the proper decoding
888 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
889 * It returns the pointer to the current xmlChar.
890 */
891
892#define CUR (*ctxt->cur)
893#define SKIP(val) ctxt->cur += (val)
894#define NXT(val) ctxt->cur[(val)]
895#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +0000896#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
897
898#define COPY_BUF(l,b,i,v) \
899 if (l == 1) b[i++] = (xmlChar) v; \
900 else i += xmlCopyChar(l,&b[i],v)
901
902#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +0000903
904#define SKIP_BLANKS \
905 while (IS_BLANK(*(ctxt->cur))) NEXT
906
907#define CURRENT (*ctxt->cur)
908#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
909
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000910
911#ifndef DBL_DIG
912#define DBL_DIG 16
913#endif
914#ifndef DBL_EPSILON
915#define DBL_EPSILON 1E-9
916#endif
917
918#define UPPER_DOUBLE 1E9
919#define LOWER_DOUBLE 1E-5
920
921#define INTEGER_DIGITS DBL_DIG
922#define FRACTION_DIGITS (DBL_DIG + 1)
923#define EXPONENT_DIGITS (3 + 2)
924
925/**
926 * xmlXPathFormatNumber:
927 * @number: number to format
928 * @buffer: output buffer
929 * @buffersize: size of output buffer
930 *
931 * Convert the number into a string representation.
932 */
933static void
934xmlXPathFormatNumber(double number, char buffer[], int buffersize)
935{
936 switch (isinf(number)) {
937 case 1:
938 if (buffersize > (int)sizeof("+Infinity"))
939 sprintf(buffer, "+Infinity");
940 break;
941 case -1:
942 if (buffersize > (int)sizeof("-Infinity"))
943 sprintf(buffer, "-Infinity");
944 break;
945 default:
946 if (isnan(number)) {
947 if (buffersize > (int)sizeof("NaN"))
948 sprintf(buffer, "NaN");
949 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000950 /* 3 is sign, decimal point, and terminating zero */
951 char work[DBL_DIG + EXPONENT_DIGITS + 3];
952 int integer_place, fraction_place;
953 char *ptr;
954 char *after_fraction;
955 double absolute_value;
956 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000957
Bjorn Reese70a9da52001-04-21 16:57:29 +0000958 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000959
Bjorn Reese70a9da52001-04-21 16:57:29 +0000960 /*
961 * First choose format - scientific or regular floating point.
962 * In either case, result is in work, and after_fraction points
963 * just past the fractional part.
964 */
965 if ( ((absolute_value > UPPER_DOUBLE) ||
966 (absolute_value < LOWER_DOUBLE)) &&
967 (absolute_value != 0.0) ) {
968 /* Use scientific notation */
969 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
970 fraction_place = DBL_DIG - 1;
971 snprintf(work, sizeof(work),"%*.*e",
972 integer_place, fraction_place, number);
973 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000974 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000975 else {
976 /* Use regular notation */
977 integer_place = 1 + (int)log10(absolute_value);
978 fraction_place = (integer_place > 0)
979 ? DBL_DIG - integer_place
980 : DBL_DIG;
981 size = snprintf(work, sizeof(work), "%0.*f",
982 fraction_place, number);
983 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000984 }
985
Bjorn Reese70a9da52001-04-21 16:57:29 +0000986 /* Remove fractional trailing zeroes */
987 ptr = after_fraction;
988 while (*(--ptr) == '0')
989 ;
990 if (*ptr != '.')
991 ptr++;
992 strcpy(ptr, after_fraction);
993
994 /* Finally copy result back to caller */
995 size = strlen(work) + 1;
996 if (size > buffersize) {
997 work[buffersize - 1] = 0;
998 size = buffersize;
999 }
1000 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001001 }
1002 break;
1003 }
1004}
1005
Owen Taylor3473f882001-02-23 17:55:21 +00001006/************************************************************************
1007 * *
1008 * Error handling routines *
1009 * *
1010 ************************************************************************/
1011
1012
1013const char *xmlXPathErrorMessages[] = {
1014 "Ok",
1015 "Number encoding",
1016 "Unfinished litteral",
1017 "Start of litteral",
1018 "Expected $ for variable reference",
1019 "Undefined variable",
1020 "Invalid predicate",
1021 "Invalid expression",
1022 "Missing closing curly brace",
1023 "Unregistered function",
1024 "Invalid operand",
1025 "Invalid type",
1026 "Invalid number of arguments",
1027 "Invalid context size",
1028 "Invalid context position",
1029 "Memory allocation error",
1030 "Syntax error",
1031 "Resource error",
1032 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001033 "Undefined namespace prefix",
1034 "Encoding error",
1035 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001036};
1037
1038/**
1039 * xmlXPathError:
1040 * @ctxt: the XPath Parser context
1041 * @file: the file name
1042 * @line: the line number
1043 * @no: the error number
1044 *
1045 * Create a new xmlNodeSetPtr of type double and of value @val
1046 *
1047 * Returns the newly created object.
1048 */
1049void
1050xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1051 int line, int no) {
1052 int n;
1053 const xmlChar *cur;
1054 const xmlChar *base;
1055
1056 xmlGenericError(xmlGenericErrorContext,
1057 "Error %s:%d: %s\n", file, line,
1058 xmlXPathErrorMessages[no]);
1059
1060 cur = ctxt->cur;
1061 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001062 if ((cur == NULL) || (base == NULL))
1063 return;
1064
Owen Taylor3473f882001-02-23 17:55:21 +00001065 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1066 cur--;
1067 }
1068 n = 0;
1069 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1070 cur--;
1071 if ((*cur == '\n') || (*cur == '\r')) cur++;
1072 base = cur;
1073 n = 0;
1074 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1075 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1076 n++;
1077 }
1078 xmlGenericError(xmlGenericErrorContext, "\n");
1079 cur = ctxt->cur;
1080 while ((*cur == '\n') || (*cur == '\r'))
1081 cur--;
1082 n = 0;
1083 while ((cur != base) && (n++ < 80)) {
1084 xmlGenericError(xmlGenericErrorContext, " ");
1085 base++;
1086 }
1087 xmlGenericError(xmlGenericErrorContext,"^\n");
1088}
1089
1090
1091/************************************************************************
1092 * *
1093 * Routines to handle NodeSets *
1094 * *
1095 ************************************************************************/
1096
1097/**
1098 * xmlXPathCmpNodes:
1099 * @node1: the first node
1100 * @node2: the second node
1101 *
1102 * Compare two nodes w.r.t document order
1103 *
1104 * Returns -2 in case of error 1 if first point < second point, 0 if
1105 * that's the same node, -1 otherwise
1106 */
1107int
1108xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1109 int depth1, depth2;
1110 xmlNodePtr cur, root;
1111
1112 if ((node1 == NULL) || (node2 == NULL))
1113 return(-2);
1114 /*
1115 * a couple of optimizations which will avoid computations in most cases
1116 */
1117 if (node1 == node2)
1118 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001119 if ((node1->type == XML_NAMESPACE_DECL) ||
1120 (node2->type == XML_NAMESPACE_DECL))
1121 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001122 if (node1 == node2->prev)
1123 return(1);
1124 if (node1 == node2->next)
1125 return(-1);
1126
1127 /*
1128 * compute depth to root
1129 */
1130 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1131 if (cur == node1)
1132 return(1);
1133 depth2++;
1134 }
1135 root = cur;
1136 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1137 if (cur == node2)
1138 return(-1);
1139 depth1++;
1140 }
1141 /*
1142 * Distinct document (or distinct entities :-( ) case.
1143 */
1144 if (root != cur) {
1145 return(-2);
1146 }
1147 /*
1148 * get the nearest common ancestor.
1149 */
1150 while (depth1 > depth2) {
1151 depth1--;
1152 node1 = node1->parent;
1153 }
1154 while (depth2 > depth1) {
1155 depth2--;
1156 node2 = node2->parent;
1157 }
1158 while (node1->parent != node2->parent) {
1159 node1 = node1->parent;
1160 node2 = node2->parent;
1161 /* should not happen but just in case ... */
1162 if ((node1 == NULL) || (node2 == NULL))
1163 return(-2);
1164 }
1165 /*
1166 * Find who's first.
1167 */
1168 if (node1 == node2->next)
1169 return(-1);
1170 for (cur = node1->next;cur != NULL;cur = cur->next)
1171 if (cur == node2)
1172 return(1);
1173 return(-1); /* assume there is no sibling list corruption */
1174}
1175
1176/**
1177 * xmlXPathNodeSetSort:
1178 * @set: the node set
1179 *
1180 * Sort the node set in document order
1181 */
1182void
1183xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001184 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001185 xmlNodePtr tmp;
1186
1187 if (set == NULL)
1188 return;
1189
1190 /* Use Shell's sort to sort the node-set */
1191 len = set->nodeNr;
1192 for (incr = len / 2; incr > 0; incr /= 2) {
1193 for (i = incr; i < len; i++) {
1194 j = i - incr;
1195 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001196 if (xmlXPathCmpNodes(set->nodeTab[j],
1197 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001198 tmp = set->nodeTab[j];
1199 set->nodeTab[j] = set->nodeTab[j + incr];
1200 set->nodeTab[j + incr] = tmp;
1201 j -= incr;
1202 } else
1203 break;
1204 }
1205 }
1206 }
1207}
1208
1209#define XML_NODESET_DEFAULT 10
1210/**
1211 * xmlXPathNodeSetCreate:
1212 * @val: an initial xmlNodePtr, or NULL
1213 *
1214 * Create a new xmlNodeSetPtr of type double and of value @val
1215 *
1216 * Returns the newly created object.
1217 */
1218xmlNodeSetPtr
1219xmlXPathNodeSetCreate(xmlNodePtr val) {
1220 xmlNodeSetPtr ret;
1221
1222 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1223 if (ret == NULL) {
1224 xmlGenericError(xmlGenericErrorContext,
1225 "xmlXPathNewNodeSet: out of memory\n");
1226 return(NULL);
1227 }
1228 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1229 if (val != NULL) {
1230 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1231 sizeof(xmlNodePtr));
1232 if (ret->nodeTab == NULL) {
1233 xmlGenericError(xmlGenericErrorContext,
1234 "xmlXPathNewNodeSet: out of memory\n");
1235 return(NULL);
1236 }
1237 memset(ret->nodeTab, 0 ,
1238 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1239 ret->nodeMax = XML_NODESET_DEFAULT;
1240 ret->nodeTab[ret->nodeNr++] = val;
1241 }
1242 return(ret);
1243}
1244
1245/**
1246 * xmlXPathNodeSetAdd:
1247 * @cur: the initial node set
1248 * @val: a new xmlNodePtr
1249 *
1250 * add a new xmlNodePtr ot an existing NodeSet
1251 */
1252void
1253xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1254 int i;
1255
1256 if (val == NULL) return;
1257
1258 /*
1259 * check against doublons
1260 */
1261 for (i = 0;i < cur->nodeNr;i++)
1262 if (cur->nodeTab[i] == val) return;
1263
1264 /*
1265 * grow the nodeTab if needed
1266 */
1267 if (cur->nodeMax == 0) {
1268 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1269 sizeof(xmlNodePtr));
1270 if (cur->nodeTab == NULL) {
1271 xmlGenericError(xmlGenericErrorContext,
1272 "xmlXPathNodeSetAdd: out of memory\n");
1273 return;
1274 }
1275 memset(cur->nodeTab, 0 ,
1276 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1277 cur->nodeMax = XML_NODESET_DEFAULT;
1278 } else if (cur->nodeNr == cur->nodeMax) {
1279 xmlNodePtr *temp;
1280
1281 cur->nodeMax *= 2;
1282 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1283 sizeof(xmlNodePtr));
1284 if (temp == NULL) {
1285 xmlGenericError(xmlGenericErrorContext,
1286 "xmlXPathNodeSetAdd: out of memory\n");
1287 return;
1288 }
1289 cur->nodeTab = temp;
1290 }
1291 cur->nodeTab[cur->nodeNr++] = val;
1292}
1293
1294/**
1295 * xmlXPathNodeSetAddUnique:
1296 * @cur: the initial node set
1297 * @val: a new xmlNodePtr
1298 *
1299 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1300 * when we are sure the node is not already in the set.
1301 */
1302void
1303xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1304 if (val == NULL) return;
1305
1306 /*
1307 * grow the nodeTab if needed
1308 */
1309 if (cur->nodeMax == 0) {
1310 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1311 sizeof(xmlNodePtr));
1312 if (cur->nodeTab == NULL) {
1313 xmlGenericError(xmlGenericErrorContext,
1314 "xmlXPathNodeSetAddUnique: out of memory\n");
1315 return;
1316 }
1317 memset(cur->nodeTab, 0 ,
1318 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1319 cur->nodeMax = XML_NODESET_DEFAULT;
1320 } else if (cur->nodeNr == cur->nodeMax) {
1321 xmlNodePtr *temp;
1322
1323 cur->nodeMax *= 2;
1324 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1325 sizeof(xmlNodePtr));
1326 if (temp == NULL) {
1327 xmlGenericError(xmlGenericErrorContext,
1328 "xmlXPathNodeSetAddUnique: out of memory\n");
1329 return;
1330 }
1331 cur->nodeTab = temp;
1332 }
1333 cur->nodeTab[cur->nodeNr++] = val;
1334}
1335
1336/**
1337 * xmlXPathNodeSetMerge:
1338 * @val1: the first NodeSet or NULL
1339 * @val2: the second NodeSet
1340 *
1341 * Merges two nodesets, all nodes from @val2 are added to @val1
1342 * if @val1 is NULL, a new set is created and copied from @val2
1343 *
1344 * Returns val1 once extended or NULL in case of error.
1345 */
1346xmlNodeSetPtr
1347xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001348 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001349
1350 if (val2 == NULL) return(val1);
1351 if (val1 == NULL) {
1352 val1 = xmlXPathNodeSetCreate(NULL);
1353 }
1354
1355 initNr = val1->nodeNr;
1356
1357 for (i = 0;i < val2->nodeNr;i++) {
1358 /*
1359 * check against doublons
1360 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001361 skip = 0;
1362 for (j = 0; j < initNr; j++) {
1363 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1364 skip = 1;
1365 break;
1366 }
1367 }
1368 if (skip)
1369 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001370
1371 /*
1372 * grow the nodeTab if needed
1373 */
1374 if (val1->nodeMax == 0) {
1375 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1376 sizeof(xmlNodePtr));
1377 if (val1->nodeTab == NULL) {
1378 xmlGenericError(xmlGenericErrorContext,
1379 "xmlXPathNodeSetMerge: out of memory\n");
1380 return(NULL);
1381 }
1382 memset(val1->nodeTab, 0 ,
1383 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1384 val1->nodeMax = XML_NODESET_DEFAULT;
1385 } else if (val1->nodeNr == val1->nodeMax) {
1386 xmlNodePtr *temp;
1387
1388 val1->nodeMax *= 2;
1389 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1390 sizeof(xmlNodePtr));
1391 if (temp == NULL) {
1392 xmlGenericError(xmlGenericErrorContext,
1393 "xmlXPathNodeSetMerge: out of memory\n");
1394 return(NULL);
1395 }
1396 val1->nodeTab = temp;
1397 }
1398 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1399 }
1400
1401 return(val1);
1402}
1403
1404/**
1405 * xmlXPathNodeSetDel:
1406 * @cur: the initial node set
1407 * @val: an xmlNodePtr
1408 *
1409 * Removes an xmlNodePtr from an existing NodeSet
1410 */
1411void
1412xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1413 int i;
1414
1415 if (cur == NULL) return;
1416 if (val == NULL) return;
1417
1418 /*
1419 * check against doublons
1420 */
1421 for (i = 0;i < cur->nodeNr;i++)
1422 if (cur->nodeTab[i] == val) break;
1423
1424 if (i >= cur->nodeNr) {
1425#ifdef DEBUG
1426 xmlGenericError(xmlGenericErrorContext,
1427 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1428 val->name);
1429#endif
1430 return;
1431 }
1432 cur->nodeNr--;
1433 for (;i < cur->nodeNr;i++)
1434 cur->nodeTab[i] = cur->nodeTab[i + 1];
1435 cur->nodeTab[cur->nodeNr] = NULL;
1436}
1437
1438/**
1439 * xmlXPathNodeSetRemove:
1440 * @cur: the initial node set
1441 * @val: the index to remove
1442 *
1443 * Removes an entry from an existing NodeSet list.
1444 */
1445void
1446xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1447 if (cur == NULL) return;
1448 if (val >= cur->nodeNr) return;
1449 cur->nodeNr--;
1450 for (;val < cur->nodeNr;val++)
1451 cur->nodeTab[val] = cur->nodeTab[val + 1];
1452 cur->nodeTab[cur->nodeNr] = NULL;
1453}
1454
1455/**
1456 * xmlXPathFreeNodeSet:
1457 * @obj: the xmlNodeSetPtr to free
1458 *
1459 * Free the NodeSet compound (not the actual nodes !).
1460 */
1461void
1462xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1463 if (obj == NULL) return;
1464 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001465 xmlFree(obj->nodeTab);
1466 }
Owen Taylor3473f882001-02-23 17:55:21 +00001467 xmlFree(obj);
1468}
1469
1470/**
1471 * xmlXPathFreeValueTree:
1472 * @obj: the xmlNodeSetPtr to free
1473 *
1474 * Free the NodeSet compound and the actual tree, this is different
1475 * from xmlXPathFreeNodeSet()
1476 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001477static void
Owen Taylor3473f882001-02-23 17:55:21 +00001478xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1479 int i;
1480
1481 if (obj == NULL) return;
1482 for (i = 0;i < obj->nodeNr;i++)
1483 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001484 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001485
1486 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001487 xmlFree(obj->nodeTab);
1488 }
Owen Taylor3473f882001-02-23 17:55:21 +00001489 xmlFree(obj);
1490}
1491
1492#if defined(DEBUG) || defined(DEBUG_STEP)
1493/**
1494 * xmlGenericErrorContextNodeSet:
1495 * @output: a FILE * for the output
1496 * @obj: the xmlNodeSetPtr to free
1497 *
1498 * Quick display of a NodeSet
1499 */
1500void
1501xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1502 int i;
1503
1504 if (output == NULL) output = xmlGenericErrorContext;
1505 if (obj == NULL) {
1506 fprintf(output, "NodeSet == NULL !\n");
1507 return;
1508 }
1509 if (obj->nodeNr == 0) {
1510 fprintf(output, "NodeSet is empty\n");
1511 return;
1512 }
1513 if (obj->nodeTab == NULL) {
1514 fprintf(output, " nodeTab == NULL !\n");
1515 return;
1516 }
1517 for (i = 0; i < obj->nodeNr; i++) {
1518 if (obj->nodeTab[i] == NULL) {
1519 fprintf(output, " NULL !\n");
1520 return;
1521 }
1522 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1523 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1524 fprintf(output, " /");
1525 else if (obj->nodeTab[i]->name == NULL)
1526 fprintf(output, " noname!");
1527 else fprintf(output, " %s", obj->nodeTab[i]->name);
1528 }
1529 fprintf(output, "\n");
1530}
1531#endif
1532
1533/**
1534 * xmlXPathNewNodeSet:
1535 * @val: the NodePtr value
1536 *
1537 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1538 * it with the single Node @val
1539 *
1540 * Returns the newly created object.
1541 */
1542xmlXPathObjectPtr
1543xmlXPathNewNodeSet(xmlNodePtr val) {
1544 xmlXPathObjectPtr ret;
1545
1546 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1547 if (ret == NULL) {
1548 xmlGenericError(xmlGenericErrorContext,
1549 "xmlXPathNewNodeSet: out of memory\n");
1550 return(NULL);
1551 }
1552 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1553 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001554 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001555 ret->nodesetval = xmlXPathNodeSetCreate(val);
1556 return(ret);
1557}
1558
1559/**
1560 * xmlXPathNewValueTree:
1561 * @val: the NodePtr value
1562 *
1563 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1564 * it with the tree root @val
1565 *
1566 * Returns the newly created object.
1567 */
1568xmlXPathObjectPtr
1569xmlXPathNewValueTree(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_XSLT_TREE;
1580 ret->nodesetval = xmlXPathNodeSetCreate(val);
1581 return(ret);
1582}
1583
1584/**
1585 * xmlXPathNewNodeSetList:
1586 * @val: an existing NodeSet
1587 *
1588 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1589 * it with the Nodeset @val
1590 *
1591 * Returns the newly created object.
1592 */
1593xmlXPathObjectPtr
1594xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1595 xmlXPathObjectPtr ret;
1596 int i;
1597
1598 if (val == NULL)
1599 ret = NULL;
1600 else if (val->nodeTab == NULL)
1601 ret = xmlXPathNewNodeSet(NULL);
1602 else
1603 {
1604 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1605 for (i = 1; i < val->nodeNr; ++i)
1606 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1607 }
1608
1609 return(ret);
1610}
1611
1612/**
1613 * xmlXPathWrapNodeSet:
1614 * @val: the NodePtr value
1615 *
1616 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1617 *
1618 * Returns the newly created object.
1619 */
1620xmlXPathObjectPtr
1621xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1622 xmlXPathObjectPtr ret;
1623
1624 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1625 if (ret == NULL) {
1626 xmlGenericError(xmlGenericErrorContext,
1627 "xmlXPathWrapNodeSet: out of memory\n");
1628 return(NULL);
1629 }
1630 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1631 ret->type = XPATH_NODESET;
1632 ret->nodesetval = val;
1633 return(ret);
1634}
1635
1636/**
1637 * xmlXPathFreeNodeSetList:
1638 * @obj: an existing NodeSetList object
1639 *
1640 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1641 * the list contrary to xmlXPathFreeObject().
1642 */
1643void
1644xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1645 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001646 xmlFree(obj);
1647}
1648
1649/************************************************************************
1650 * *
1651 * Routines to handle extra functions *
1652 * *
1653 ************************************************************************/
1654
1655/**
1656 * xmlXPathRegisterFunc:
1657 * @ctxt: the XPath context
1658 * @name: the function name
1659 * @f: the function implementation or NULL
1660 *
1661 * Register a new function. If @f is NULL it unregisters the function
1662 *
1663 * Returns 0 in case of success, -1 in case of error
1664 */
1665int
1666xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1667 xmlXPathFunction f) {
1668 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1669}
1670
1671/**
1672 * xmlXPathRegisterFuncNS:
1673 * @ctxt: the XPath context
1674 * @name: the function name
1675 * @ns_uri: the function namespace URI
1676 * @f: the function implementation or NULL
1677 *
1678 * Register a new function. If @f is NULL it unregisters the function
1679 *
1680 * Returns 0 in case of success, -1 in case of error
1681 */
1682int
1683xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1684 const xmlChar *ns_uri, xmlXPathFunction f) {
1685 if (ctxt == NULL)
1686 return(-1);
1687 if (name == NULL)
1688 return(-1);
1689
1690 if (ctxt->funcHash == NULL)
1691 ctxt->funcHash = xmlHashCreate(0);
1692 if (ctxt->funcHash == NULL)
1693 return(-1);
1694 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1695}
1696
1697/**
1698 * xmlXPathFunctionLookup:
1699 * @ctxt: the XPath context
1700 * @name: the function name
1701 *
1702 * Search in the Function array of the context for the given
1703 * function.
1704 *
1705 * Returns the xmlXPathFunction or NULL if not found
1706 */
1707xmlXPathFunction
1708xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1709 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1710}
1711
1712/**
1713 * xmlXPathFunctionLookupNS:
1714 * @ctxt: the XPath context
1715 * @name: the function name
1716 * @ns_uri: the function namespace URI
1717 *
1718 * Search in the Function array of the context for the given
1719 * function.
1720 *
1721 * Returns the xmlXPathFunction or NULL if not found
1722 */
1723xmlXPathFunction
1724xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1725 const xmlChar *ns_uri) {
1726 if (ctxt == NULL)
1727 return(NULL);
1728 if (ctxt->funcHash == NULL)
1729 return(NULL);
1730 if (name == NULL)
1731 return(NULL);
1732
1733 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1734}
1735
1736/**
1737 * xmlXPathRegisteredFuncsCleanup:
1738 * @ctxt: the XPath context
1739 *
1740 * Cleanup the XPath context data associated to registered functions
1741 */
1742void
1743xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1744 if (ctxt == NULL)
1745 return;
1746
1747 xmlHashFree(ctxt->funcHash, NULL);
1748 ctxt->funcHash = NULL;
1749}
1750
1751/************************************************************************
1752 * *
1753 * Routines to handle Variable *
1754 * *
1755 ************************************************************************/
1756
1757/**
1758 * xmlXPathRegisterVariable:
1759 * @ctxt: the XPath context
1760 * @name: the variable name
1761 * @value: the variable value or NULL
1762 *
1763 * Register a new variable value. If @value is NULL it unregisters
1764 * the variable
1765 *
1766 * Returns 0 in case of success, -1 in case of error
1767 */
1768int
1769xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1770 xmlXPathObjectPtr value) {
1771 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1772}
1773
1774/**
1775 * xmlXPathRegisterVariableNS:
1776 * @ctxt: the XPath context
1777 * @name: the variable name
1778 * @ns_uri: the variable namespace URI
1779 * @value: the variable value or NULL
1780 *
1781 * Register a new variable value. If @value is NULL it unregisters
1782 * the variable
1783 *
1784 * Returns 0 in case of success, -1 in case of error
1785 */
1786int
1787xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1788 const xmlChar *ns_uri,
1789 xmlXPathObjectPtr value) {
1790 if (ctxt == NULL)
1791 return(-1);
1792 if (name == NULL)
1793 return(-1);
1794
1795 if (ctxt->varHash == NULL)
1796 ctxt->varHash = xmlHashCreate(0);
1797 if (ctxt->varHash == NULL)
1798 return(-1);
1799 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1800 (void *) value,
1801 (xmlHashDeallocator)xmlXPathFreeObject));
1802}
1803
1804/**
1805 * xmlXPathRegisterVariableLookup:
1806 * @ctxt: the XPath context
1807 * @f: the lookup function
1808 * @data: the lookup data
1809 *
1810 * register an external mechanism to do variable lookup
1811 */
1812void
1813xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1814 xmlXPathVariableLookupFunc f, void *data) {
1815 if (ctxt == NULL)
1816 return;
1817 ctxt->varLookupFunc = (void *) f;
1818 ctxt->varLookupData = data;
1819}
1820
1821/**
1822 * xmlXPathVariableLookup:
1823 * @ctxt: the XPath context
1824 * @name: the variable name
1825 *
1826 * Search in the Variable array of the context for the given
1827 * variable value.
1828 *
1829 * Returns the value or NULL if not found
1830 */
1831xmlXPathObjectPtr
1832xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1833 if (ctxt == NULL)
1834 return(NULL);
1835
1836 if (ctxt->varLookupFunc != NULL) {
1837 xmlXPathObjectPtr ret;
1838
1839 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1840 (ctxt->varLookupData, name, NULL);
1841 if (ret != NULL) return(ret);
1842 }
1843 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1844}
1845
1846/**
1847 * xmlXPathVariableLookupNS:
1848 * @ctxt: the XPath context
1849 * @name: the variable name
1850 * @ns_uri: the variable namespace URI
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
1858xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1859 const xmlChar *ns_uri) {
1860 if (ctxt == NULL)
1861 return(NULL);
1862
1863 if (ctxt->varLookupFunc != NULL) {
1864 xmlXPathObjectPtr ret;
1865
1866 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1867 (ctxt->varLookupData, name, ns_uri);
1868 if (ret != NULL) return(ret);
1869 }
1870
1871 if (ctxt->varHash == NULL)
1872 return(NULL);
1873 if (name == NULL)
1874 return(NULL);
1875
1876 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1877}
1878
1879/**
1880 * xmlXPathRegisteredVariablesCleanup:
1881 * @ctxt: the XPath context
1882 *
1883 * Cleanup the XPath context data associated to registered variables
1884 */
1885void
1886xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1887 if (ctxt == NULL)
1888 return;
1889
1890 xmlHashFree(ctxt->varHash, NULL);
1891 ctxt->varHash = NULL;
1892}
1893
1894/**
1895 * xmlXPathRegisterNs:
1896 * @ctxt: the XPath context
1897 * @prefix: the namespace prefix
1898 * @ns_uri: the namespace name
1899 *
1900 * Register a new namespace. If @ns_uri is NULL it unregisters
1901 * the namespace
1902 *
1903 * Returns 0 in case of success, -1 in case of error
1904 */
1905int
1906xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1907 const xmlChar *ns_uri) {
1908 if (ctxt == NULL)
1909 return(-1);
1910 if (prefix == NULL)
1911 return(-1);
1912
1913 if (ctxt->nsHash == NULL)
1914 ctxt->nsHash = xmlHashCreate(10);
1915 if (ctxt->nsHash == NULL)
1916 return(-1);
1917 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1918 (xmlHashDeallocator)xmlFree));
1919}
1920
1921/**
1922 * xmlXPathNsLookup:
1923 * @ctxt: the XPath context
1924 * @prefix: the namespace prefix value
1925 *
1926 * Search in the namespace declaration array of the context for the given
1927 * namespace name associated to the given prefix
1928 *
1929 * Returns the value or NULL if not found
1930 */
1931const xmlChar *
1932xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1933 if (ctxt == NULL)
1934 return(NULL);
1935 if (prefix == NULL)
1936 return(NULL);
1937
1938#ifdef XML_XML_NAMESPACE
1939 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1940 return(XML_XML_NAMESPACE);
1941#endif
1942
1943 if (ctxt->nsHash == NULL)
1944 return(NULL);
1945
1946 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1947}
1948
1949/**
1950 * xmlXPathRegisteredVariablesCleanup:
1951 * @ctxt: the XPath context
1952 *
1953 * Cleanup the XPath context data associated to registered variables
1954 */
1955void
1956xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
1957 if (ctxt == NULL)
1958 return;
1959
1960 xmlHashFree(ctxt->nsHash, NULL);
1961 ctxt->nsHash = NULL;
1962}
1963
1964/************************************************************************
1965 * *
1966 * Routines to handle Values *
1967 * *
1968 ************************************************************************/
1969
1970/* Allocations are terrible, one need to optimize all this !!! */
1971
1972/**
1973 * xmlXPathNewFloat:
1974 * @val: the double value
1975 *
1976 * Create a new xmlXPathObjectPtr of type double and of value @val
1977 *
1978 * Returns the newly created object.
1979 */
1980xmlXPathObjectPtr
1981xmlXPathNewFloat(double val) {
1982 xmlXPathObjectPtr ret;
1983
1984 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1985 if (ret == NULL) {
1986 xmlGenericError(xmlGenericErrorContext,
1987 "xmlXPathNewFloat: out of memory\n");
1988 return(NULL);
1989 }
1990 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1991 ret->type = XPATH_NUMBER;
1992 ret->floatval = val;
1993 return(ret);
1994}
1995
1996/**
1997 * xmlXPathNewBoolean:
1998 * @val: the boolean value
1999 *
2000 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2001 *
2002 * Returns the newly created object.
2003 */
2004xmlXPathObjectPtr
2005xmlXPathNewBoolean(int val) {
2006 xmlXPathObjectPtr ret;
2007
2008 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2009 if (ret == NULL) {
2010 xmlGenericError(xmlGenericErrorContext,
2011 "xmlXPathNewBoolean: out of memory\n");
2012 return(NULL);
2013 }
2014 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2015 ret->type = XPATH_BOOLEAN;
2016 ret->boolval = (val != 0);
2017 return(ret);
2018}
2019
2020/**
2021 * xmlXPathNewString:
2022 * @val: the xmlChar * value
2023 *
2024 * Create a new xmlXPathObjectPtr of type string and of value @val
2025 *
2026 * Returns the newly created object.
2027 */
2028xmlXPathObjectPtr
2029xmlXPathNewString(const xmlChar *val) {
2030 xmlXPathObjectPtr ret;
2031
2032 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2033 if (ret == NULL) {
2034 xmlGenericError(xmlGenericErrorContext,
2035 "xmlXPathNewString: out of memory\n");
2036 return(NULL);
2037 }
2038 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2039 ret->type = XPATH_STRING;
2040 if (val != NULL)
2041 ret->stringval = xmlStrdup(val);
2042 else
2043 ret->stringval = xmlStrdup((const xmlChar *)"");
2044 return(ret);
2045}
2046
2047/**
2048 * xmlXPathNewCString:
2049 * @val: the char * value
2050 *
2051 * Create a new xmlXPathObjectPtr of type string and of value @val
2052 *
2053 * Returns the newly created object.
2054 */
2055xmlXPathObjectPtr
2056xmlXPathNewCString(const char *val) {
2057 xmlXPathObjectPtr ret;
2058
2059 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2060 if (ret == NULL) {
2061 xmlGenericError(xmlGenericErrorContext,
2062 "xmlXPathNewCString: out of memory\n");
2063 return(NULL);
2064 }
2065 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2066 ret->type = XPATH_STRING;
2067 ret->stringval = xmlStrdup(BAD_CAST val);
2068 return(ret);
2069}
2070
2071/**
2072 * xmlXPathObjectCopy:
2073 * @val: the original object
2074 *
2075 * allocate a new copy of a given object
2076 *
2077 * Returns the newly created object.
2078 */
2079xmlXPathObjectPtr
2080xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2081 xmlXPathObjectPtr ret;
2082
2083 if (val == NULL)
2084 return(NULL);
2085
2086 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2087 if (ret == NULL) {
2088 xmlGenericError(xmlGenericErrorContext,
2089 "xmlXPathObjectCopy: out of memory\n");
2090 return(NULL);
2091 }
2092 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2093 switch (val->type) {
2094 case XPATH_BOOLEAN:
2095 case XPATH_NUMBER:
2096 case XPATH_POINT:
2097 case XPATH_RANGE:
2098 break;
2099 case XPATH_STRING:
2100 ret->stringval = xmlStrdup(val->stringval);
2101 break;
2102 case XPATH_XSLT_TREE:
2103 if ((val->nodesetval != NULL) &&
2104 (val->nodesetval->nodeTab != NULL))
2105 ret->nodesetval = xmlXPathNodeSetCreate(
2106 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2107 else
2108 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2109 break;
2110 case XPATH_NODESET:
2111 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2112 break;
2113 case XPATH_LOCATIONSET:
2114#ifdef LIBXML_XPTR_ENABLED
2115 {
2116 xmlLocationSetPtr loc = val->user;
2117 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2118 break;
2119 }
2120#endif
2121 case XPATH_UNDEFINED:
2122 case XPATH_USERS:
2123 xmlGenericError(xmlGenericErrorContext,
2124 "xmlXPathObjectCopy: unsupported type %d\n",
2125 val->type);
2126 break;
2127 }
2128 return(ret);
2129}
2130
2131/**
2132 * xmlXPathFreeObject:
2133 * @obj: the object to free
2134 *
2135 * Free up an xmlXPathObjectPtr object.
2136 */
2137void
2138xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2139 if (obj == NULL) return;
2140 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002141 if (obj->boolval) {
2142 obj->type = XPATH_XSLT_TREE;
2143 if (obj->nodesetval != NULL)
2144 xmlXPathFreeValueTree(obj->nodesetval);
2145 } else {
2146 if (obj->nodesetval != NULL)
2147 xmlXPathFreeNodeSet(obj->nodesetval);
2148 }
Owen Taylor3473f882001-02-23 17:55:21 +00002149#ifdef LIBXML_XPTR_ENABLED
2150 } else if (obj->type == XPATH_LOCATIONSET) {
2151 if (obj->user != NULL)
2152 xmlXPtrFreeLocationSet(obj->user);
2153#endif
2154 } else if (obj->type == XPATH_STRING) {
2155 if (obj->stringval != NULL)
2156 xmlFree(obj->stringval);
2157 } else if (obj->type == XPATH_XSLT_TREE) {
2158 if (obj->nodesetval != NULL)
2159 xmlXPathFreeValueTree(obj->nodesetval);
2160 }
2161
Owen Taylor3473f882001-02-23 17:55:21 +00002162 xmlFree(obj);
2163}
2164
2165/************************************************************************
2166 * *
2167 * Routines to handle XPath contexts *
2168 * *
2169 ************************************************************************/
2170
2171/**
2172 * xmlXPathNewContext:
2173 * @doc: the XML document
2174 *
2175 * Create a new xmlXPathContext
2176 *
2177 * Returns the xmlXPathContext just allocated.
2178 */
2179xmlXPathContextPtr
2180xmlXPathNewContext(xmlDocPtr doc) {
2181 xmlXPathContextPtr ret;
2182
2183 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2184 if (ret == NULL) {
2185 xmlGenericError(xmlGenericErrorContext,
2186 "xmlXPathNewContext: out of memory\n");
2187 return(NULL);
2188 }
2189 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2190 ret->doc = doc;
2191 ret->node = NULL;
2192
2193 ret->varHash = NULL;
2194
2195 ret->nb_types = 0;
2196 ret->max_types = 0;
2197 ret->types = NULL;
2198
2199 ret->funcHash = xmlHashCreate(0);
2200
2201 ret->nb_axis = 0;
2202 ret->max_axis = 0;
2203 ret->axis = NULL;
2204
2205 ret->nsHash = NULL;
2206 ret->user = NULL;
2207
2208 ret->contextSize = -1;
2209 ret->proximityPosition = -1;
2210
2211 xmlXPathRegisterAllFunctions(ret);
2212
2213 return(ret);
2214}
2215
2216/**
2217 * xmlXPathFreeContext:
2218 * @ctxt: the context to free
2219 *
2220 * Free up an xmlXPathContext
2221 */
2222void
2223xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2224 xmlXPathRegisteredNsCleanup(ctxt);
2225 xmlXPathRegisteredFuncsCleanup(ctxt);
2226 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002227 xmlFree(ctxt);
2228}
2229
2230/************************************************************************
2231 * *
2232 * Routines to handle XPath parser contexts *
2233 * *
2234 ************************************************************************/
2235
2236#define CHECK_CTXT(ctxt) \
2237 if (ctxt == NULL) { \
2238 xmlGenericError(xmlGenericErrorContext, \
2239 "%s:%d Internal error: ctxt == NULL\n", \
2240 __FILE__, __LINE__); \
2241 } \
2242
2243
2244#define CHECK_CONTEXT(ctxt) \
2245 if (ctxt == NULL) { \
2246 xmlGenericError(xmlGenericErrorContext, \
2247 "%s:%d Internal error: no context\n", \
2248 __FILE__, __LINE__); \
2249 } \
2250 else if (ctxt->doc == NULL) { \
2251 xmlGenericError(xmlGenericErrorContext, \
2252 "%s:%d Internal error: no document\n", \
2253 __FILE__, __LINE__); \
2254 } \
2255 else if (ctxt->doc->children == NULL) { \
2256 xmlGenericError(xmlGenericErrorContext, \
2257 "%s:%d Internal error: document without root\n", \
2258 __FILE__, __LINE__); \
2259 } \
2260
2261
2262/**
2263 * xmlXPathNewParserContext:
2264 * @str: the XPath expression
2265 * @ctxt: the XPath context
2266 *
2267 * Create a new xmlXPathParserContext
2268 *
2269 * Returns the xmlXPathParserContext just allocated.
2270 */
2271xmlXPathParserContextPtr
2272xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2273 xmlXPathParserContextPtr ret;
2274
2275 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2276 if (ret == NULL) {
2277 xmlGenericError(xmlGenericErrorContext,
2278 "xmlXPathNewParserContext: out of memory\n");
2279 return(NULL);
2280 }
2281 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2282 ret->cur = ret->base = str;
2283 ret->context = ctxt;
2284
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002285 ret->comp = xmlXPathNewCompExpr();
2286 if (ret->comp == NULL) {
2287 xmlFree(ret->valueTab);
2288 xmlFree(ret);
2289 return(NULL);
2290 }
2291
2292 return(ret);
2293}
2294
2295/**
2296 * xmlXPathCompParserContext:
2297 * @comp: the XPath compiled expression
2298 * @ctxt: the XPath context
2299 *
2300 * Create a new xmlXPathParserContext when processing a compiled expression
2301 *
2302 * Returns the xmlXPathParserContext just allocated.
2303 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002304static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002305xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2306 xmlXPathParserContextPtr ret;
2307
2308 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2309 if (ret == NULL) {
2310 xmlGenericError(xmlGenericErrorContext,
2311 "xmlXPathNewParserContext: out of memory\n");
2312 return(NULL);
2313 }
2314 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2315
Owen Taylor3473f882001-02-23 17:55:21 +00002316 /* Allocate the value stack */
2317 ret->valueTab = (xmlXPathObjectPtr *)
2318 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002319 if (ret->valueTab == NULL) {
2320 xmlFree(ret);
2321 xmlGenericError(xmlGenericErrorContext,
2322 "xmlXPathNewParserContext: out of memory\n");
2323 return(NULL);
2324 }
Owen Taylor3473f882001-02-23 17:55:21 +00002325 ret->valueNr = 0;
2326 ret->valueMax = 10;
2327 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002328
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002329 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002330 ret->comp = comp;
2331
Owen Taylor3473f882001-02-23 17:55:21 +00002332 return(ret);
2333}
2334
2335/**
2336 * xmlXPathFreeParserContext:
2337 * @ctxt: the context to free
2338 *
2339 * Free up an xmlXPathParserContext
2340 */
2341void
2342xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2343 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002344 xmlFree(ctxt->valueTab);
2345 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002346 if (ctxt->comp)
2347 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002348 xmlFree(ctxt);
2349}
2350
2351/************************************************************************
2352 * *
2353 * The implicit core function library *
2354 * *
2355 ************************************************************************/
2356
2357/*
2358 * Auto-pop and cast to a number
2359 */
2360void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
2361
2362
2363#define POP_FLOAT \
2364 arg = valuePop(ctxt); \
2365 if (arg == NULL) { \
2366 XP_ERROR(XPATH_INVALID_OPERAND); \
2367 } \
2368 if (arg->type != XPATH_NUMBER) { \
2369 valuePush(ctxt, arg); \
2370 xmlXPathNumberFunction(ctxt, 1); \
2371 arg = valuePop(ctxt); \
2372 }
2373
2374/**
2375 * xmlXPathCompareNodeSetFloat:
2376 * @ctxt: the XPath Parser context
2377 * @inf: less than (1) or greater than (0)
2378 * @strict: is the comparison strict
2379 * @arg: the node set
2380 * @f: the value
2381 *
2382 * Implement the compare operation between a nodeset and a number
2383 * @ns < @val (1, 1, ...
2384 * @ns <= @val (1, 0, ...
2385 * @ns > @val (0, 1, ...
2386 * @ns >= @val (0, 0, ...
2387 *
2388 * If one object to be compared is a node-set and the other is a number,
2389 * then the comparison will be true if and only if there is a node in the
2390 * node-set such that the result of performing the comparison on the number
2391 * to be compared and on the result of converting the string-value of that
2392 * node to a number using the number function is true.
2393 *
2394 * Returns 0 or 1 depending on the results of the test.
2395 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002396static int
Owen Taylor3473f882001-02-23 17:55:21 +00002397xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2398 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2399 int i, ret = 0;
2400 xmlNodeSetPtr ns;
2401 xmlChar *str2;
2402
2403 if ((f == NULL) || (arg == NULL) ||
2404 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2405 xmlXPathFreeObject(arg);
2406 xmlXPathFreeObject(f);
2407 return(0);
2408 }
2409 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002410 if (ns != NULL) {
2411 for (i = 0;i < ns->nodeNr;i++) {
2412 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2413 if (str2 != NULL) {
2414 valuePush(ctxt,
2415 xmlXPathNewString(str2));
2416 xmlFree(str2);
2417 xmlXPathNumberFunction(ctxt, 1);
2418 valuePush(ctxt, xmlXPathObjectCopy(f));
2419 ret = xmlXPathCompareValues(ctxt, inf, strict);
2420 if (ret)
2421 break;
2422 }
2423 }
Owen Taylor3473f882001-02-23 17:55:21 +00002424 }
2425 xmlXPathFreeObject(arg);
2426 xmlXPathFreeObject(f);
2427 return(ret);
2428}
2429
2430/**
2431 * xmlXPathCompareNodeSetString:
2432 * @ctxt: the XPath Parser context
2433 * @inf: less than (1) or greater than (0)
2434 * @strict: is the comparison strict
2435 * @arg: the node set
2436 * @s: the value
2437 *
2438 * Implement the compare operation between a nodeset and a string
2439 * @ns < @val (1, 1, ...
2440 * @ns <= @val (1, 0, ...
2441 * @ns > @val (0, 1, ...
2442 * @ns >= @val (0, 0, ...
2443 *
2444 * If one object to be compared is a node-set and the other is a string,
2445 * then the comparison will be true if and only if there is a node in
2446 * the node-set such that the result of performing the comparison on the
2447 * string-value of the node and the other string is true.
2448 *
2449 * Returns 0 or 1 depending on the results of the test.
2450 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002451static int
Owen Taylor3473f882001-02-23 17:55:21 +00002452xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2453 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2454 int i, ret = 0;
2455 xmlNodeSetPtr ns;
2456 xmlChar *str2;
2457
2458 if ((s == NULL) || (arg == NULL) ||
2459 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2460 xmlXPathFreeObject(arg);
2461 xmlXPathFreeObject(s);
2462 return(0);
2463 }
2464 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002465 if (ns != NULL) {
2466 for (i = 0;i < ns->nodeNr;i++) {
2467 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2468 if (str2 != NULL) {
2469 valuePush(ctxt,
2470 xmlXPathNewString(str2));
2471 xmlFree(str2);
2472 valuePush(ctxt, xmlXPathObjectCopy(s));
2473 ret = xmlXPathCompareValues(ctxt, inf, strict);
2474 if (ret)
2475 break;
2476 }
2477 }
Owen Taylor3473f882001-02-23 17:55:21 +00002478 }
2479 xmlXPathFreeObject(arg);
2480 xmlXPathFreeObject(s);
2481 return(ret);
2482}
2483
2484/**
2485 * xmlXPathCompareNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00002486 * @op: less than (-1), equal (0) or greater than (1)
2487 * @strict: is the comparison strict
2488 * @arg1: the fist node set object
2489 * @arg2: the second node set object
2490 *
2491 * Implement the compare operation on nodesets:
2492 *
2493 * If both objects to be compared are node-sets, then the comparison
2494 * will be true if and only if there is a node in the first node-set
2495 * and a node in the second node-set such that the result of performing
2496 * the comparison on the string-values of the two nodes is true.
2497 * ....
2498 * When neither object to be compared is a node-set and the operator
2499 * is <=, <, >= or >, then the objects are compared by converting both
2500 * objects to numbers and comparing the numbers according to IEEE 754.
2501 * ....
2502 * The number function converts its argument to a number as follows:
2503 * - a string that consists of optional whitespace followed by an
2504 * optional minus sign followed by a Number followed by whitespace
2505 * is converted to the IEEE 754 number that is nearest (according
2506 * to the IEEE 754 round-to-nearest rule) to the mathematical value
2507 * represented by the string; any other string is converted to NaN
2508 *
2509 * Conclusion all nodes need to be converted first to their string value
2510 * and then the comparison must be done when possible
2511 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002512static int
2513xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00002514 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2515 int i, j, init = 0;
2516 double val1;
2517 double *values2;
2518 int ret = 0;
2519 xmlChar *str;
2520 xmlNodeSetPtr ns1;
2521 xmlNodeSetPtr ns2;
2522
2523 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002524 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
2525 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002526 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002527 }
Owen Taylor3473f882001-02-23 17:55:21 +00002528 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002529 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
2530 xmlXPathFreeObject(arg1);
2531 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002532 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002533 }
Owen Taylor3473f882001-02-23 17:55:21 +00002534
2535 ns1 = arg1->nodesetval;
2536 ns2 = arg2->nodesetval;
2537
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002538 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002539 xmlXPathFreeObject(arg1);
2540 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002541 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002542 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002543 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002544 xmlXPathFreeObject(arg1);
2545 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002546 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002547 }
Owen Taylor3473f882001-02-23 17:55:21 +00002548
2549 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
2550 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002551 xmlXPathFreeObject(arg1);
2552 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002553 return(0);
2554 }
2555 for (i = 0;i < ns1->nodeNr;i++) {
2556 str = xmlNodeGetContent(ns1->nodeTab[i]);
2557 if (str == NULL)
2558 continue;
2559 val1 = xmlXPathStringEvalNumber(str);
2560 xmlFree(str);
2561 if (isnan(val1))
2562 continue;
2563 for (j = 0;j < ns2->nodeNr;j++) {
2564 if (init == 0) {
2565 str = xmlNodeGetContent(ns2->nodeTab[j]);
2566 if (str == NULL) {
2567 values2[j] = xmlXPathNAN;
2568 } else {
2569 values2[j] = xmlXPathStringEvalNumber(str);
2570 xmlFree(str);
2571 }
2572 }
2573 if (isnan(values2[j]))
2574 continue;
2575 if (inf && strict)
2576 ret = (val1 < values2[j]);
2577 else if (inf && !strict)
2578 ret = (val1 <= values2[j]);
2579 else if (!inf && strict)
2580 ret = (val1 > values2[j]);
2581 else if (!inf && !strict)
2582 ret = (val1 >= values2[j]);
2583 if (ret)
2584 break;
2585 }
2586 if (ret)
2587 break;
2588 init = 1;
2589 }
2590 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002591 xmlXPathFreeObject(arg1);
2592 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002593 return(ret);
2594 return(0);
2595}
2596
2597/**
2598 * xmlXPathCompareNodeSetValue:
2599 * @ctxt: the XPath Parser context
2600 * @inf: less than (1) or greater than (0)
2601 * @strict: is the comparison strict
2602 * @arg: the node set
2603 * @val: the value
2604 *
2605 * Implement the compare operation between a nodeset and a value
2606 * @ns < @val (1, 1, ...
2607 * @ns <= @val (1, 0, ...
2608 * @ns > @val (0, 1, ...
2609 * @ns >= @val (0, 0, ...
2610 *
2611 * If one object to be compared is a node-set and the other is a boolean,
2612 * then the comparison will be true if and only if the result of performing
2613 * the comparison on the boolean and on the result of converting
2614 * the node-set to a boolean using the boolean function is true.
2615 *
2616 * Returns 0 or 1 depending on the results of the test.
2617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002618static int
Owen Taylor3473f882001-02-23 17:55:21 +00002619xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
2620 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
2621 if ((val == NULL) || (arg == NULL) ||
2622 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2623 return(0);
2624
2625 switch(val->type) {
2626 case XPATH_NUMBER:
2627 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
2628 case XPATH_NODESET:
2629 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002630 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00002631 case XPATH_STRING:
2632 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
2633 case XPATH_BOOLEAN:
2634 valuePush(ctxt, arg);
2635 xmlXPathBooleanFunction(ctxt, 1);
2636 valuePush(ctxt, val);
2637 return(xmlXPathCompareValues(ctxt, inf, strict));
2638 default:
2639 TODO
2640 return(0);
2641 }
2642 return(0);
2643}
2644
2645/**
2646 * xmlXPathEqualNodeSetString
2647 * @arg: the nodeset object argument
2648 * @str: the string to compare to.
2649 *
2650 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2651 * If one object to be compared is a node-set and the other is a string,
2652 * then the comparison will be true if and only if there is a node in
2653 * the node-set such that the result of performing the comparison on the
2654 * string-value of the node and the other string is true.
2655 *
2656 * Returns 0 or 1 depending on the results of the test.
2657 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002658static int
Owen Taylor3473f882001-02-23 17:55:21 +00002659xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
2660 int i;
2661 xmlNodeSetPtr ns;
2662 xmlChar *str2;
2663
2664 if ((str == NULL) || (arg == NULL) ||
2665 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2666 return(0);
2667 ns = arg->nodesetval;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002668 if (ns == NULL)
2669 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002670 if (ns->nodeNr <= 0)
2671 return(0);
2672 for (i = 0;i < ns->nodeNr;i++) {
2673 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2674 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
2675 xmlFree(str2);
2676 return(1);
2677 }
2678 if (str2 != NULL)
2679 xmlFree(str2);
2680 }
2681 return(0);
2682}
2683
2684/**
2685 * xmlXPathEqualNodeSetFloat
2686 * @arg: the nodeset object argument
2687 * @f: the float to compare to
2688 *
2689 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2690 * If one object to be compared is a node-set and the other is a number,
2691 * then the comparison will be true if and only if there is a node in
2692 * the node-set such that the result of performing the comparison on the
2693 * number to be compared and on the result of converting the string-value
2694 * of that node to a number using the number function is true.
2695 *
2696 * Returns 0 or 1 depending on the results of the test.
2697 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002698static int
Owen Taylor3473f882001-02-23 17:55:21 +00002699xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
2700 char buf[100] = "";
2701
2702 if ((arg == NULL) ||
2703 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2704 return(0);
2705
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002706 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00002707 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
2708}
2709
2710
2711/**
2712 * xmlXPathEqualNodeSets
2713 * @arg1: first nodeset object argument
2714 * @arg2: second nodeset object argument
2715 *
2716 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
2717 * If both objects to be compared are node-sets, then the comparison
2718 * will be true if and only if there is a node in the first node-set and
2719 * a node in the second node-set such that the result of performing the
2720 * comparison on the string-values of the two nodes is true.
2721 *
2722 * (needless to say, this is a costly operation)
2723 *
2724 * Returns 0 or 1 depending on the results of the test.
2725 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002726static int
Owen Taylor3473f882001-02-23 17:55:21 +00002727xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2728 int i, j;
2729 xmlChar **values1;
2730 xmlChar **values2;
2731 int ret = 0;
2732 xmlNodeSetPtr ns1;
2733 xmlNodeSetPtr ns2;
2734
2735 if ((arg1 == NULL) ||
2736 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
2737 return(0);
2738 if ((arg2 == NULL) ||
2739 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
2740 return(0);
2741
2742 ns1 = arg1->nodesetval;
2743 ns2 = arg2->nodesetval;
2744
Daniel Veillard911f49a2001-04-07 15:39:35 +00002745 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00002746 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002747 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00002748 return(0);
2749
2750 /*
2751 * check if there is a node pertaining to both sets
2752 */
2753 for (i = 0;i < ns1->nodeNr;i++)
2754 for (j = 0;j < ns2->nodeNr;j++)
2755 if (ns1->nodeTab[i] == ns2->nodeTab[j])
2756 return(1);
2757
2758 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
2759 if (values1 == NULL)
2760 return(0);
2761 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
2762 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
2763 if (values2 == NULL) {
2764 xmlFree(values1);
2765 return(0);
2766 }
2767 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
2768 for (i = 0;i < ns1->nodeNr;i++) {
2769 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
2770 for (j = 0;j < ns2->nodeNr;j++) {
2771 if (i == 0)
2772 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
2773 ret = xmlStrEqual(values1[i], values2[j]);
2774 if (ret)
2775 break;
2776 }
2777 if (ret)
2778 break;
2779 }
2780 for (i = 0;i < ns1->nodeNr;i++)
2781 if (values1[i] != NULL)
2782 xmlFree(values1[i]);
2783 for (j = 0;j < ns2->nodeNr;j++)
2784 if (values2[j] != NULL)
2785 xmlFree(values2[j]);
2786 xmlFree(values1);
2787 xmlFree(values2);
2788 return(ret);
2789}
2790
2791/**
2792 * xmlXPathEqualValues:
2793 * @ctxt: the XPath Parser context
2794 *
2795 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2796 *
2797 * Returns 0 or 1 depending on the results of the test.
2798 */
2799int
2800xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
2801 xmlXPathObjectPtr arg1, arg2;
2802 int ret = 0;
2803
2804 arg1 = valuePop(ctxt);
2805 if (arg1 == NULL)
2806 XP_ERROR0(XPATH_INVALID_OPERAND);
2807
2808 arg2 = valuePop(ctxt);
2809 if (arg2 == NULL) {
2810 xmlXPathFreeObject(arg1);
2811 XP_ERROR0(XPATH_INVALID_OPERAND);
2812 }
2813
2814 if (arg1 == arg2) {
2815#ifdef DEBUG_EXPR
2816 xmlGenericError(xmlGenericErrorContext,
2817 "Equal: by pointer\n");
2818#endif
2819 return(1);
2820 }
2821
2822 switch (arg1->type) {
2823 case XPATH_UNDEFINED:
2824#ifdef DEBUG_EXPR
2825 xmlGenericError(xmlGenericErrorContext,
2826 "Equal: undefined\n");
2827#endif
2828 break;
2829 case XPATH_XSLT_TREE:
2830 case XPATH_NODESET:
2831 switch (arg2->type) {
2832 case XPATH_UNDEFINED:
2833#ifdef DEBUG_EXPR
2834 xmlGenericError(xmlGenericErrorContext,
2835 "Equal: undefined\n");
2836#endif
2837 break;
2838 case XPATH_XSLT_TREE:
2839 case XPATH_NODESET:
2840 ret = xmlXPathEqualNodeSets(arg1, arg2);
2841 break;
2842 case XPATH_BOOLEAN:
2843 if ((arg1->nodesetval == NULL) ||
2844 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2845 else
2846 ret = 1;
2847 ret = (ret == arg2->boolval);
2848 break;
2849 case XPATH_NUMBER:
2850 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2851 break;
2852 case XPATH_STRING:
2853 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2854 break;
2855 case XPATH_USERS:
2856 case XPATH_POINT:
2857 case XPATH_RANGE:
2858 case XPATH_LOCATIONSET:
2859 TODO
2860 break;
2861 }
2862 break;
2863 case XPATH_BOOLEAN:
2864 switch (arg2->type) {
2865 case XPATH_UNDEFINED:
2866#ifdef DEBUG_EXPR
2867 xmlGenericError(xmlGenericErrorContext,
2868 "Equal: undefined\n");
2869#endif
2870 break;
2871 case XPATH_NODESET:
2872 case XPATH_XSLT_TREE:
2873 if ((arg2->nodesetval == NULL) ||
2874 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2875 else
2876 ret = 1;
2877 break;
2878 case XPATH_BOOLEAN:
2879#ifdef DEBUG_EXPR
2880 xmlGenericError(xmlGenericErrorContext,
2881 "Equal: %d boolean %d \n",
2882 arg1->boolval, arg2->boolval);
2883#endif
2884 ret = (arg1->boolval == arg2->boolval);
2885 break;
2886 case XPATH_NUMBER:
2887 if (arg2->floatval) ret = 1;
2888 else ret = 0;
2889 ret = (arg1->boolval == ret);
2890 break;
2891 case XPATH_STRING:
2892 if ((arg2->stringval == NULL) ||
2893 (arg2->stringval[0] == 0)) ret = 0;
2894 else
2895 ret = 1;
2896 ret = (arg1->boolval == ret);
2897 break;
2898 case XPATH_USERS:
2899 case XPATH_POINT:
2900 case XPATH_RANGE:
2901 case XPATH_LOCATIONSET:
2902 TODO
2903 break;
2904 }
2905 break;
2906 case XPATH_NUMBER:
2907 switch (arg2->type) {
2908 case XPATH_UNDEFINED:
2909#ifdef DEBUG_EXPR
2910 xmlGenericError(xmlGenericErrorContext,
2911 "Equal: undefined\n");
2912#endif
2913 break;
2914 case XPATH_NODESET:
2915 case XPATH_XSLT_TREE:
2916 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2917 break;
2918 case XPATH_BOOLEAN:
2919 if (arg1->floatval) ret = 1;
2920 else ret = 0;
2921 ret = (arg2->boolval == ret);
2922 break;
2923 case XPATH_STRING:
2924 valuePush(ctxt, arg2);
2925 xmlXPathNumberFunction(ctxt, 1);
2926 arg2 = valuePop(ctxt);
2927 /* no break on purpose */
2928 case XPATH_NUMBER:
2929 ret = (arg1->floatval == arg2->floatval);
2930 break;
2931 case XPATH_USERS:
2932 case XPATH_POINT:
2933 case XPATH_RANGE:
2934 case XPATH_LOCATIONSET:
2935 TODO
2936 break;
2937 }
2938 break;
2939 case XPATH_STRING:
2940 switch (arg2->type) {
2941 case XPATH_UNDEFINED:
2942#ifdef DEBUG_EXPR
2943 xmlGenericError(xmlGenericErrorContext,
2944 "Equal: undefined\n");
2945#endif
2946 break;
2947 case XPATH_NODESET:
2948 case XPATH_XSLT_TREE:
2949 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2950 break;
2951 case XPATH_BOOLEAN:
2952 if ((arg1->stringval == NULL) ||
2953 (arg1->stringval[0] == 0)) ret = 0;
2954 else
2955 ret = 1;
2956 ret = (arg2->boolval == ret);
2957 break;
2958 case XPATH_STRING:
2959 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
2960 break;
2961 case XPATH_NUMBER:
2962 valuePush(ctxt, arg1);
2963 xmlXPathNumberFunction(ctxt, 1);
2964 arg1 = valuePop(ctxt);
2965 ret = (arg1->floatval == arg2->floatval);
2966 break;
2967 case XPATH_USERS:
2968 case XPATH_POINT:
2969 case XPATH_RANGE:
2970 case XPATH_LOCATIONSET:
2971 TODO
2972 break;
2973 }
2974 break;
2975 case XPATH_USERS:
2976 case XPATH_POINT:
2977 case XPATH_RANGE:
2978 case XPATH_LOCATIONSET:
2979 TODO
2980 break;
2981 }
2982 xmlXPathFreeObject(arg1);
2983 xmlXPathFreeObject(arg2);
2984 return(ret);
2985}
2986
2987
2988/**
2989 * xmlXPathCompareValues:
2990 * @ctxt: the XPath Parser context
2991 * @inf: less than (1) or greater than (0)
2992 * @strict: is the comparison strict
2993 *
2994 * Implement the compare operation on XPath objects:
2995 * @arg1 < @arg2 (1, 1, ...
2996 * @arg1 <= @arg2 (1, 0, ...
2997 * @arg1 > @arg2 (0, 1, ...
2998 * @arg1 >= @arg2 (0, 0, ...
2999 *
3000 * When neither object to be compared is a node-set and the operator is
3001 * <=, <, >=, >, then the objects are compared by converted both objects
3002 * to numbers and comparing the numbers according to IEEE 754. The <
3003 * comparison will be true if and only if the first number is less than the
3004 * second number. The <= comparison will be true if and only if the first
3005 * number is less than or equal to the second number. The > comparison
3006 * will be true if and only if the first number is greater than the second
3007 * number. The >= comparison will be true if and only if the first number
3008 * is greater than or equal to the second number.
3009 *
3010 * Returns 1 if the comparaison succeeded, 0 if it failed
3011 */
3012int
3013xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3014 int ret = 0;
3015 xmlXPathObjectPtr arg1, arg2;
3016
3017 arg2 = valuePop(ctxt);
3018 if (arg2 == NULL) {
3019 XP_ERROR0(XPATH_INVALID_OPERAND);
3020 }
3021
3022 arg1 = valuePop(ctxt);
3023 if (arg1 == NULL) {
3024 xmlXPathFreeObject(arg2);
3025 XP_ERROR0(XPATH_INVALID_OPERAND);
3026 }
3027
3028 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3029 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003030 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003031 } else {
3032 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003033 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3034 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003035 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003036 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3037 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003038 }
3039 }
3040 return(ret);
3041 }
3042
3043 if (arg1->type != XPATH_NUMBER) {
3044 valuePush(ctxt, arg1);
3045 xmlXPathNumberFunction(ctxt, 1);
3046 arg1 = valuePop(ctxt);
3047 }
3048 if (arg1->type != XPATH_NUMBER) {
3049 xmlXPathFreeObject(arg1);
3050 xmlXPathFreeObject(arg2);
3051 XP_ERROR0(XPATH_INVALID_OPERAND);
3052 }
3053 if (arg2->type != XPATH_NUMBER) {
3054 valuePush(ctxt, arg2);
3055 xmlXPathNumberFunction(ctxt, 1);
3056 arg2 = valuePop(ctxt);
3057 }
3058 if (arg2->type != XPATH_NUMBER) {
3059 xmlXPathFreeObject(arg1);
3060 xmlXPathFreeObject(arg2);
3061 XP_ERROR0(XPATH_INVALID_OPERAND);
3062 }
3063 /*
3064 * Add tests for infinity and nan
3065 * => feedback on 3.4 for Inf and NaN
3066 */
3067 if (inf && strict)
3068 ret = (arg1->floatval < arg2->floatval);
3069 else if (inf && !strict)
3070 ret = (arg1->floatval <= arg2->floatval);
3071 else if (!inf && strict)
3072 ret = (arg1->floatval > arg2->floatval);
3073 else if (!inf && !strict)
3074 ret = (arg1->floatval >= arg2->floatval);
3075 xmlXPathFreeObject(arg1);
3076 xmlXPathFreeObject(arg2);
3077 return(ret);
3078}
3079
3080/**
3081 * xmlXPathValueFlipSign:
3082 * @ctxt: the XPath Parser context
3083 *
3084 * Implement the unary - operation on an XPath object
3085 * The numeric operators convert their operands to numbers as if
3086 * by calling the number function.
3087 */
3088void
3089xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
3090 xmlXPathObjectPtr arg;
3091
3092 POP_FLOAT
3093 arg->floatval = -arg->floatval;
3094 valuePush(ctxt, arg);
3095}
3096
3097/**
3098 * xmlXPathAddValues:
3099 * @ctxt: the XPath Parser context
3100 *
3101 * Implement the add operation on XPath objects:
3102 * The numeric operators convert their operands to numbers as if
3103 * by calling the number function.
3104 */
3105void
3106xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3107 xmlXPathObjectPtr arg;
3108 double val;
3109
3110 POP_FLOAT
3111 val = arg->floatval;
3112 xmlXPathFreeObject(arg);
3113
3114 POP_FLOAT
3115 arg->floatval += val;
3116 valuePush(ctxt, arg);
3117}
3118
3119/**
3120 * xmlXPathSubValues:
3121 * @ctxt: the XPath Parser context
3122 *
3123 * Implement the substraction operation on XPath objects:
3124 * The numeric operators convert their operands to numbers as if
3125 * by calling the number function.
3126 */
3127void
3128xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3129 xmlXPathObjectPtr arg;
3130 double val;
3131
3132 POP_FLOAT
3133 val = arg->floatval;
3134 xmlXPathFreeObject(arg);
3135
3136 POP_FLOAT
3137 arg->floatval -= val;
3138 valuePush(ctxt, arg);
3139}
3140
3141/**
3142 * xmlXPathMultValues:
3143 * @ctxt: the XPath Parser context
3144 *
3145 * Implement the multiply operation on XPath objects:
3146 * The numeric operators convert their operands to numbers as if
3147 * by calling the number function.
3148 */
3149void
3150xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3151 xmlXPathObjectPtr arg;
3152 double val;
3153
3154 POP_FLOAT
3155 val = arg->floatval;
3156 xmlXPathFreeObject(arg);
3157
3158 POP_FLOAT
3159 arg->floatval *= val;
3160 valuePush(ctxt, arg);
3161}
3162
3163/**
3164 * xmlXPathDivValues:
3165 * @ctxt: the XPath Parser context
3166 *
3167 * Implement the div operation on XPath objects @arg1 / @arg2:
3168 * The numeric operators convert their operands to numbers as if
3169 * by calling the number function.
3170 */
3171void
3172xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3173 xmlXPathObjectPtr arg;
3174 double val;
3175
3176 POP_FLOAT
3177 val = arg->floatval;
3178 xmlXPathFreeObject(arg);
3179
3180 POP_FLOAT
3181 arg->floatval /= val;
3182 valuePush(ctxt, arg);
3183}
3184
3185/**
3186 * xmlXPathModValues:
3187 * @ctxt: the XPath Parser context
3188 *
3189 * Implement the mod operation on XPath objects: @arg1 / @arg2
3190 * The numeric operators convert their operands to numbers as if
3191 * by calling the number function.
3192 */
3193void
3194xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3195 xmlXPathObjectPtr arg;
3196 int arg1, arg2;
3197
3198 POP_FLOAT
3199 arg2 = (int) arg->floatval;
3200 xmlXPathFreeObject(arg);
3201
3202 POP_FLOAT
3203 arg1 = (int) arg->floatval;
3204 arg->floatval = arg1 % arg2;
3205 valuePush(ctxt, arg);
3206}
3207
3208/************************************************************************
3209 * *
3210 * The traversal functions *
3211 * *
3212 ************************************************************************/
3213
Owen Taylor3473f882001-02-23 17:55:21 +00003214/*
3215 * A traversal function enumerates nodes along an axis.
3216 * Initially it must be called with NULL, and it indicates
3217 * termination on the axis by returning NULL.
3218 */
3219typedef xmlNodePtr (*xmlXPathTraversalFunction)
3220 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3221
3222/**
3223 * xmlXPathNextSelf:
3224 * @ctxt: the XPath Parser context
3225 * @cur: the current node in the traversal
3226 *
3227 * Traversal function for the "self" direction
3228 * The self axis contains just the context node itself
3229 *
3230 * Returns the next element following that axis
3231 */
3232xmlNodePtr
3233xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3234 if (cur == NULL)
3235 return(ctxt->context->node);
3236 return(NULL);
3237}
3238
3239/**
3240 * xmlXPathNextChild:
3241 * @ctxt: the XPath Parser context
3242 * @cur: the current node in the traversal
3243 *
3244 * Traversal function for the "child" direction
3245 * The child axis contains the children of the context node in document order.
3246 *
3247 * Returns the next element following that axis
3248 */
3249xmlNodePtr
3250xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3251 if (cur == NULL) {
3252 if (ctxt->context->node == NULL) return(NULL);
3253 switch (ctxt->context->node->type) {
3254 case XML_ELEMENT_NODE:
3255 case XML_TEXT_NODE:
3256 case XML_CDATA_SECTION_NODE:
3257 case XML_ENTITY_REF_NODE:
3258 case XML_ENTITY_NODE:
3259 case XML_PI_NODE:
3260 case XML_COMMENT_NODE:
3261 case XML_NOTATION_NODE:
3262 case XML_DTD_NODE:
3263 return(ctxt->context->node->children);
3264 case XML_DOCUMENT_NODE:
3265 case XML_DOCUMENT_TYPE_NODE:
3266 case XML_DOCUMENT_FRAG_NODE:
3267 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003268#ifdef LIBXML_DOCB_ENABLED
3269 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003270#endif
3271 return(((xmlDocPtr) ctxt->context->node)->children);
3272 case XML_ELEMENT_DECL:
3273 case XML_ATTRIBUTE_DECL:
3274 case XML_ENTITY_DECL:
3275 case XML_ATTRIBUTE_NODE:
3276 case XML_NAMESPACE_DECL:
3277 case XML_XINCLUDE_START:
3278 case XML_XINCLUDE_END:
3279 return(NULL);
3280 }
3281 return(NULL);
3282 }
3283 if ((cur->type == XML_DOCUMENT_NODE) ||
3284 (cur->type == XML_HTML_DOCUMENT_NODE))
3285 return(NULL);
3286 return(cur->next);
3287}
3288
3289/**
3290 * xmlXPathNextDescendant:
3291 * @ctxt: the XPath Parser context
3292 * @cur: the current node in the traversal
3293 *
3294 * Traversal function for the "descendant" direction
3295 * the descendant axis contains the descendants of the context node in document
3296 * order; a descendant is a child or a child of a child and so on.
3297 *
3298 * Returns the next element following that axis
3299 */
3300xmlNodePtr
3301xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3302 if (cur == NULL) {
3303 if (ctxt->context->node == NULL)
3304 return(NULL);
3305 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3306 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3307 return(NULL);
3308
3309 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3310 return(ctxt->context->doc->children);
3311 return(ctxt->context->node->children);
3312 }
3313
3314 if (cur->children != NULL)
3315 {
3316 if (cur->children->type != XML_ENTITY_DECL)
3317 return(cur->children);
3318 }
3319 if (cur->next != NULL) return(cur->next);
3320
3321 do {
3322 cur = cur->parent;
3323 if (cur == NULL) return(NULL);
3324 if (cur == ctxt->context->node) return(NULL);
3325 if (cur->next != NULL) {
3326 cur = cur->next;
3327 return(cur);
3328 }
3329 } while (cur != NULL);
3330 return(cur);
3331}
3332
3333/**
3334 * xmlXPathNextDescendantOrSelf:
3335 * @ctxt: the XPath Parser context
3336 * @cur: the current node in the traversal
3337 *
3338 * Traversal function for the "descendant-or-self" direction
3339 * the descendant-or-self axis contains the context node and the descendants
3340 * of the context node in document order; thus the context node is the first
3341 * node on the axis, and the first child of the context node is the second node
3342 * on the axis
3343 *
3344 * Returns the next element following that axis
3345 */
3346xmlNodePtr
3347xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3348 if (cur == NULL) {
3349 if (ctxt->context->node == NULL)
3350 return(NULL);
3351 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3352 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3353 return(NULL);
3354 return(ctxt->context->node);
3355 }
3356
3357 return(xmlXPathNextDescendant(ctxt, cur));
3358}
3359
3360/**
3361 * xmlXPathNextParent:
3362 * @ctxt: the XPath Parser context
3363 * @cur: the current node in the traversal
3364 *
3365 * Traversal function for the "parent" direction
3366 * The parent axis contains the parent of the context node, if there is one.
3367 *
3368 * Returns the next element following that axis
3369 */
3370xmlNodePtr
3371xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3372 /*
3373 * the parent of an attribute or namespace node is the element
3374 * to which the attribute or namespace node is attached
3375 * Namespace handling !!!
3376 */
3377 if (cur == NULL) {
3378 if (ctxt->context->node == NULL) return(NULL);
3379 switch (ctxt->context->node->type) {
3380 case XML_ELEMENT_NODE:
3381 case XML_TEXT_NODE:
3382 case XML_CDATA_SECTION_NODE:
3383 case XML_ENTITY_REF_NODE:
3384 case XML_ENTITY_NODE:
3385 case XML_PI_NODE:
3386 case XML_COMMENT_NODE:
3387 case XML_NOTATION_NODE:
3388 case XML_DTD_NODE:
3389 case XML_ELEMENT_DECL:
3390 case XML_ATTRIBUTE_DECL:
3391 case XML_XINCLUDE_START:
3392 case XML_XINCLUDE_END:
3393 case XML_ENTITY_DECL:
3394 if (ctxt->context->node->parent == NULL)
3395 return((xmlNodePtr) ctxt->context->doc);
3396 return(ctxt->context->node->parent);
3397 case XML_ATTRIBUTE_NODE: {
3398 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3399
3400 return(att->parent);
3401 }
3402 case XML_DOCUMENT_NODE:
3403 case XML_DOCUMENT_TYPE_NODE:
3404 case XML_DOCUMENT_FRAG_NODE:
3405 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003406#ifdef LIBXML_DOCB_ENABLED
3407 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003408#endif
3409 return(NULL);
3410 case XML_NAMESPACE_DECL:
3411 /*
3412 * TODO !!! may require extending struct _xmlNs with
3413 * parent field
3414 * C.f. Infoset case...
3415 */
3416 return(NULL);
3417 }
3418 }
3419 return(NULL);
3420}
3421
3422/**
3423 * xmlXPathNextAncestor:
3424 * @ctxt: the XPath Parser context
3425 * @cur: the current node in the traversal
3426 *
3427 * Traversal function for the "ancestor" direction
3428 * the ancestor axis contains the ancestors of the context node; the ancestors
3429 * of the context node consist of the parent of context node and the parent's
3430 * parent and so on; the nodes are ordered in reverse document order; thus the
3431 * parent is the first node on the axis, and the parent's parent is the second
3432 * node on the axis
3433 *
3434 * Returns the next element following that axis
3435 */
3436xmlNodePtr
3437xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3438 /*
3439 * the parent of an attribute or namespace node is the element
3440 * to which the attribute or namespace node is attached
3441 * !!!!!!!!!!!!!
3442 */
3443 if (cur == NULL) {
3444 if (ctxt->context->node == NULL) return(NULL);
3445 switch (ctxt->context->node->type) {
3446 case XML_ELEMENT_NODE:
3447 case XML_TEXT_NODE:
3448 case XML_CDATA_SECTION_NODE:
3449 case XML_ENTITY_REF_NODE:
3450 case XML_ENTITY_NODE:
3451 case XML_PI_NODE:
3452 case XML_COMMENT_NODE:
3453 case XML_DTD_NODE:
3454 case XML_ELEMENT_DECL:
3455 case XML_ATTRIBUTE_DECL:
3456 case XML_ENTITY_DECL:
3457 case XML_NOTATION_NODE:
3458 case XML_XINCLUDE_START:
3459 case XML_XINCLUDE_END:
3460 if (ctxt->context->node->parent == NULL)
3461 return((xmlNodePtr) ctxt->context->doc);
3462 return(ctxt->context->node->parent);
3463 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003464 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00003465
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003466 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003467 }
3468 case XML_DOCUMENT_NODE:
3469 case XML_DOCUMENT_TYPE_NODE:
3470 case XML_DOCUMENT_FRAG_NODE:
3471 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003472#ifdef LIBXML_DOCB_ENABLED
3473 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003474#endif
3475 return(NULL);
3476 case XML_NAMESPACE_DECL:
3477 /*
3478 * TODO !!! may require extending struct _xmlNs with
3479 * parent field
3480 * C.f. Infoset case...
3481 */
3482 return(NULL);
3483 }
3484 return(NULL);
3485 }
3486 if (cur == ctxt->context->doc->children)
3487 return((xmlNodePtr) ctxt->context->doc);
3488 if (cur == (xmlNodePtr) ctxt->context->doc)
3489 return(NULL);
3490 switch (cur->type) {
3491 case XML_ELEMENT_NODE:
3492 case XML_TEXT_NODE:
3493 case XML_CDATA_SECTION_NODE:
3494 case XML_ENTITY_REF_NODE:
3495 case XML_ENTITY_NODE:
3496 case XML_PI_NODE:
3497 case XML_COMMENT_NODE:
3498 case XML_NOTATION_NODE:
3499 case XML_DTD_NODE:
3500 case XML_ELEMENT_DECL:
3501 case XML_ATTRIBUTE_DECL:
3502 case XML_ENTITY_DECL:
3503 case XML_XINCLUDE_START:
3504 case XML_XINCLUDE_END:
3505 return(cur->parent);
3506 case XML_ATTRIBUTE_NODE: {
3507 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3508
3509 return(att->parent);
3510 }
3511 case XML_DOCUMENT_NODE:
3512 case XML_DOCUMENT_TYPE_NODE:
3513 case XML_DOCUMENT_FRAG_NODE:
3514 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003515#ifdef LIBXML_DOCB_ENABLED
3516 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003517#endif
3518 return(NULL);
3519 case XML_NAMESPACE_DECL:
3520 /*
3521 * TODO !!! may require extending struct _xmlNs with
3522 * parent field
3523 * C.f. Infoset case...
3524 */
3525 return(NULL);
3526 }
3527 return(NULL);
3528}
3529
3530/**
3531 * xmlXPathNextAncestorOrSelf:
3532 * @ctxt: the XPath Parser context
3533 * @cur: the current node in the traversal
3534 *
3535 * Traversal function for the "ancestor-or-self" direction
3536 * he ancestor-or-self axis contains the context node and ancestors of
3537 * the context node in reverse document order; thus the context node is
3538 * the first node on the axis, and the context node's parent the second;
3539 * parent here is defined the same as with the parent axis.
3540 *
3541 * Returns the next element following that axis
3542 */
3543xmlNodePtr
3544xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3545 if (cur == NULL)
3546 return(ctxt->context->node);
3547 return(xmlXPathNextAncestor(ctxt, cur));
3548}
3549
3550/**
3551 * xmlXPathNextFollowingSibling:
3552 * @ctxt: the XPath Parser context
3553 * @cur: the current node in the traversal
3554 *
3555 * Traversal function for the "following-sibling" direction
3556 * The following-sibling axis contains the following siblings of the context
3557 * node in document order.
3558 *
3559 * Returns the next element following that axis
3560 */
3561xmlNodePtr
3562xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3563 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3564 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3565 return(NULL);
3566 if (cur == (xmlNodePtr) ctxt->context->doc)
3567 return(NULL);
3568 if (cur == NULL)
3569 return(ctxt->context->node->next);
3570 return(cur->next);
3571}
3572
3573/**
3574 * xmlXPathNextPrecedingSibling:
3575 * @ctxt: the XPath Parser context
3576 * @cur: the current node in the traversal
3577 *
3578 * Traversal function for the "preceding-sibling" direction
3579 * The preceding-sibling axis contains the preceding siblings of the context
3580 * node in reverse document order; the first preceding sibling is first on the
3581 * axis; the sibling preceding that node is the second on the axis and so on.
3582 *
3583 * Returns the next element following that axis
3584 */
3585xmlNodePtr
3586xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3587 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3588 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3589 return(NULL);
3590 if (cur == (xmlNodePtr) ctxt->context->doc)
3591 return(NULL);
3592 if (cur == NULL)
3593 return(ctxt->context->node->prev);
3594 return(cur->prev);
3595}
3596
3597/**
3598 * xmlXPathNextFollowing:
3599 * @ctxt: the XPath Parser context
3600 * @cur: the current node in the traversal
3601 *
3602 * Traversal function for the "following" direction
3603 * The following axis contains all nodes in the same document as the context
3604 * node that are after the context node in document order, excluding any
3605 * descendants and excluding attribute nodes and namespace nodes; the nodes
3606 * are ordered in document order
3607 *
3608 * Returns the next element following that axis
3609 */
3610xmlNodePtr
3611xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3612 if (cur != NULL && cur->children != NULL)
3613 return cur->children ;
3614 if (cur == NULL) cur = ctxt->context->node;
3615 if (cur == NULL) return(NULL) ; /* ERROR */
3616 if (cur->next != NULL) return(cur->next) ;
3617 do {
3618 cur = cur->parent;
3619 if (cur == NULL) return(NULL);
3620 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
3621 if (cur->next != NULL) return(cur->next);
3622 } while (cur != NULL);
3623 return(cur);
3624}
3625
3626/*
3627 * xmlXPathIsAncestor:
3628 * @ancestor: the ancestor node
3629 * @node: the current node
3630 *
3631 * Check that @ancestor is a @node's ancestor
3632 *
3633 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
3634 */
3635static int
3636xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
3637 if ((ancestor == NULL) || (node == NULL)) return(0);
3638 /* nodes need to be in the same document */
3639 if (ancestor->doc != node->doc) return(0);
3640 /* avoid searching if ancestor or node is the root node */
3641 if (ancestor == (xmlNodePtr) node->doc) return(1);
3642 if (node == (xmlNodePtr) ancestor->doc) return(0);
3643 while (node->parent != NULL) {
3644 if (node->parent == ancestor)
3645 return(1);
3646 node = node->parent;
3647 }
3648 return(0);
3649}
3650
3651/**
3652 * xmlXPathNextPreceding:
3653 * @ctxt: the XPath Parser context
3654 * @cur: the current node in the traversal
3655 *
3656 * Traversal function for the "preceding" direction
3657 * the preceding axis contains all nodes in the same document as the context
3658 * node that are before the context node in document order, excluding any
3659 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
3660 * ordered in reverse document order
3661 *
3662 * Returns the next element following that axis
3663 */
3664xmlNodePtr
3665xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3666 if (cur == NULL)
3667 cur = ctxt->context->node ;
3668 do {
3669 if (cur->prev != NULL) {
3670 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
3671 ;
3672 return(cur) ;
3673 }
3674
3675 cur = cur->parent;
3676 if (cur == NULL) return(NULL);
3677 if (cur == ctxt->context->doc->children) return(NULL);
3678 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
3679 return(cur);
3680}
3681
3682/**
3683 * xmlXPathNextNamespace:
3684 * @ctxt: the XPath Parser context
3685 * @cur: the current attribute in the traversal
3686 *
3687 * Traversal function for the "namespace" direction
3688 * the namespace axis contains the namespace nodes of the context node;
3689 * the order of nodes on this axis is implementation-defined; the axis will
3690 * be empty unless the context node is an element
3691 *
3692 * Returns the next element following that axis
3693 */
3694xmlNodePtr
3695xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3696 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3697 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
3698 if (ctxt->context->namespaces != NULL)
3699 xmlFree(ctxt->context->namespaces);
3700 ctxt->context->namespaces =
3701 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
3702 if (ctxt->context->namespaces == NULL) return(NULL);
3703 ctxt->context->nsNr = 0;
3704 }
3705 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
3706}
3707
3708/**
3709 * xmlXPathNextAttribute:
3710 * @ctxt: the XPath Parser context
3711 * @cur: the current attribute in the traversal
3712 *
3713 * Traversal function for the "attribute" direction
3714 * TODO: support DTD inherited default attributes
3715 *
3716 * Returns the next element following that axis
3717 */
3718xmlNodePtr
3719xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00003720 if (ctxt->context->node == NULL)
3721 return(NULL);
3722 if (ctxt->context->node->type != XML_ELEMENT_NODE)
3723 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003724 if (cur == NULL) {
3725 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3726 return(NULL);
3727 return((xmlNodePtr)ctxt->context->node->properties);
3728 }
3729 return((xmlNodePtr)cur->next);
3730}
3731
3732/************************************************************************
3733 * *
3734 * NodeTest Functions *
3735 * *
3736 ************************************************************************/
3737
Owen Taylor3473f882001-02-23 17:55:21 +00003738#define IS_FUNCTION 200
3739
Owen Taylor3473f882001-02-23 17:55:21 +00003740
3741/************************************************************************
3742 * *
3743 * Implicit tree core function library *
3744 * *
3745 ************************************************************************/
3746
3747/**
3748 * xmlXPathRoot:
3749 * @ctxt: the XPath Parser context
3750 *
3751 * Initialize the context to the root of the document
3752 */
3753void
3754xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
3755 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
3756 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3757}
3758
3759/************************************************************************
3760 * *
3761 * The explicit core function library *
3762 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
3763 * *
3764 ************************************************************************/
3765
3766
3767/**
3768 * xmlXPathLastFunction:
3769 * @ctxt: the XPath Parser context
3770 * @nargs: the number of arguments
3771 *
3772 * Implement the last() XPath function
3773 * number last()
3774 * The last function returns the number of nodes in the context node list.
3775 */
3776void
3777xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3778 CHECK_ARITY(0);
3779 if (ctxt->context->contextSize >= 0) {
3780 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
3781#ifdef DEBUG_EXPR
3782 xmlGenericError(xmlGenericErrorContext,
3783 "last() : %d\n", ctxt->context->contextSize);
3784#endif
3785 } else {
3786 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
3787 }
3788}
3789
3790/**
3791 * xmlXPathPositionFunction:
3792 * @ctxt: the XPath Parser context
3793 * @nargs: the number of arguments
3794 *
3795 * Implement the position() XPath function
3796 * number position()
3797 * The position function returns the position of the context node in the
3798 * context node list. The first position is 1, and so the last positionr
3799 * will be equal to last().
3800 */
3801void
3802xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3803 CHECK_ARITY(0);
3804 if (ctxt->context->proximityPosition >= 0) {
3805 valuePush(ctxt,
3806 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
3807#ifdef DEBUG_EXPR
3808 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
3809 ctxt->context->proximityPosition);
3810#endif
3811 } else {
3812 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
3813 }
3814}
3815
3816/**
3817 * xmlXPathCountFunction:
3818 * @ctxt: the XPath Parser context
3819 * @nargs: the number of arguments
3820 *
3821 * Implement the count() XPath function
3822 * number count(node-set)
3823 */
3824void
3825xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3826 xmlXPathObjectPtr cur;
3827
3828 CHECK_ARITY(1);
3829 if ((ctxt->value == NULL) ||
3830 ((ctxt->value->type != XPATH_NODESET) &&
3831 (ctxt->value->type != XPATH_XSLT_TREE)))
3832 XP_ERROR(XPATH_INVALID_TYPE);
3833 cur = valuePop(ctxt);
3834
Daniel Veillard911f49a2001-04-07 15:39:35 +00003835 if ((cur == NULL) || (cur->nodesetval == NULL))
3836 valuePush(ctxt, xmlXPathNewFloat((double) 0));
3837 else
3838 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00003839 xmlXPathFreeObject(cur);
3840}
3841
3842/**
3843 * xmlXPathIdFunction:
3844 * @ctxt: the XPath Parser context
3845 * @nargs: the number of arguments
3846 *
3847 * Implement the id() XPath function
3848 * node-set id(object)
3849 * The id function selects elements by their unique ID
3850 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
3851 * then the result is the union of the result of applying id to the
3852 * string value of each of the nodes in the argument node-set. When the
3853 * argument to id is of any other type, the argument is converted to a
3854 * string as if by a call to the string function; the string is split
3855 * into a whitespace-separated list of tokens (whitespace is any sequence
3856 * of characters matching the production S); the result is a node-set
3857 * containing the elements in the same document as the context node that
3858 * have a unique ID equal to any of the tokens in the list.
3859 */
3860void
3861xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3862 const xmlChar *tokens;
3863 const xmlChar *cur;
3864 xmlChar *ID;
3865 xmlAttrPtr attr;
3866 xmlNodePtr elem = NULL;
3867 xmlXPathObjectPtr ret, obj;
3868
3869 CHECK_ARITY(1);
3870 obj = valuePop(ctxt);
3871 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3872 if (obj->type == XPATH_NODESET) {
3873 xmlXPathObjectPtr newobj;
3874 int i;
3875
3876 ret = xmlXPathNewNodeSet(NULL);
3877
Daniel Veillard911f49a2001-04-07 15:39:35 +00003878 if (obj->nodesetval != NULL) {
3879 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
3880 valuePush(ctxt,
3881 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
3882 xmlXPathStringFunction(ctxt, 1);
3883 xmlXPathIdFunction(ctxt, 1);
3884 newobj = valuePop(ctxt);
3885 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
3886 newobj->nodesetval);
3887 xmlXPathFreeObject(newobj);
3888 }
Owen Taylor3473f882001-02-23 17:55:21 +00003889 }
3890
3891 xmlXPathFreeObject(obj);
3892 valuePush(ctxt, ret);
3893 return;
3894 }
3895 if (obj->type != XPATH_STRING) {
3896 valuePush(ctxt, obj);
3897 xmlXPathStringFunction(ctxt, 1);
3898 obj = valuePop(ctxt);
3899 if (obj->type != XPATH_STRING) {
3900 xmlXPathFreeObject(obj);
3901 return;
3902 }
3903 }
3904 tokens = obj->stringval;
3905
3906 ret = xmlXPathNewNodeSet(NULL);
3907 valuePush(ctxt, ret);
3908 if (tokens == NULL) {
3909 xmlXPathFreeObject(obj);
3910 return;
3911 }
3912
3913 cur = tokens;
3914
3915 while (IS_BLANK(*cur)) cur++;
3916 while (*cur != 0) {
3917 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
3918 (*cur == '.') || (*cur == '-') ||
3919 (*cur == '_') || (*cur == ':') ||
3920 (IS_COMBINING(*cur)) ||
3921 (IS_EXTENDER(*cur)))
3922 cur++;
3923
3924 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
3925
3926 ID = xmlStrndup(tokens, cur - tokens);
3927 attr = xmlGetID(ctxt->context->doc, ID);
3928 if (attr != NULL) {
3929 elem = attr->parent;
3930 xmlXPathNodeSetAdd(ret->nodesetval, elem);
3931 }
3932 if (ID != NULL)
3933 xmlFree(ID);
3934
3935 while (IS_BLANK(*cur)) cur++;
3936 tokens = cur;
3937 }
3938 xmlXPathFreeObject(obj);
3939 return;
3940}
3941
3942/**
3943 * xmlXPathLocalNameFunction:
3944 * @ctxt: the XPath Parser context
3945 * @nargs: the number of arguments
3946 *
3947 * Implement the local-name() XPath function
3948 * string local-name(node-set?)
3949 * The local-name function returns a string containing the local part
3950 * of the name of the node in the argument node-set that is first in
3951 * document order. If the node-set is empty or the first node has no
3952 * name, an empty string is returned. If the argument is omitted it
3953 * defaults to the context node.
3954 */
3955void
3956xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3957 xmlXPathObjectPtr cur;
3958
3959 if (nargs == 0) {
3960 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3961 nargs = 1;
3962 }
3963
3964 CHECK_ARITY(1);
3965 if ((ctxt->value == NULL) ||
3966 ((ctxt->value->type != XPATH_NODESET) &&
3967 (ctxt->value->type != XPATH_XSLT_TREE)))
3968 XP_ERROR(XPATH_INVALID_TYPE);
3969 cur = valuePop(ctxt);
3970
Daniel Veillard911f49a2001-04-07 15:39:35 +00003971 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003972 valuePush(ctxt, xmlXPathNewCString(""));
3973 } else {
3974 int i = 0; /* Should be first in document order !!!!! */
3975 switch (cur->nodesetval->nodeTab[i]->type) {
3976 case XML_ELEMENT_NODE:
3977 case XML_ATTRIBUTE_NODE:
3978 case XML_PI_NODE:
3979 valuePush(ctxt,
3980 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
3981 break;
3982 case XML_NAMESPACE_DECL:
3983 valuePush(ctxt, xmlXPathNewString(
3984 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
3985 break;
3986 default:
3987 valuePush(ctxt, xmlXPathNewCString(""));
3988 }
3989 }
3990 xmlXPathFreeObject(cur);
3991}
3992
3993/**
3994 * xmlXPathNamespaceURIFunction:
3995 * @ctxt: the XPath Parser context
3996 * @nargs: the number of arguments
3997 *
3998 * Implement the namespace-uri() XPath function
3999 * string namespace-uri(node-set?)
4000 * The namespace-uri function returns a string containing the
4001 * namespace URI of the expanded name of the node in the argument
4002 * node-set that is first in document order. If the node-set is empty,
4003 * the first node has no name, or the expanded name has no namespace
4004 * URI, an empty string is returned. If the argument is omitted it
4005 * defaults to the context node.
4006 */
4007void
4008xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4009 xmlXPathObjectPtr cur;
4010
4011 if (nargs == 0) {
4012 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4013 nargs = 1;
4014 }
4015 CHECK_ARITY(1);
4016 if ((ctxt->value == NULL) ||
4017 ((ctxt->value->type != XPATH_NODESET) &&
4018 (ctxt->value->type != XPATH_XSLT_TREE)))
4019 XP_ERROR(XPATH_INVALID_TYPE);
4020 cur = valuePop(ctxt);
4021
Daniel Veillard911f49a2001-04-07 15:39:35 +00004022 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004023 valuePush(ctxt, xmlXPathNewCString(""));
4024 } else {
4025 int i = 0; /* Should be first in document order !!!!! */
4026 switch (cur->nodesetval->nodeTab[i]->type) {
4027 case XML_ELEMENT_NODE:
4028 case XML_ATTRIBUTE_NODE:
4029 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4030 valuePush(ctxt, xmlXPathNewCString(""));
4031 else
4032 valuePush(ctxt, xmlXPathNewString(
4033 cur->nodesetval->nodeTab[i]->ns->href));
4034 break;
4035 default:
4036 valuePush(ctxt, xmlXPathNewCString(""));
4037 }
4038 }
4039 xmlXPathFreeObject(cur);
4040}
4041
4042/**
4043 * xmlXPathNameFunction:
4044 * @ctxt: the XPath Parser context
4045 * @nargs: the number of arguments
4046 *
4047 * Implement the name() XPath function
4048 * string name(node-set?)
4049 * The name function returns a string containing a QName representing
4050 * the name of the node in the argument node-set that is first in documenti
4051 * order. The QName must represent the name with respect to the namespace
4052 * declarations in effect on the node whose name is being represented.
4053 * Typically, this will be the form in which the name occurred in the XML
4054 * source. This need not be the case if there are namespace declarations
4055 * in effect on the node that associate multiple prefixes with the same
4056 * namespace. However, an implementation may include information about
4057 * the original prefix in its representation of nodes; in this case, an
4058 * implementation can ensure that the returned string is always the same
4059 * as the QName used in the XML source. If the argument it omitted it
4060 * defaults to the context node.
4061 * Libxml keep the original prefix so the "real qualified name" used is
4062 * returned.
4063 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004064static void
Owen Taylor3473f882001-02-23 17:55:21 +00004065xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4066 xmlXPathObjectPtr cur;
4067
4068 if (nargs == 0) {
4069 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4070 nargs = 1;
4071 }
4072
4073 CHECK_ARITY(1);
4074 if ((ctxt->value == NULL) ||
4075 ((ctxt->value->type != XPATH_NODESET) &&
4076 (ctxt->value->type != XPATH_XSLT_TREE)))
4077 XP_ERROR(XPATH_INVALID_TYPE);
4078 cur = valuePop(ctxt);
4079
Daniel Veillard911f49a2001-04-07 15:39:35 +00004080 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004081 valuePush(ctxt, xmlXPathNewCString(""));
4082 } else {
4083 int i = 0; /* Should be first in document order !!!!! */
4084
4085 switch (cur->nodesetval->nodeTab[i]->type) {
4086 case XML_ELEMENT_NODE:
4087 case XML_ATTRIBUTE_NODE:
4088 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4089 valuePush(ctxt, xmlXPathNewString(
4090 cur->nodesetval->nodeTab[i]->name));
4091
4092 else {
4093 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004094 snprintf(name, sizeof(name), "%s:%s",
4095 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4096 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004097 name[sizeof(name) - 1] = 0;
4098 valuePush(ctxt, xmlXPathNewCString(name));
4099 }
4100 break;
4101 default:
4102 valuePush(ctxt,
4103 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4104 xmlXPathLocalNameFunction(ctxt, 1);
4105 }
4106 }
4107 xmlXPathFreeObject(cur);
4108}
4109
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004110
4111/**
4112 * xmlXPathConvertString:
4113 * @val: an XPath object
4114 *
4115 * Converts an existing object to its string() equivalent
4116 *
4117 * Returns the new object, the old one is freed (or the operation
4118 * is done directly on @val)
4119 */
4120xmlXPathObjectPtr
4121xmlXPathConvertString(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004122 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004123
4124 if (val == NULL)
4125 return(xmlXPathNewCString(""));
4126 switch (val->type) {
4127 case XPATH_UNDEFINED:
4128#ifdef DEBUG_EXPR
4129 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
4130#endif
4131 ret = xmlXPathNewCString("");
4132 break;
4133 case XPATH_XSLT_TREE:
4134 case XPATH_NODESET:
Daniel Veillard911f49a2001-04-07 15:39:35 +00004135 if ((val->nodesetval == NULL) || (val->nodesetval->nodeNr == 0)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004136 ret = xmlXPathNewCString("");
4137 } else {
4138 xmlChar *res;
4139
4140 xmlXPathNodeSetSort(val->nodesetval);
4141 res = xmlNodeGetContent(val->nodesetval->nodeTab[0]);
4142 /* TODO: avoid allocating res to free it */
4143 ret = xmlXPathNewString(res);
4144 if (res != NULL)
4145 xmlFree(res);
4146 }
4147 break;
4148 case XPATH_STRING:
4149 return(val);
4150 case XPATH_BOOLEAN:
4151 if (val->boolval) ret = xmlXPathNewCString("true");
4152 else ret = xmlXPathNewCString("false");
4153 break;
4154 case XPATH_NUMBER: {
4155 char buf[100];
4156
4157 xmlXPathFormatNumber(val->floatval, buf, sizeof(buf));
4158 ret = xmlXPathNewCString(buf);
4159 break;
4160 }
4161 case XPATH_USERS:
4162 case XPATH_POINT:
4163 case XPATH_RANGE:
4164 case XPATH_LOCATIONSET:
4165 TODO
4166 ret = xmlXPathNewCString("");
4167 break;
4168 }
4169 xmlXPathFreeObject(val);
4170 return(ret);
4171}
4172
Owen Taylor3473f882001-02-23 17:55:21 +00004173/**
4174 * xmlXPathStringFunction:
4175 * @ctxt: the XPath Parser context
4176 * @nargs: the number of arguments
4177 *
4178 * Implement the string() XPath function
4179 * string string(object?)
4180 * he string function converts an object to a string as follows:
4181 * - A node-set is converted to a string by returning the value of
4182 * the node in the node-set that is first in document order.
4183 * If the node-set is empty, an empty string is returned.
4184 * - A number is converted to a string as follows
4185 * + NaN is converted to the string NaN
4186 * + positive zero is converted to the string 0
4187 * + negative zero is converted to the string 0
4188 * + positive infinity is converted to the string Infinity
4189 * + negative infinity is converted to the string -Infinity
4190 * + if the number is an integer, the number is represented in
4191 * decimal form as a Number with no decimal point and no leading
4192 * zeros, preceded by a minus sign (-) if the number is negative
4193 * + otherwise, the number is represented in decimal form as a
4194 * Number including a decimal point with at least one digit
4195 * before the decimal point and at least one digit after the
4196 * decimal point, preceded by a minus sign (-) if the number
4197 * is negative; there must be no leading zeros before the decimal
4198 * point apart possibly from the one required digit immediatelyi
4199 * before the decimal point; beyond the one required digit
4200 * after the decimal point there must be as many, but only as
4201 * many, more digits as are needed to uniquely distinguish the
4202 * number from all other IEEE 754 numeric values.
4203 * - The boolean false value is converted to the string false.
4204 * The boolean true value is converted to the string true.
4205 *
4206 * If the argument is omitted, it defaults to a node-set with the
4207 * context node as its only member.
4208 */
4209void
4210xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4211 xmlXPathObjectPtr cur;
4212
4213 if (nargs == 0) {
4214 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4215 nargs = 1;
4216 }
4217
4218 CHECK_ARITY(1);
4219 cur = valuePop(ctxt);
4220 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004221 cur = xmlXPathConvertString(cur);
4222 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004223}
4224
4225/**
4226 * xmlXPathStringLengthFunction:
4227 * @ctxt: the XPath Parser context
4228 * @nargs: the number of arguments
4229 *
4230 * Implement the string-length() XPath function
4231 * number string-length(string?)
4232 * The string-length returns the number of characters in the string
4233 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4234 * the context node converted to a string, in other words the value
4235 * of the context node.
4236 */
4237void
4238xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4239 xmlXPathObjectPtr cur;
4240
4241 if (nargs == 0) {
4242 if (ctxt->context->node == NULL) {
4243 valuePush(ctxt, xmlXPathNewFloat(0));
4244 } else {
4245 xmlChar *content;
4246
4247 content = xmlNodeGetContent(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004248 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004249 xmlFree(content);
4250 }
4251 return;
4252 }
4253 CHECK_ARITY(1);
4254 CAST_TO_STRING;
4255 CHECK_TYPE(XPATH_STRING);
4256 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004257 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004258 xmlXPathFreeObject(cur);
4259}
4260
4261/**
4262 * xmlXPathConcatFunction:
4263 * @ctxt: the XPath Parser context
4264 * @nargs: the number of arguments
4265 *
4266 * Implement the concat() XPath function
4267 * string concat(string, string, string*)
4268 * The concat function returns the concatenation of its arguments.
4269 */
4270void
4271xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4272 xmlXPathObjectPtr cur, newobj;
4273 xmlChar *tmp;
4274
4275 if (nargs < 2) {
4276 CHECK_ARITY(2);
4277 }
4278
4279 CAST_TO_STRING;
4280 cur = valuePop(ctxt);
4281 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4282 xmlXPathFreeObject(cur);
4283 return;
4284 }
4285 nargs--;
4286
4287 while (nargs > 0) {
4288 CAST_TO_STRING;
4289 newobj = valuePop(ctxt);
4290 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4291 xmlXPathFreeObject(newobj);
4292 xmlXPathFreeObject(cur);
4293 XP_ERROR(XPATH_INVALID_TYPE);
4294 }
4295 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4296 newobj->stringval = cur->stringval;
4297 cur->stringval = tmp;
4298
4299 xmlXPathFreeObject(newobj);
4300 nargs--;
4301 }
4302 valuePush(ctxt, cur);
4303}
4304
4305/**
4306 * xmlXPathContainsFunction:
4307 * @ctxt: the XPath Parser context
4308 * @nargs: the number of arguments
4309 *
4310 * Implement the contains() XPath function
4311 * boolean contains(string, string)
4312 * The contains function returns true if the first argument string
4313 * contains the second argument string, and otherwise returns false.
4314 */
4315void
4316xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4317 xmlXPathObjectPtr hay, needle;
4318
4319 CHECK_ARITY(2);
4320 CAST_TO_STRING;
4321 CHECK_TYPE(XPATH_STRING);
4322 needle = valuePop(ctxt);
4323 CAST_TO_STRING;
4324 hay = valuePop(ctxt);
4325 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4326 xmlXPathFreeObject(hay);
4327 xmlXPathFreeObject(needle);
4328 XP_ERROR(XPATH_INVALID_TYPE);
4329 }
4330 if (xmlStrstr(hay->stringval, needle->stringval))
4331 valuePush(ctxt, xmlXPathNewBoolean(1));
4332 else
4333 valuePush(ctxt, xmlXPathNewBoolean(0));
4334 xmlXPathFreeObject(hay);
4335 xmlXPathFreeObject(needle);
4336}
4337
4338/**
4339 * xmlXPathStartsWithFunction:
4340 * @ctxt: the XPath Parser context
4341 * @nargs: the number of arguments
4342 *
4343 * Implement the starts-with() XPath function
4344 * boolean starts-with(string, string)
4345 * The starts-with function returns true if the first argument string
4346 * starts with the second argument string, and otherwise returns false.
4347 */
4348void
4349xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4350 xmlXPathObjectPtr hay, needle;
4351 int n;
4352
4353 CHECK_ARITY(2);
4354 CAST_TO_STRING;
4355 CHECK_TYPE(XPATH_STRING);
4356 needle = valuePop(ctxt);
4357 CAST_TO_STRING;
4358 hay = valuePop(ctxt);
4359 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4360 xmlXPathFreeObject(hay);
4361 xmlXPathFreeObject(needle);
4362 XP_ERROR(XPATH_INVALID_TYPE);
4363 }
4364 n = xmlStrlen(needle->stringval);
4365 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4366 valuePush(ctxt, xmlXPathNewBoolean(0));
4367 else
4368 valuePush(ctxt, xmlXPathNewBoolean(1));
4369 xmlXPathFreeObject(hay);
4370 xmlXPathFreeObject(needle);
4371}
4372
4373/**
4374 * xmlXPathSubstringFunction:
4375 * @ctxt: the XPath Parser context
4376 * @nargs: the number of arguments
4377 *
4378 * Implement the substring() XPath function
4379 * string substring(string, number, number?)
4380 * The substring function returns the substring of the first argument
4381 * starting at the position specified in the second argument with
4382 * length specified in the third argument. For example,
4383 * substring("12345",2,3) returns "234". If the third argument is not
4384 * specified, it returns the substring starting at the position specified
4385 * in the second argument and continuing to the end of the string. For
4386 * example, substring("12345",2) returns "2345". More precisely, each
4387 * character in the string (see [3.6 Strings]) is considered to have a
4388 * numeric position: the position of the first character is 1, the position
4389 * of the second character is 2 and so on. The returned substring contains
4390 * those characters for which the position of the character is greater than
4391 * or equal to the second argument and, if the third argument is specified,
4392 * less than the sum of the second and third arguments; the comparisons
4393 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4394 * - substring("12345", 1.5, 2.6) returns "234"
4395 * - substring("12345", 0, 3) returns "12"
4396 * - substring("12345", 0 div 0, 3) returns ""
4397 * - substring("12345", 1, 0 div 0) returns ""
4398 * - substring("12345", -42, 1 div 0) returns "12345"
4399 * - substring("12345", -1 div 0, 1 div 0) returns ""
4400 */
4401void
4402xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4403 xmlXPathObjectPtr str, start, len;
4404 double le, in;
4405 int i, l;
4406 xmlChar *ret;
4407
4408 /*
Daniel Veillarde043ee12001-04-16 14:08:07 +00004409 * TODO: need to be converted to UTF8 strings
Owen Taylor3473f882001-02-23 17:55:21 +00004410 */
4411 if (nargs < 2) {
4412 CHECK_ARITY(2);
4413 }
4414 if (nargs > 3) {
4415 CHECK_ARITY(3);
4416 }
4417 if (nargs == 3) {
4418 CAST_TO_NUMBER;
4419 CHECK_TYPE(XPATH_NUMBER);
4420 len = valuePop(ctxt);
4421 le = len->floatval;
4422 xmlXPathFreeObject(len);
4423 } else {
4424 le = 2000000000;
4425 }
4426 CAST_TO_NUMBER;
4427 CHECK_TYPE(XPATH_NUMBER);
4428 start = valuePop(ctxt);
4429 in = start->floatval;
4430 xmlXPathFreeObject(start);
4431 CAST_TO_STRING;
4432 CHECK_TYPE(XPATH_STRING);
4433 str = valuePop(ctxt);
4434 le += in;
4435
4436 /* integer index of the first char */
4437 i = (int) in;
4438 if (((double)i) != in) i++;
4439
4440 /* integer index of the last char */
4441 l = (int) le;
4442 if (((double)l) != le) l++;
4443
4444 /* back to a zero based len */
4445 i--;
4446 l--;
4447
4448 /* check against the string len */
4449 if (l > 1024) {
4450 l = xmlStrlen(str->stringval);
4451 }
4452 if (i < 0) {
4453 i = 0;
4454 }
4455
4456 /* number of chars to copy */
4457 l -= i;
4458
4459 ret = xmlStrsub(str->stringval, i, l);
4460 if (ret == NULL)
4461 valuePush(ctxt, xmlXPathNewCString(""));
4462 else {
4463 valuePush(ctxt, xmlXPathNewString(ret));
4464 xmlFree(ret);
4465 }
4466 xmlXPathFreeObject(str);
4467}
4468
4469/**
4470 * xmlXPathSubstringBeforeFunction:
4471 * @ctxt: the XPath Parser context
4472 * @nargs: the number of arguments
4473 *
4474 * Implement the substring-before() XPath function
4475 * string substring-before(string, string)
4476 * The substring-before function returns the substring of the first
4477 * argument string that precedes the first occurrence of the second
4478 * argument string in the first argument string, or the empty string
4479 * if the first argument string does not contain the second argument
4480 * string. For example, substring-before("1999/04/01","/") returns 1999.
4481 */
4482void
4483xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4484 xmlXPathObjectPtr str;
4485 xmlXPathObjectPtr find;
4486 xmlBufferPtr target;
4487 const xmlChar *point;
4488 int offset;
4489
4490 CHECK_ARITY(2);
4491 CAST_TO_STRING;
4492 find = valuePop(ctxt);
4493 CAST_TO_STRING;
4494 str = valuePop(ctxt);
4495
4496 target = xmlBufferCreate();
4497 if (target) {
4498 point = xmlStrstr(str->stringval, find->stringval);
4499 if (point) {
4500 offset = (int)(point - str->stringval);
4501 xmlBufferAdd(target, str->stringval, offset);
4502 }
4503 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4504 xmlBufferFree(target);
4505 }
4506
4507 xmlXPathFreeObject(str);
4508 xmlXPathFreeObject(find);
4509}
4510
4511/**
4512 * xmlXPathSubstringAfterFunction:
4513 * @ctxt: the XPath Parser context
4514 * @nargs: the number of arguments
4515 *
4516 * Implement the substring-after() XPath function
4517 * string substring-after(string, string)
4518 * The substring-after function returns the substring of the first
4519 * argument string that follows the first occurrence of the second
4520 * argument string in the first argument string, or the empty stringi
4521 * if the first argument string does not contain the second argument
4522 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4523 * and substring-after("1999/04/01","19") returns 99/04/01.
4524 */
4525void
4526xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4527 xmlXPathObjectPtr str;
4528 xmlXPathObjectPtr find;
4529 xmlBufferPtr target;
4530 const xmlChar *point;
4531 int offset;
4532
4533 CHECK_ARITY(2);
4534 CAST_TO_STRING;
4535 find = valuePop(ctxt);
4536 CAST_TO_STRING;
4537 str = valuePop(ctxt);
4538
4539 target = xmlBufferCreate();
4540 if (target) {
4541 point = xmlStrstr(str->stringval, find->stringval);
4542 if (point) {
4543 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4544 xmlBufferAdd(target, &str->stringval[offset],
4545 xmlStrlen(str->stringval) - offset);
4546 }
4547 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4548 xmlBufferFree(target);
4549 }
4550
4551 xmlXPathFreeObject(str);
4552 xmlXPathFreeObject(find);
4553}
4554
4555/**
4556 * xmlXPathNormalizeFunction:
4557 * @ctxt: the XPath Parser context
4558 * @nargs: the number of arguments
4559 *
4560 * Implement the normalize-space() XPath function
4561 * string normalize-space(string?)
4562 * The normalize-space function returns the argument string with white
4563 * space normalized by stripping leading and trailing whitespace
4564 * and replacing sequences of whitespace characters by a single
4565 * space. Whitespace characters are the same allowed by the S production
4566 * in XML. If the argument is omitted, it defaults to the context
4567 * node converted to a string, in other words the value of the context node.
4568 */
4569void
4570xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4571 xmlXPathObjectPtr obj = NULL;
4572 xmlChar *source = NULL;
4573 xmlBufferPtr target;
4574 xmlChar blank;
4575
4576 if (nargs == 0) {
4577 /* Use current context node */
4578 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4579 xmlXPathStringFunction(ctxt, 1);
4580 nargs = 1;
4581 }
4582
4583 CHECK_ARITY(1);
4584 CAST_TO_STRING;
4585 CHECK_TYPE(XPATH_STRING);
4586 obj = valuePop(ctxt);
4587 source = obj->stringval;
4588
4589 target = xmlBufferCreate();
4590 if (target && source) {
4591
4592 /* Skip leading whitespaces */
4593 while (IS_BLANK(*source))
4594 source++;
4595
4596 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4597 blank = 0;
4598 while (*source) {
4599 if (IS_BLANK(*source)) {
4600 blank = *source;
4601 } else {
4602 if (blank) {
4603 xmlBufferAdd(target, &blank, 1);
4604 blank = 0;
4605 }
4606 xmlBufferAdd(target, source, 1);
4607 }
4608 source++;
4609 }
4610
4611 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4612 xmlBufferFree(target);
4613 }
4614 xmlXPathFreeObject(obj);
4615}
4616
4617/**
4618 * xmlXPathTranslateFunction:
4619 * @ctxt: the XPath Parser context
4620 * @nargs: the number of arguments
4621 *
4622 * Implement the translate() XPath function
4623 * string translate(string, string, string)
4624 * The translate function returns the first argument string with
4625 * occurrences of characters in the second argument string replaced
4626 * by the character at the corresponding position in the third argument
4627 * string. For example, translate("bar","abc","ABC") returns the string
4628 * BAr. If there is a character in the second argument string with no
4629 * character at a corresponding position in the third argument string
4630 * (because the second argument string is longer than the third argument
4631 * string), then occurrences of that character in the first argument
4632 * string are removed. For example, translate("--aaa--","abc-","ABC")
4633 * returns "AAA". If a character occurs more than once in second
4634 * argument string, then the first occurrence determines the replacement
4635 * character. If the third argument string is longer than the second
4636 * argument string, then excess characters are ignored.
4637 */
4638void
4639xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00004640 xmlXPathObjectPtr str;
4641 xmlXPathObjectPtr from;
4642 xmlXPathObjectPtr to;
4643 xmlBufferPtr target;
4644 int i, offset, max;
4645 xmlChar ch;
4646 const xmlChar *point;
Owen Taylor3473f882001-02-23 17:55:21 +00004647
Daniel Veillarde043ee12001-04-16 14:08:07 +00004648 /*
4649 * TODO: need to be converted to UTF8 strings
4650 */
4651 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00004652
Daniel Veillarde043ee12001-04-16 14:08:07 +00004653 CAST_TO_STRING;
4654 to = valuePop(ctxt);
4655 CAST_TO_STRING;
4656 from = valuePop(ctxt);
4657 CAST_TO_STRING;
4658 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004659
Daniel Veillarde043ee12001-04-16 14:08:07 +00004660 target = xmlBufferCreate();
4661 if (target) {
4662 max = xmlStrlen(to->stringval);
4663 for (i = 0; (ch = str->stringval[i]); i++) {
4664 point = xmlStrchr(from->stringval, ch);
4665 if (point) {
4666 offset = (int)(point - from->stringval);
4667 if (offset < max)
4668 xmlBufferAdd(target, &to->stringval[offset], 1);
4669 } else
4670 xmlBufferAdd(target, &ch, 1);
4671 }
Owen Taylor3473f882001-02-23 17:55:21 +00004672 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00004673 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4674 xmlBufferFree(target);
4675 xmlXPathFreeObject(str);
4676 xmlXPathFreeObject(from);
4677 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00004678}
4679
4680/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004681 * xmlXPathConvertBoolean:
4682 * @val: an XPath object
4683 *
4684 * Converts an existing object to its boolean() equivalent
4685 *
4686 * Returns the new object, the old one is freed (or the operation
4687 * is done directly on @val)
4688 */
4689xmlXPathObjectPtr
4690xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4691 int res = 0;
4692
4693 if (val == NULL)
4694 return(NULL);
4695 switch (val->type) {
4696 case XPATH_NODESET:
4697 case XPATH_XSLT_TREE:
4698 if ((val->nodesetval == NULL) ||
4699 (val->nodesetval->nodeNr == 0)) res = 0;
4700 else
4701 res = 1;
4702 break;
4703 case XPATH_STRING:
4704 if ((val->stringval == NULL) ||
4705 (val->stringval[0] == 0)) res = 0;
4706 else
4707 res = 1;
4708 break;
4709 case XPATH_BOOLEAN:
4710 return(val);
4711 case XPATH_NUMBER:
4712 if (val->floatval) res = 1;
4713 break;
4714 default:
4715 STRANGE
4716 }
4717 xmlXPathFreeObject(val);
4718 return(xmlXPathNewBoolean(res));
4719}
4720
4721/**
Owen Taylor3473f882001-02-23 17:55:21 +00004722 * xmlXPathBooleanFunction:
4723 * @ctxt: the XPath Parser context
4724 * @nargs: the number of arguments
4725 *
4726 * Implement the boolean() XPath function
4727 * boolean boolean(object)
4728 * he boolean function converts its argument to a boolean as follows:
4729 * - a number is true if and only if it is neither positive or
4730 * negative zero nor NaN
4731 * - a node-set is true if and only if it is non-empty
4732 * - a string is true if and only if its length is non-zero
4733 */
4734void
4735xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4736 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00004737
4738 CHECK_ARITY(1);
4739 cur = valuePop(ctxt);
4740 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004741 cur = xmlXPathConvertBoolean(cur);
4742 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004743}
4744
4745/**
4746 * xmlXPathNotFunction:
4747 * @ctxt: the XPath Parser context
4748 * @nargs: the number of arguments
4749 *
4750 * Implement the not() XPath function
4751 * boolean not(boolean)
4752 * The not function returns true if its argument is false,
4753 * and false otherwise.
4754 */
4755void
4756xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4757 CHECK_ARITY(1);
4758 CAST_TO_BOOLEAN;
4759 CHECK_TYPE(XPATH_BOOLEAN);
4760 ctxt->value->boolval = ! ctxt->value->boolval;
4761}
4762
4763/**
4764 * xmlXPathTrueFunction:
4765 * @ctxt: the XPath Parser context
4766 * @nargs: the number of arguments
4767 *
4768 * Implement the true() XPath function
4769 * boolean true()
4770 */
4771void
4772xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4773 CHECK_ARITY(0);
4774 valuePush(ctxt, xmlXPathNewBoolean(1));
4775}
4776
4777/**
4778 * xmlXPathFalseFunction:
4779 * @ctxt: the XPath Parser context
4780 * @nargs: the number of arguments
4781 *
4782 * Implement the false() XPath function
4783 * boolean false()
4784 */
4785void
4786xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4787 CHECK_ARITY(0);
4788 valuePush(ctxt, xmlXPathNewBoolean(0));
4789}
4790
4791/**
4792 * xmlXPathLangFunction:
4793 * @ctxt: the XPath Parser context
4794 * @nargs: the number of arguments
4795 *
4796 * Implement the lang() XPath function
4797 * boolean lang(string)
4798 * The lang function returns true or false depending on whether the
4799 * language of the context node as specified by xml:lang attributes
4800 * is the same as or is a sublanguage of the language specified by
4801 * the argument string. The language of the context node is determined
4802 * by the value of the xml:lang attribute on the context node, or, if
4803 * the context node has no xml:lang attribute, by the value of the
4804 * xml:lang attribute on the nearest ancestor of the context node that
4805 * has an xml:lang attribute. If there is no such attribute, then lang
4806 * returns false. If there is such an attribute, then lang returns
4807 * true if the attribute value is equal to the argument ignoring case,
4808 * or if there is some suffix starting with - such that the attribute
4809 * value is equal to the argument ignoring that suffix of the attribute
4810 * value and ignoring case.
4811 */
4812void
4813xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4814 xmlXPathObjectPtr val;
4815 const xmlChar *theLang;
4816 const xmlChar *lang;
4817 int ret = 0;
4818 int i;
4819
4820 CHECK_ARITY(1);
4821 CAST_TO_STRING;
4822 CHECK_TYPE(XPATH_STRING);
4823 val = valuePop(ctxt);
4824 lang = val->stringval;
4825 theLang = xmlNodeGetLang(ctxt->context->node);
4826 if ((theLang != NULL) && (lang != NULL)) {
4827 for (i = 0;lang[i] != 0;i++)
4828 if (toupper(lang[i]) != toupper(theLang[i]))
4829 goto not_equal;
4830 ret = 1;
4831 }
4832not_equal:
4833 xmlXPathFreeObject(val);
4834 valuePush(ctxt, xmlXPathNewBoolean(ret));
4835}
4836
4837/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004838 * xmlXPathConvertNumber:
4839 * @val: an XPath object
4840 *
4841 * Converts an existing object to its number() equivalent
4842 *
4843 * Returns the new object, the old one is freed (or the operation
4844 * is done directly on @val)
4845 */
4846xmlXPathObjectPtr
4847xmlXPathConvertNumber(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004848 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004849 double res;
4850
4851 if (val == NULL)
4852 return(xmlXPathNewFloat(0.0));
4853 switch (val->type) {
4854 case XPATH_UNDEFINED:
4855#ifdef DEBUG_EXPR
4856 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
4857#endif
4858 ret = xmlXPathNewFloat(0.0);
4859 break;
4860 case XPATH_XSLT_TREE:
4861 case XPATH_NODESET:
4862 val = xmlXPathConvertString(val);
4863 /* no break on purpose */
4864 case XPATH_STRING:
4865 res = xmlXPathStringEvalNumber(val->stringval);
4866 ret = xmlXPathNewFloat(res);
4867 break;
4868 case XPATH_BOOLEAN:
4869 if (val->boolval) ret = xmlXPathNewFloat(1.0);
4870 else ret = xmlXPathNewFloat(0.0);
4871 break;
4872 case XPATH_NUMBER:
4873 return(val);
4874 case XPATH_USERS:
4875 case XPATH_POINT:
4876 case XPATH_RANGE:
4877 case XPATH_LOCATIONSET:
4878 TODO
4879 ret = xmlXPathNewFloat(0.0);
4880 break;
4881 }
4882 xmlXPathFreeObject(val);
4883 return(ret);
4884}
4885
4886/**
Owen Taylor3473f882001-02-23 17:55:21 +00004887 * xmlXPathNumberFunction:
4888 * @ctxt: the XPath Parser context
4889 * @nargs: the number of arguments
4890 *
4891 * Implement the number() XPath function
4892 * number number(object?)
4893 */
4894void
4895xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4896 xmlXPathObjectPtr cur;
4897 double res;
4898
4899 if (nargs == 0) {
4900 if (ctxt->context->node == NULL) {
4901 valuePush(ctxt, xmlXPathNewFloat(0.0));
4902 } else {
4903 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
4904
4905 res = xmlXPathStringEvalNumber(content);
4906 valuePush(ctxt, xmlXPathNewFloat(res));
4907 xmlFree(content);
4908 }
4909 return;
4910 }
4911
4912 CHECK_ARITY(1);
4913 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004914 cur = xmlXPathConvertNumber(cur);
4915 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004916}
4917
4918/**
4919 * xmlXPathSumFunction:
4920 * @ctxt: the XPath Parser context
4921 * @nargs: the number of arguments
4922 *
4923 * Implement the sum() XPath function
4924 * number sum(node-set)
4925 * The sum function returns the sum of the values of the nodes in
4926 * the argument node-set.
4927 */
4928void
4929xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4930 xmlXPathObjectPtr cur;
4931 int i;
4932
4933 CHECK_ARITY(1);
4934 if ((ctxt->value == NULL) ||
4935 ((ctxt->value->type != XPATH_NODESET) &&
4936 (ctxt->value->type != XPATH_XSLT_TREE)))
4937 XP_ERROR(XPATH_INVALID_TYPE);
4938 cur = valuePop(ctxt);
4939
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004940 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004941 valuePush(ctxt, xmlXPathNewFloat(0.0));
4942 } else {
4943 valuePush(ctxt,
4944 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
4945 xmlXPathNumberFunction(ctxt, 1);
4946 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
4947 valuePush(ctxt,
4948 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4949 xmlXPathAddValues(ctxt);
4950 }
4951 }
4952 xmlXPathFreeObject(cur);
4953}
4954
4955/**
4956 * xmlXPathFloorFunction:
4957 * @ctxt: the XPath Parser context
4958 * @nargs: the number of arguments
4959 *
4960 * Implement the floor() XPath function
4961 * number floor(number)
4962 * The floor function returns the largest (closest to positive infinity)
4963 * number that is not greater than the argument and that is an integer.
4964 */
4965void
4966xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4967 CHECK_ARITY(1);
4968 CAST_TO_NUMBER;
4969 CHECK_TYPE(XPATH_NUMBER);
4970#if 0
4971 ctxt->value->floatval = floor(ctxt->value->floatval);
4972#else
4973 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
4974 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
4975#endif
4976}
4977
4978/**
4979 * xmlXPathCeilingFunction:
4980 * @ctxt: the XPath Parser context
4981 * @nargs: the number of arguments
4982 *
4983 * Implement the ceiling() XPath function
4984 * number ceiling(number)
4985 * The ceiling function returns the smallest (closest to negative infinity)
4986 * number that is not less than the argument and that is an integer.
4987 */
4988void
4989xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4990 double f;
4991
4992 CHECK_ARITY(1);
4993 CAST_TO_NUMBER;
4994 CHECK_TYPE(XPATH_NUMBER);
4995
4996#if 0
4997 ctxt->value->floatval = ceil(ctxt->value->floatval);
4998#else
4999 f = (double)((int) ctxt->value->floatval);
5000 if (f != ctxt->value->floatval)
5001 ctxt->value->floatval = f + 1;
5002#endif
5003}
5004
5005/**
5006 * xmlXPathRoundFunction:
5007 * @ctxt: the XPath Parser context
5008 * @nargs: the number of arguments
5009 *
5010 * Implement the round() XPath function
5011 * number round(number)
5012 * The round function returns the number that is closest to the
5013 * argument and that is an integer. If there are two such numbers,
5014 * then the one that is even is returned.
5015 */
5016void
5017xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5018 double f;
5019
5020 CHECK_ARITY(1);
5021 CAST_TO_NUMBER;
5022 CHECK_TYPE(XPATH_NUMBER);
5023
5024 if ((ctxt->value->floatval == xmlXPathNAN) ||
5025 (ctxt->value->floatval == xmlXPathPINF) ||
5026 (ctxt->value->floatval == xmlXPathNINF) ||
5027 (ctxt->value->floatval == 0.0))
5028 return;
5029
5030#if 0
5031 f = floor(ctxt->value->floatval);
5032#else
5033 f = (double)((int) ctxt->value->floatval);
5034#endif
5035 if (ctxt->value->floatval < f + 0.5)
5036 ctxt->value->floatval = f;
5037 else
5038 ctxt->value->floatval = f + 1;
5039}
5040
5041/************************************************************************
5042 * *
5043 * The Parser *
5044 * *
5045 ************************************************************************/
5046
5047/*
5048 * a couple of forward declarations since we use a recursive call based
5049 * implementation.
5050 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005051static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005052static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005053static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005054#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005055static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5056#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005057#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005058static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005059#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005060static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5061 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005062
5063/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005064 * xmlXPathCurrentChar:
5065 * @ctxt: the XPath parser context
5066 * @cur: pointer to the beginning of the char
5067 * @len: pointer to the length of the char read
5068 *
5069 * The current char value, if using UTF-8 this may actaully span multiple
5070 * bytes in the input buffer.
5071 *
5072 * Returns the current char value and its lenght
5073 */
5074
5075static int
5076xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5077 unsigned char c;
5078 unsigned int val;
5079 const xmlChar *cur;
5080
5081 if (ctxt == NULL)
5082 return(0);
5083 cur = ctxt->cur;
5084
5085 /*
5086 * We are supposed to handle UTF8, check it's valid
5087 * From rfc2044: encoding of the Unicode values on UTF-8:
5088 *
5089 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5090 * 0000 0000-0000 007F 0xxxxxxx
5091 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5092 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5093 *
5094 * Check for the 0x110000 limit too
5095 */
5096 c = *cur;
5097 if (c & 0x80) {
5098 if ((cur[1] & 0xc0) != 0x80)
5099 goto encoding_error;
5100 if ((c & 0xe0) == 0xe0) {
5101
5102 if ((cur[2] & 0xc0) != 0x80)
5103 goto encoding_error;
5104 if ((c & 0xf0) == 0xf0) {
5105 if (((c & 0xf8) != 0xf0) ||
5106 ((cur[3] & 0xc0) != 0x80))
5107 goto encoding_error;
5108 /* 4-byte code */
5109 *len = 4;
5110 val = (cur[0] & 0x7) << 18;
5111 val |= (cur[1] & 0x3f) << 12;
5112 val |= (cur[2] & 0x3f) << 6;
5113 val |= cur[3] & 0x3f;
5114 } else {
5115 /* 3-byte code */
5116 *len = 3;
5117 val = (cur[0] & 0xf) << 12;
5118 val |= (cur[1] & 0x3f) << 6;
5119 val |= cur[2] & 0x3f;
5120 }
5121 } else {
5122 /* 2-byte code */
5123 *len = 2;
5124 val = (cur[0] & 0x1f) << 6;
5125 val |= cur[1] & 0x3f;
5126 }
5127 if (!IS_CHAR(val)) {
5128 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5129 }
5130 return(val);
5131 } else {
5132 /* 1-byte code */
5133 *len = 1;
5134 return((int) *cur);
5135 }
5136encoding_error:
5137 /*
5138 * If we detect an UTF8 error that probably mean that the
5139 * input encoding didn't get properly advertized in the
5140 * declaration header. Report the error and switch the encoding
5141 * to ISO-Latin-1 (if you don't like this policy, just declare the
5142 * encoding !)
5143 */
5144 XP_ERROR0(XPATH_ENCODING_ERROR);
5145 *len = 1;
5146 return((int) *cur);
5147}
5148
5149/**
Owen Taylor3473f882001-02-23 17:55:21 +00005150 * xmlXPathParseNCName:
5151 * @ctxt: the XPath Parser context
5152 *
5153 * parse an XML namespace non qualified name.
5154 *
5155 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5156 *
5157 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5158 * CombiningChar | Extender
5159 *
5160 * Returns the namespace name or NULL
5161 */
5162
5163xmlChar *
5164xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005165 const xmlChar *in;
5166 xmlChar *ret;
5167 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005168
Daniel Veillard2156a562001-04-28 12:24:34 +00005169 /*
5170 * Accelerator for simple ASCII names
5171 */
5172 in = ctxt->cur;
5173 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5174 ((*in >= 0x41) && (*in <= 0x5A)) ||
5175 (*in == '_')) {
5176 in++;
5177 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5178 ((*in >= 0x41) && (*in <= 0x5A)) ||
5179 ((*in >= 0x30) && (*in <= 0x39)) ||
5180 (*in == '_'))
5181 in++;
5182 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5183 (*in == '[') || (*in == ']') || (*in == ':') ||
5184 (*in == '@') || (*in == '*')) {
5185 count = in - ctxt->cur;
5186 if (count == 0)
5187 return(NULL);
5188 ret = xmlStrndup(ctxt->cur, count);
5189 ctxt->cur = in;
5190 return(ret);
5191 }
5192 }
5193 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005194}
5195
Daniel Veillard2156a562001-04-28 12:24:34 +00005196
Owen Taylor3473f882001-02-23 17:55:21 +00005197/**
5198 * xmlXPathParseQName:
5199 * @ctxt: the XPath Parser context
5200 * @prefix: a xmlChar **
5201 *
5202 * parse an XML qualified name
5203 *
5204 * [NS 5] QName ::= (Prefix ':')? LocalPart
5205 *
5206 * [NS 6] Prefix ::= NCName
5207 *
5208 * [NS 7] LocalPart ::= NCName
5209 *
5210 * Returns the function returns the local part, and prefix is updated
5211 * to get the Prefix if any.
5212 */
5213
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005214static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005215xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5216 xmlChar *ret = NULL;
5217
5218 *prefix = NULL;
5219 ret = xmlXPathParseNCName(ctxt);
5220 if (CUR == ':') {
5221 *prefix = ret;
5222 NEXT;
5223 ret = xmlXPathParseNCName(ctxt);
5224 }
5225 return(ret);
5226}
5227
5228/**
5229 * xmlXPathParseName:
5230 * @ctxt: the XPath Parser context
5231 *
5232 * parse an XML name
5233 *
5234 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5235 * CombiningChar | Extender
5236 *
5237 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5238 *
5239 * Returns the namespace name or NULL
5240 */
5241
5242xmlChar *
5243xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005244 const xmlChar *in;
5245 xmlChar *ret;
5246 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005247
Daniel Veillard61d80a22001-04-27 17:13:01 +00005248 /*
5249 * Accelerator for simple ASCII names
5250 */
5251 in = ctxt->cur;
5252 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5253 ((*in >= 0x41) && (*in <= 0x5A)) ||
5254 (*in == '_') || (*in == ':')) {
5255 in++;
5256 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5257 ((*in >= 0x41) && (*in <= 0x5A)) ||
5258 ((*in >= 0x30) && (*in <= 0x39)) ||
5259 (*in == '_') || (*in == ':'))
5260 in++;
5261 if ((*in == ' ') || (*in == '>') || (*in == '/')) {
5262 count = in - ctxt->cur;
5263 ret = xmlStrndup(ctxt->cur, count);
5264 ctxt->cur = in;
5265 return(ret);
5266 }
5267 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005268 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005269}
5270
Daniel Veillard61d80a22001-04-27 17:13:01 +00005271static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005272xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005273 xmlChar buf[XML_MAX_NAMELEN + 5];
5274 int len = 0, l;
5275 int c;
5276
5277 /*
5278 * Handler for more complex cases
5279 */
5280 c = CUR_CHAR(l);
5281 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005282 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5283 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005284 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005285 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005286 return(NULL);
5287 }
5288
5289 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5290 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5291 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005292 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005293 (IS_COMBINING(c)) ||
5294 (IS_EXTENDER(c)))) {
5295 COPY_BUF(l,buf,len,c);
5296 NEXTL(l);
5297 c = CUR_CHAR(l);
5298 if (len >= XML_MAX_NAMELEN) {
5299 /*
5300 * Okay someone managed to make a huge name, so he's ready to pay
5301 * for the processing speed.
5302 */
5303 xmlChar *buffer;
5304 int max = len * 2;
5305
5306 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5307 if (buffer == NULL) {
5308 XP_ERROR0(XPATH_MEMORY_ERROR);
5309 }
5310 memcpy(buffer, buf, len);
5311 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5312 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005313 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005314 (IS_COMBINING(c)) ||
5315 (IS_EXTENDER(c))) {
5316 if (len + 10 > max) {
5317 max *= 2;
5318 buffer = (xmlChar *) xmlRealloc(buffer,
5319 max * sizeof(xmlChar));
5320 XP_ERROR0(XPATH_MEMORY_ERROR);
5321 if (buffer == NULL) {
5322 XP_ERROR0(XPATH_MEMORY_ERROR);
5323 }
5324 }
5325 COPY_BUF(l,buffer,len,c);
5326 NEXTL(l);
5327 c = CUR_CHAR(l);
5328 }
5329 buffer[len] = 0;
5330 return(buffer);
5331 }
5332 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005333 if (len == 0)
5334 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005335 return(xmlStrndup(buf, len));
5336}
Owen Taylor3473f882001-02-23 17:55:21 +00005337/**
5338 * xmlXPathStringEvalNumber:
5339 * @str: A string to scan
5340 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005341 * [30a] Float ::= Number ('e' Digits?)?
5342 *
Owen Taylor3473f882001-02-23 17:55:21 +00005343 * [30] Number ::= Digits ('.' Digits?)?
5344 * | '.' Digits
5345 * [31] Digits ::= [0-9]+
5346 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005347 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005348 * In complement of the Number expression, this function also handles
5349 * negative values : '-' Number.
5350 *
5351 * Returns the double value.
5352 */
5353double
5354xmlXPathStringEvalNumber(const xmlChar *str) {
5355 const xmlChar *cur = str;
5356 double ret = 0.0;
5357 double mult = 1;
5358 int ok = 0;
5359 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005360 int exponent = 0;
5361 int is_exponent_negative = 0;
5362
Owen Taylor3473f882001-02-23 17:55:21 +00005363 while (IS_BLANK(*cur)) cur++;
5364 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5365 return(xmlXPathNAN);
5366 }
5367 if (*cur == '-') {
5368 isneg = 1;
5369 cur++;
5370 }
5371 while ((*cur >= '0') && (*cur <= '9')) {
5372 ret = ret * 10 + (*cur - '0');
5373 ok = 1;
5374 cur++;
5375 }
5376 if (*cur == '.') {
5377 cur++;
5378 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5379 return(xmlXPathNAN);
5380 }
5381 while ((*cur >= '0') && (*cur <= '9')) {
5382 mult /= 10;
5383 ret = ret + (*cur - '0') * mult;
5384 cur++;
5385 }
5386 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005387 if ((*cur == 'e') || (*cur == 'E')) {
5388 cur++;
5389 if (*cur == '-') {
5390 is_exponent_negative = 1;
5391 cur++;
5392 }
5393 while ((*cur >= '0') && (*cur <= '9')) {
5394 exponent = exponent * 10 + (*cur - '0');
5395 cur++;
5396 }
5397 }
Owen Taylor3473f882001-02-23 17:55:21 +00005398 while (IS_BLANK(*cur)) cur++;
5399 if (*cur != 0) return(xmlXPathNAN);
5400 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005401 if (is_exponent_negative) exponent = -exponent;
5402 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005403 return(ret);
5404}
5405
5406/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005407 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005408 * @ctxt: the XPath Parser context
5409 *
5410 * [30] Number ::= Digits ('.' Digits?)?
5411 * | '.' Digits
5412 * [31] Digits ::= [0-9]+
5413 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005414 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005415 *
5416 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005417static void
5418xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005419 double ret = 0.0;
5420 double mult = 1;
5421 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005422 int exponent = 0;
5423 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005424
5425 CHECK_ERROR;
5426 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5427 XP_ERROR(XPATH_NUMBER_ERROR);
5428 }
5429 while ((CUR >= '0') && (CUR <= '9')) {
5430 ret = ret * 10 + (CUR - '0');
5431 ok = 1;
5432 NEXT;
5433 }
5434 if (CUR == '.') {
5435 NEXT;
5436 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5437 XP_ERROR(XPATH_NUMBER_ERROR);
5438 }
5439 while ((CUR >= '0') && (CUR <= '9')) {
5440 mult /= 10;
5441 ret = ret + (CUR - '0') * mult;
5442 NEXT;
5443 }
5444 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005445 if ((CUR == 'e') || (CUR == 'E')) {
5446 NEXT;
5447 if (CUR == '-') {
5448 is_exponent_negative = 1;
5449 NEXT;
5450 }
5451 while ((CUR >= '0') && (CUR <= '9')) {
5452 exponent = exponent * 10 + (CUR - '0');
5453 NEXT;
5454 }
5455 }
5456 if (is_exponent_negative)
5457 exponent = -exponent;
5458 ret *= pow(10.0, (double)exponent);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005459 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5460 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005461}
5462
5463/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005464 * xmlXPathParseLiteral:
5465 * @ctxt: the XPath Parser context
5466 *
5467 * Parse a Literal
5468 *
5469 * [29] Literal ::= '"' [^"]* '"'
5470 * | "'" [^']* "'"
5471 *
5472 * Returns the value found or NULL in case of error
5473 */
5474static xmlChar *
5475xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5476 const xmlChar *q;
5477 xmlChar *ret = NULL;
5478
5479 if (CUR == '"') {
5480 NEXT;
5481 q = CUR_PTR;
5482 while ((IS_CHAR(CUR)) && (CUR != '"'))
5483 NEXT;
5484 if (!IS_CHAR(CUR)) {
5485 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5486 } else {
5487 ret = xmlStrndup(q, CUR_PTR - q);
5488 NEXT;
5489 }
5490 } else if (CUR == '\'') {
5491 NEXT;
5492 q = CUR_PTR;
5493 while ((IS_CHAR(CUR)) && (CUR != '\''))
5494 NEXT;
5495 if (!IS_CHAR(CUR)) {
5496 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5497 } else {
5498 ret = xmlStrndup(q, CUR_PTR - q);
5499 NEXT;
5500 }
5501 } else {
5502 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5503 }
5504 return(ret);
5505}
5506
5507/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005508 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005509 * @ctxt: the XPath Parser context
5510 *
5511 * Parse a Literal and push it on the stack.
5512 *
5513 * [29] Literal ::= '"' [^"]* '"'
5514 * | "'" [^']* "'"
5515 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005516 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005517 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005518static void
5519xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005520 const xmlChar *q;
5521 xmlChar *ret = NULL;
5522
5523 if (CUR == '"') {
5524 NEXT;
5525 q = CUR_PTR;
5526 while ((IS_CHAR(CUR)) && (CUR != '"'))
5527 NEXT;
5528 if (!IS_CHAR(CUR)) {
5529 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5530 } else {
5531 ret = xmlStrndup(q, CUR_PTR - q);
5532 NEXT;
5533 }
5534 } else if (CUR == '\'') {
5535 NEXT;
5536 q = CUR_PTR;
5537 while ((IS_CHAR(CUR)) && (CUR != '\''))
5538 NEXT;
5539 if (!IS_CHAR(CUR)) {
5540 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5541 } else {
5542 ret = xmlStrndup(q, CUR_PTR - q);
5543 NEXT;
5544 }
5545 } else {
5546 XP_ERROR(XPATH_START_LITERAL_ERROR);
5547 }
5548 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005549 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5550 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005551 xmlFree(ret);
5552}
5553
5554/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005555 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005556 * @ctxt: the XPath Parser context
5557 *
5558 * Parse a VariableReference, evaluate it and push it on the stack.
5559 *
5560 * The variable bindings consist of a mapping from variable names
5561 * to variable values. The value of a variable is an object, which
5562 * of any of the types that are possible for the value of an expression,
5563 * and may also be of additional types not specified here.
5564 *
5565 * Early evaluation is possible since:
5566 * The variable bindings [...] used to evaluate a subexpression are
5567 * always the same as those used to evaluate the containing expression.
5568 *
5569 * [36] VariableReference ::= '$' QName
5570 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005571static void
5572xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005573 xmlChar *name;
5574 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005575
5576 SKIP_BLANKS;
5577 if (CUR != '$') {
5578 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5579 }
5580 NEXT;
5581 name = xmlXPathParseQName(ctxt, &prefix);
5582 if (name == NULL) {
5583 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5584 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005585 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005586 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5587 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005588 SKIP_BLANKS;
5589}
5590
5591/**
5592 * xmlXPathIsNodeType:
5593 * @ctxt: the XPath Parser context
5594 * @name: a name string
5595 *
5596 * Is the name given a NodeType one.
5597 *
5598 * [38] NodeType ::= 'comment'
5599 * | 'text'
5600 * | 'processing-instruction'
5601 * | 'node'
5602 *
5603 * Returns 1 if true 0 otherwise
5604 */
5605int
5606xmlXPathIsNodeType(const xmlChar *name) {
5607 if (name == NULL)
5608 return(0);
5609
5610 if (xmlStrEqual(name, BAD_CAST "comment"))
5611 return(1);
5612 if (xmlStrEqual(name, BAD_CAST "text"))
5613 return(1);
5614 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5615 return(1);
5616 if (xmlStrEqual(name, BAD_CAST "node"))
5617 return(1);
5618 return(0);
5619}
5620
5621/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005622 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005623 * @ctxt: the XPath Parser context
5624 *
5625 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5626 * [17] Argument ::= Expr
5627 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005628 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00005629 * pushed on the stack
5630 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005631static void
5632xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005633 xmlChar *name;
5634 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005635 int nbargs = 0;
5636
5637 name = xmlXPathParseQName(ctxt, &prefix);
5638 if (name == NULL) {
5639 XP_ERROR(XPATH_EXPR_ERROR);
5640 }
5641 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005642#ifdef DEBUG_EXPR
5643 if (prefix == NULL)
5644 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5645 name);
5646 else
5647 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5648 prefix, name);
5649#endif
5650
Owen Taylor3473f882001-02-23 17:55:21 +00005651 if (CUR != '(') {
5652 XP_ERROR(XPATH_EXPR_ERROR);
5653 }
5654 NEXT;
5655 SKIP_BLANKS;
5656
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005657 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005658 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005659 int op1 = ctxt->comp->last;
5660 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005661 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005662 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005663 nbargs++;
5664 if (CUR == ')') break;
5665 if (CUR != ',') {
5666 XP_ERROR(XPATH_EXPR_ERROR);
5667 }
5668 NEXT;
5669 SKIP_BLANKS;
5670 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005671 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
5672 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005673 NEXT;
5674 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005675}
5676
5677/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005678 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005679 * @ctxt: the XPath Parser context
5680 *
5681 * [15] PrimaryExpr ::= VariableReference
5682 * | '(' Expr ')'
5683 * | Literal
5684 * | Number
5685 * | FunctionCall
5686 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005687 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005688 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005689static void
5690xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005691 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005692 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005693 else if (CUR == '(') {
5694 NEXT;
5695 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005696 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005697 if (CUR != ')') {
5698 XP_ERROR(XPATH_EXPR_ERROR);
5699 }
5700 NEXT;
5701 SKIP_BLANKS;
5702 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005703 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005704 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005705 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005706 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005707 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005708 }
5709 SKIP_BLANKS;
5710}
5711
5712/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005713 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005714 * @ctxt: the XPath Parser context
5715 *
5716 * [20] FilterExpr ::= PrimaryExpr
5717 * | FilterExpr Predicate
5718 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005719 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005720 * Square brackets are used to filter expressions in the same way that
5721 * they are used in location paths. It is an error if the expression to
5722 * be filtered does not evaluate to a node-set. The context node list
5723 * used for evaluating the expression in square brackets is the node-set
5724 * to be filtered listed in document order.
5725 */
5726
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005727static void
5728xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
5729 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005730 CHECK_ERROR;
5731 SKIP_BLANKS;
5732
5733 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005734 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00005735 SKIP_BLANKS;
5736 }
5737
5738
5739}
5740
5741/**
5742 * xmlXPathScanName:
5743 * @ctxt: the XPath Parser context
5744 *
5745 * Trickery: parse an XML name but without consuming the input flow
5746 * Needed to avoid insanity in the parser state.
5747 *
5748 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5749 * CombiningChar | Extender
5750 *
5751 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5752 *
5753 * [6] Names ::= Name (S Name)*
5754 *
5755 * Returns the Name parsed or NULL
5756 */
5757
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005758static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005759xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
5760 xmlChar buf[XML_MAX_NAMELEN];
5761 int len = 0;
5762
5763 SKIP_BLANKS;
5764 if (!IS_LETTER(CUR) && (CUR != '_') &&
5765 (CUR != ':')) {
5766 return(NULL);
5767 }
5768
5769 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5770 (NXT(len) == '.') || (NXT(len) == '-') ||
5771 (NXT(len) == '_') || (NXT(len) == ':') ||
5772 (IS_COMBINING(NXT(len))) ||
5773 (IS_EXTENDER(NXT(len)))) {
5774 buf[len] = NXT(len);
5775 len++;
5776 if (len >= XML_MAX_NAMELEN) {
5777 xmlGenericError(xmlGenericErrorContext,
5778 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5779 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5780 (NXT(len) == '.') || (NXT(len) == '-') ||
5781 (NXT(len) == '_') || (NXT(len) == ':') ||
5782 (IS_COMBINING(NXT(len))) ||
5783 (IS_EXTENDER(NXT(len))))
5784 len++;
5785 break;
5786 }
5787 }
5788 return(xmlStrndup(buf, len));
5789}
5790
5791/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005792 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005793 * @ctxt: the XPath Parser context
5794 *
5795 * [19] PathExpr ::= LocationPath
5796 * | FilterExpr
5797 * | FilterExpr '/' RelativeLocationPath
5798 * | FilterExpr '//' RelativeLocationPath
5799 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005800 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005801 * The / operator and // operators combine an arbitrary expression
5802 * and a relative location path. It is an error if the expression
5803 * does not evaluate to a node-set.
5804 * The / operator does composition in the same way as when / is
5805 * used in a location path. As in location paths, // is short for
5806 * /descendant-or-self::node()/.
5807 */
5808
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005809static void
5810xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005811 int lc = 1; /* Should we branch to LocationPath ? */
5812 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5813
5814 SKIP_BLANKS;
5815 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5816 (CUR == '\'') || (CUR == '"')) {
5817 lc = 0;
5818 } else if (CUR == '*') {
5819 /* relative or absolute location path */
5820 lc = 1;
5821 } else if (CUR == '/') {
5822 /* relative or absolute location path */
5823 lc = 1;
5824 } else if (CUR == '@') {
5825 /* relative abbreviated attribute location path */
5826 lc = 1;
5827 } else if (CUR == '.') {
5828 /* relative abbreviated attribute location path */
5829 lc = 1;
5830 } else {
5831 /*
5832 * Problem is finding if we have a name here whether it's:
5833 * - a nodetype
5834 * - a function call in which case it's followed by '('
5835 * - an axis in which case it's followed by ':'
5836 * - a element name
5837 * We do an a priori analysis here rather than having to
5838 * maintain parsed token content through the recursive function
5839 * calls. This looks uglier but makes the code quite easier to
5840 * read/write/debug.
5841 */
5842 SKIP_BLANKS;
5843 name = xmlXPathScanName(ctxt);
5844 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
5845#ifdef DEBUG_STEP
5846 xmlGenericError(xmlGenericErrorContext,
5847 "PathExpr: Axis\n");
5848#endif
5849 lc = 1;
5850 xmlFree(name);
5851 } else if (name != NULL) {
5852 int len =xmlStrlen(name);
5853 int blank = 0;
5854
5855
5856 while (NXT(len) != 0) {
5857 if (NXT(len) == '/') {
5858 /* element name */
5859#ifdef DEBUG_STEP
5860 xmlGenericError(xmlGenericErrorContext,
5861 "PathExpr: AbbrRelLocation\n");
5862#endif
5863 lc = 1;
5864 break;
5865 } else if (IS_BLANK(NXT(len))) {
5866 /* skip to next */
5867 blank = 1;
5868 } else if (NXT(len) == ':') {
5869#ifdef DEBUG_STEP
5870 xmlGenericError(xmlGenericErrorContext,
5871 "PathExpr: AbbrRelLocation\n");
5872#endif
5873 lc = 1;
5874 break;
5875 } else if ((NXT(len) == '(')) {
5876 /* Note Type or Function */
5877 if (xmlXPathIsNodeType(name)) {
5878#ifdef DEBUG_STEP
5879 xmlGenericError(xmlGenericErrorContext,
5880 "PathExpr: Type search\n");
5881#endif
5882 lc = 1;
5883 } else {
5884#ifdef DEBUG_STEP
5885 xmlGenericError(xmlGenericErrorContext,
5886 "PathExpr: function call\n");
5887#endif
5888 lc = 0;
5889 }
5890 break;
5891 } else if ((NXT(len) == '[')) {
5892 /* element name */
5893#ifdef DEBUG_STEP
5894 xmlGenericError(xmlGenericErrorContext,
5895 "PathExpr: AbbrRelLocation\n");
5896#endif
5897 lc = 1;
5898 break;
5899 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5900 (NXT(len) == '=')) {
5901 lc = 1;
5902 break;
5903 } else {
5904 lc = 1;
5905 break;
5906 }
5907 len++;
5908 }
5909 if (NXT(len) == 0) {
5910#ifdef DEBUG_STEP
5911 xmlGenericError(xmlGenericErrorContext,
5912 "PathExpr: AbbrRelLocation\n");
5913#endif
5914 /* element name */
5915 lc = 1;
5916 }
5917 xmlFree(name);
5918 } else {
5919 /* make sure all cases are covered explicitely */
5920 XP_ERROR(XPATH_EXPR_ERROR);
5921 }
5922 }
5923
5924 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005925 if (CUR == '/') {
5926 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
5927 } else {
5928 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005929 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005930 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005931 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005932 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005933 CHECK_ERROR;
5934 if ((CUR == '/') && (NXT(1) == '/')) {
5935 SKIP(2);
5936 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005937
5938 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
5939 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5940 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
5941
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005942 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005943 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005944 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005945 }
5946 }
5947 SKIP_BLANKS;
5948}
5949
5950/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005951 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005952 * @ctxt: the XPath Parser context
5953 *
5954 * [18] UnionExpr ::= PathExpr
5955 * | UnionExpr '|' PathExpr
5956 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005957 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005958 */
5959
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005960static void
5961xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
5962 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005963 CHECK_ERROR;
5964 SKIP_BLANKS;
5965 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005966 int op1 = ctxt->comp->last;
5967 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005968
5969 NEXT;
5970 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005971 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005972
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005973 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
5974
Owen Taylor3473f882001-02-23 17:55:21 +00005975 SKIP_BLANKS;
5976 }
Owen Taylor3473f882001-02-23 17:55:21 +00005977}
5978
5979/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005980 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005981 * @ctxt: the XPath Parser context
5982 *
5983 * [27] UnaryExpr ::= UnionExpr
5984 * | '-' UnaryExpr
5985 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005986 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005987 */
5988
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005989static void
5990xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005991 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005992 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005993
5994 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00005995 while (CUR == '-') {
5996 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005997 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005998 NEXT;
5999 SKIP_BLANKS;
6000 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006001
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006002 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006003 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006004 if (found) {
6005 if (minus)
6006 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6007 else
6008 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006009 }
6010}
6011
6012/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006013 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006014 * @ctxt: the XPath Parser context
6015 *
6016 * [26] MultiplicativeExpr ::= UnaryExpr
6017 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6018 * | MultiplicativeExpr 'div' UnaryExpr
6019 * | MultiplicativeExpr 'mod' UnaryExpr
6020 * [34] MultiplyOperator ::= '*'
6021 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006022 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006023 */
6024
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006025static void
6026xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6027 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006028 CHECK_ERROR;
6029 SKIP_BLANKS;
6030 while ((CUR == '*') ||
6031 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6032 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6033 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006034 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006035
6036 if (CUR == '*') {
6037 op = 0;
6038 NEXT;
6039 } else if (CUR == 'd') {
6040 op = 1;
6041 SKIP(3);
6042 } else if (CUR == 'm') {
6043 op = 2;
6044 SKIP(3);
6045 }
6046 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006047 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006048 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006049 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006050 SKIP_BLANKS;
6051 }
6052}
6053
6054/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006055 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006056 * @ctxt: the XPath Parser context
6057 *
6058 * [25] AdditiveExpr ::= MultiplicativeExpr
6059 * | AdditiveExpr '+' MultiplicativeExpr
6060 * | AdditiveExpr '-' MultiplicativeExpr
6061 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006062 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006063 */
6064
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006065static void
6066xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006067
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006068 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006069 CHECK_ERROR;
6070 SKIP_BLANKS;
6071 while ((CUR == '+') || (CUR == '-')) {
6072 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006073 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006074
6075 if (CUR == '+') plus = 1;
6076 else plus = 0;
6077 NEXT;
6078 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006079 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006080 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006081 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006082 SKIP_BLANKS;
6083 }
6084}
6085
6086/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006087 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006088 * @ctxt: the XPath Parser context
6089 *
6090 * [24] RelationalExpr ::= AdditiveExpr
6091 * | RelationalExpr '<' AdditiveExpr
6092 * | RelationalExpr '>' AdditiveExpr
6093 * | RelationalExpr '<=' AdditiveExpr
6094 * | RelationalExpr '>=' AdditiveExpr
6095 *
6096 * A <= B > C is allowed ? Answer from James, yes with
6097 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6098 * which is basically what got implemented.
6099 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006100 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006101 * on the stack
6102 */
6103
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006104static void
6105xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6106 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006107 CHECK_ERROR;
6108 SKIP_BLANKS;
6109 while ((CUR == '<') ||
6110 (CUR == '>') ||
6111 ((CUR == '<') && (NXT(1) == '=')) ||
6112 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006113 int inf, strict;
6114 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006115
6116 if (CUR == '<') inf = 1;
6117 else inf = 0;
6118 if (NXT(1) == '=') strict = 0;
6119 else strict = 1;
6120 NEXT;
6121 if (!strict) NEXT;
6122 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006123 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006124 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006125 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006126 SKIP_BLANKS;
6127 }
6128}
6129
6130/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006131 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006132 * @ctxt: the XPath Parser context
6133 *
6134 * [23] EqualityExpr ::= RelationalExpr
6135 * | EqualityExpr '=' RelationalExpr
6136 * | EqualityExpr '!=' RelationalExpr
6137 *
6138 * A != B != C is allowed ? Answer from James, yes with
6139 * (RelationalExpr = RelationalExpr) = RelationalExpr
6140 * (RelationalExpr != RelationalExpr) != RelationalExpr
6141 * which is basically what got implemented.
6142 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006143 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006144 *
6145 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006146static void
6147xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6148 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006149 CHECK_ERROR;
6150 SKIP_BLANKS;
6151 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006152 int eq;
6153 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006154
6155 if (CUR == '=') eq = 1;
6156 else eq = 0;
6157 NEXT;
6158 if (!eq) NEXT;
6159 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006160 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006161 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006162 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006163 SKIP_BLANKS;
6164 }
6165}
6166
6167/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006168 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006169 * @ctxt: the XPath Parser context
6170 *
6171 * [22] AndExpr ::= EqualityExpr
6172 * | AndExpr 'and' EqualityExpr
6173 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006174 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006175 *
6176 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006177static void
6178xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6179 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006180 CHECK_ERROR;
6181 SKIP_BLANKS;
6182 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006183 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006184 SKIP(3);
6185 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006186 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006187 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006188 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006189 SKIP_BLANKS;
6190 }
6191}
6192
6193/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006194 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006195 * @ctxt: the XPath Parser context
6196 *
6197 * [14] Expr ::= OrExpr
6198 * [21] OrExpr ::= AndExpr
6199 * | OrExpr 'or' AndExpr
6200 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006201 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006202 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006203static void
6204xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6205 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006206 CHECK_ERROR;
6207 SKIP_BLANKS;
6208 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006209 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006210 SKIP(2);
6211 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006212 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006213 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006214 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6215 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006216 SKIP_BLANKS;
6217 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006218 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6219 /* more ops could be optimized too */
6220 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6221 }
Owen Taylor3473f882001-02-23 17:55:21 +00006222}
6223
6224/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006225 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006226 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006227 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006228 *
6229 * [8] Predicate ::= '[' PredicateExpr ']'
6230 * [9] PredicateExpr ::= Expr
6231 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006232 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006233 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006234static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006235xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006236 int op1 = ctxt->comp->last;
6237
6238 SKIP_BLANKS;
6239 if (CUR != '[') {
6240 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6241 }
6242 NEXT;
6243 SKIP_BLANKS;
6244
6245 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006246 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006247 CHECK_ERROR;
6248
6249 if (CUR != ']') {
6250 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6251 }
6252
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006253 if (filter)
6254 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6255 else
6256 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006257
6258 NEXT;
6259 SKIP_BLANKS;
6260}
6261
6262/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006263 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006264 * @ctxt: the XPath Parser context
6265 * @test: pointer to a xmlXPathTestVal
6266 * @type: pointer to a xmlXPathTypeVal
6267 * @prefix: placeholder for a possible name prefix
6268 *
6269 * [7] NodeTest ::= NameTest
6270 * | NodeType '(' ')'
6271 * | 'processing-instruction' '(' Literal ')'
6272 *
6273 * [37] NameTest ::= '*'
6274 * | NCName ':' '*'
6275 * | QName
6276 * [38] NodeType ::= 'comment'
6277 * | 'text'
6278 * | 'processing-instruction'
6279 * | 'node'
6280 *
6281 * Returns the name found and update @test, @type and @prefix appropriately
6282 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006283static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006284xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6285 xmlXPathTypeVal *type, const xmlChar **prefix,
6286 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006287 int blanks;
6288
6289 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6290 STRANGE;
6291 return(NULL);
6292 }
6293 *type = 0;
6294 *test = 0;
6295 *prefix = NULL;
6296 SKIP_BLANKS;
6297
6298 if ((name == NULL) && (CUR == '*')) {
6299 /*
6300 * All elements
6301 */
6302 NEXT;
6303 *test = NODE_TEST_ALL;
6304 return(NULL);
6305 }
6306
6307 if (name == NULL)
6308 name = xmlXPathParseNCName(ctxt);
6309 if (name == NULL) {
6310 XP_ERROR0(XPATH_EXPR_ERROR);
6311 }
6312
6313 blanks = IS_BLANK(CUR);
6314 SKIP_BLANKS;
6315 if (CUR == '(') {
6316 NEXT;
6317 /*
6318 * NodeType or PI search
6319 */
6320 if (xmlStrEqual(name, BAD_CAST "comment"))
6321 *type = NODE_TYPE_COMMENT;
6322 else if (xmlStrEqual(name, BAD_CAST "node"))
6323 *type = NODE_TYPE_NODE;
6324 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6325 *type = NODE_TYPE_PI;
6326 else if (xmlStrEqual(name, BAD_CAST "text"))
6327 *type = NODE_TYPE_TEXT;
6328 else {
6329 if (name != NULL)
6330 xmlFree(name);
6331 XP_ERROR0(XPATH_EXPR_ERROR);
6332 }
6333
6334 *test = NODE_TEST_TYPE;
6335
6336 SKIP_BLANKS;
6337 if (*type == NODE_TYPE_PI) {
6338 /*
6339 * Specific case: search a PI by name.
6340 */
Owen Taylor3473f882001-02-23 17:55:21 +00006341 if (name != NULL)
6342 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006343 name = NULL;
6344 if (CUR != ')') {
6345 name = xmlXPathParseLiteral(ctxt);
6346 CHECK_ERROR 0;
6347 SKIP_BLANKS;
6348 }
Owen Taylor3473f882001-02-23 17:55:21 +00006349 }
6350 if (CUR != ')') {
6351 if (name != NULL)
6352 xmlFree(name);
6353 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6354 }
6355 NEXT;
6356 return(name);
6357 }
6358 *test = NODE_TEST_NAME;
6359 if ((!blanks) && (CUR == ':')) {
6360 NEXT;
6361
6362 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006363 * Since currently the parser context don't have a
6364 * namespace list associated:
6365 * The namespace name for this prefix can be computed
6366 * only at evaluation time. The compilation is done
6367 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006368 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006369#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006370 *prefix = xmlXPathNsLookup(ctxt->context, name);
6371 if (name != NULL)
6372 xmlFree(name);
6373 if (*prefix == NULL) {
6374 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6375 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006376#else
6377 *prefix = name;
6378#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006379
6380 if (CUR == '*') {
6381 /*
6382 * All elements
6383 */
6384 NEXT;
6385 *test = NODE_TEST_ALL;
6386 return(NULL);
6387 }
6388
6389 name = xmlXPathParseNCName(ctxt);
6390 if (name == NULL) {
6391 XP_ERROR0(XPATH_EXPR_ERROR);
6392 }
6393 }
6394 return(name);
6395}
6396
6397/**
6398 * xmlXPathIsAxisName:
6399 * @name: a preparsed name token
6400 *
6401 * [6] AxisName ::= 'ancestor'
6402 * | 'ancestor-or-self'
6403 * | 'attribute'
6404 * | 'child'
6405 * | 'descendant'
6406 * | 'descendant-or-self'
6407 * | 'following'
6408 * | 'following-sibling'
6409 * | 'namespace'
6410 * | 'parent'
6411 * | 'preceding'
6412 * | 'preceding-sibling'
6413 * | 'self'
6414 *
6415 * Returns the axis or 0
6416 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006417static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006418xmlXPathIsAxisName(const xmlChar *name) {
6419 xmlXPathAxisVal ret = 0;
6420 switch (name[0]) {
6421 case 'a':
6422 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6423 ret = AXIS_ANCESTOR;
6424 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6425 ret = AXIS_ANCESTOR_OR_SELF;
6426 if (xmlStrEqual(name, BAD_CAST "attribute"))
6427 ret = AXIS_ATTRIBUTE;
6428 break;
6429 case 'c':
6430 if (xmlStrEqual(name, BAD_CAST "child"))
6431 ret = AXIS_CHILD;
6432 break;
6433 case 'd':
6434 if (xmlStrEqual(name, BAD_CAST "descendant"))
6435 ret = AXIS_DESCENDANT;
6436 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6437 ret = AXIS_DESCENDANT_OR_SELF;
6438 break;
6439 case 'f':
6440 if (xmlStrEqual(name, BAD_CAST "following"))
6441 ret = AXIS_FOLLOWING;
6442 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6443 ret = AXIS_FOLLOWING_SIBLING;
6444 break;
6445 case 'n':
6446 if (xmlStrEqual(name, BAD_CAST "namespace"))
6447 ret = AXIS_NAMESPACE;
6448 break;
6449 case 'p':
6450 if (xmlStrEqual(name, BAD_CAST "parent"))
6451 ret = AXIS_PARENT;
6452 if (xmlStrEqual(name, BAD_CAST "preceding"))
6453 ret = AXIS_PRECEDING;
6454 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6455 ret = AXIS_PRECEDING_SIBLING;
6456 break;
6457 case 's':
6458 if (xmlStrEqual(name, BAD_CAST "self"))
6459 ret = AXIS_SELF;
6460 break;
6461 }
6462 return(ret);
6463}
6464
6465/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006466 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006467 * @ctxt: the XPath Parser context
6468 *
6469 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6470 * | AbbreviatedStep
6471 *
6472 * [12] AbbreviatedStep ::= '.' | '..'
6473 *
6474 * [5] AxisSpecifier ::= AxisName '::'
6475 * | AbbreviatedAxisSpecifier
6476 *
6477 * [13] AbbreviatedAxisSpecifier ::= '@'?
6478 *
6479 * Modified for XPtr range support as:
6480 *
6481 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6482 * | AbbreviatedStep
6483 * | 'range-to' '(' Expr ')' Predicate*
6484 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006485 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006486 * A location step of . is short for self::node(). This is
6487 * particularly useful in conjunction with //. For example, the
6488 * location path .//para is short for
6489 * self::node()/descendant-or-self::node()/child::para
6490 * and so will select all para descendant elements of the context
6491 * node.
6492 * Similarly, a location step of .. is short for parent::node().
6493 * For example, ../title is short for parent::node()/child::title
6494 * and so will select the title children of the parent of the context
6495 * node.
6496 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006497static void
6498xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006499#ifdef LIBXML_XPTR_ENABLED
6500 int rangeto = 0;
6501 int op2 = -1;
6502#endif
6503
Owen Taylor3473f882001-02-23 17:55:21 +00006504 SKIP_BLANKS;
6505 if ((CUR == '.') && (NXT(1) == '.')) {
6506 SKIP(2);
6507 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006508 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6509 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006510 } else if (CUR == '.') {
6511 NEXT;
6512 SKIP_BLANKS;
6513 } else {
6514 xmlChar *name = NULL;
6515 const xmlChar *prefix = NULL;
6516 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006517 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006518 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006519 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006520
6521 /*
6522 * The modification needed for XPointer change to the production
6523 */
6524#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006525 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006526 name = xmlXPathParseNCName(ctxt);
6527 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006528 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006529 xmlFree(name);
6530 SKIP_BLANKS;
6531 if (CUR != '(') {
6532 XP_ERROR(XPATH_EXPR_ERROR);
6533 }
6534 NEXT;
6535 SKIP_BLANKS;
6536
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006537 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006538 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006539 CHECK_ERROR;
6540
6541 SKIP_BLANKS;
6542 if (CUR != ')') {
6543 XP_ERROR(XPATH_EXPR_ERROR);
6544 }
6545 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006546 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006547 goto eval_predicates;
6548 }
6549 }
6550#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006551 if (CUR == '*') {
6552 axis = AXIS_CHILD;
6553 } else {
6554 if (name == NULL)
6555 name = xmlXPathParseNCName(ctxt);
6556 if (name != NULL) {
6557 axis = xmlXPathIsAxisName(name);
6558 if (axis != 0) {
6559 SKIP_BLANKS;
6560 if ((CUR == ':') && (NXT(1) == ':')) {
6561 SKIP(2);
6562 xmlFree(name);
6563 name = NULL;
6564 } else {
6565 /* an element name can conflict with an axis one :-\ */
6566 axis = AXIS_CHILD;
6567 }
Owen Taylor3473f882001-02-23 17:55:21 +00006568 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00006569 axis = AXIS_CHILD;
6570 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006571 } else if (CUR == '@') {
6572 NEXT;
6573 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00006574 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00006575 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00006576 }
Owen Taylor3473f882001-02-23 17:55:21 +00006577 }
6578
6579 CHECK_ERROR;
6580
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006581 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006582 if (test == 0)
6583 return;
6584
6585#ifdef DEBUG_STEP
6586 xmlGenericError(xmlGenericErrorContext,
6587 "Basis : computing new set\n");
6588#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006589
Owen Taylor3473f882001-02-23 17:55:21 +00006590#ifdef DEBUG_STEP
6591 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006592 if (ctxt->value == NULL)
6593 xmlGenericError(xmlGenericErrorContext, "no value\n");
6594 else if (ctxt->value->nodesetval == NULL)
6595 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6596 else
6597 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006598#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006599
6600eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006601 op1 = ctxt->comp->last;
6602 ctxt->comp->last = -1;
6603
Owen Taylor3473f882001-02-23 17:55:21 +00006604 SKIP_BLANKS;
6605 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006606 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006607 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006608
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006609#ifdef LIBXML_XPTR_ENABLED
6610 if (rangeto) {
6611 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
6612 } else
6613#endif
6614 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
6615 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006616
Owen Taylor3473f882001-02-23 17:55:21 +00006617 }
6618#ifdef DEBUG_STEP
6619 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006620 if (ctxt->value == NULL)
6621 xmlGenericError(xmlGenericErrorContext, "no value\n");
6622 else if (ctxt->value->nodesetval == NULL)
6623 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6624 else
6625 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6626 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006627#endif
6628}
6629
6630/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006631 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006632 * @ctxt: the XPath Parser context
6633 *
6634 * [3] RelativeLocationPath ::= Step
6635 * | RelativeLocationPath '/' Step
6636 * | AbbreviatedRelativeLocationPath
6637 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6638 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006639 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00006640 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006641static void
Owen Taylor3473f882001-02-23 17:55:21 +00006642#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006643xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006644#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006645xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006646#endif
6647(xmlXPathParserContextPtr ctxt) {
6648 SKIP_BLANKS;
6649 if ((CUR == '/') && (NXT(1) == '/')) {
6650 SKIP(2);
6651 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006652 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6653 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006654 } else if (CUR == '/') {
6655 NEXT;
6656 SKIP_BLANKS;
6657 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006658 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006659 SKIP_BLANKS;
6660 while (CUR == '/') {
6661 if ((CUR == '/') && (NXT(1) == '/')) {
6662 SKIP(2);
6663 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006664 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00006665 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006666 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006667 } else if (CUR == '/') {
6668 NEXT;
6669 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006670 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006671 }
6672 SKIP_BLANKS;
6673 }
6674}
6675
6676/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006677 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006678 * @ctxt: the XPath Parser context
6679 *
6680 * [1] LocationPath ::= RelativeLocationPath
6681 * | AbsoluteLocationPath
6682 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6683 * | AbbreviatedAbsoluteLocationPath
6684 * [10] AbbreviatedAbsoluteLocationPath ::=
6685 * '//' RelativeLocationPath
6686 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006687 * Compile a location path
6688 *
Owen Taylor3473f882001-02-23 17:55:21 +00006689 * // is short for /descendant-or-self::node()/. For example,
6690 * //para is short for /descendant-or-self::node()/child::para and
6691 * so will select any para element in the document (even a para element
6692 * that is a document element will be selected by //para since the
6693 * document element node is a child of the root node); div//para is
6694 * short for div/descendant-or-self::node()/child::para and so will
6695 * select all para descendants of div children.
6696 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006697static void
6698xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006699 SKIP_BLANKS;
6700 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006701 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006702 } else {
6703 while (CUR == '/') {
6704 if ((CUR == '/') && (NXT(1) == '/')) {
6705 SKIP(2);
6706 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006707 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6708 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006709 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006710 } else if (CUR == '/') {
6711 NEXT;
6712 SKIP_BLANKS;
6713 if (CUR != 0)
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006714 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006715 }
6716 }
6717 }
6718}
6719
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006720/************************************************************************
6721 * *
6722 * XPath precompiled expression evaluation *
6723 * *
6724 ************************************************************************/
6725
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006726static void
6727xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
6728
6729/**
6730 * xmlXPathNodeCollectAndTest:
6731 * @ctxt: the XPath Parser context
6732 * @op: the XPath precompiled step operation
6733 *
6734 * This is the function implementing a step: based on the current list
6735 * of nodes, it builds up a new list, looking at all nodes under that
6736 * axis and selecting them it also do the predicate filtering
6737 *
6738 * Pushes the new NodeSet resulting from the search.
6739 */
6740static void
6741xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
6742 xmlXPathStepOpPtr op) {
6743 xmlXPathAxisVal axis = op->value;
6744 xmlXPathTestVal test = op->value2;
6745 xmlXPathTypeVal type = op->value3;
6746 const xmlChar *prefix = op->value4;
6747 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006748 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006749
6750#ifdef DEBUG_STEP
6751 int n = 0, t = 0;
6752#endif
6753 int i;
6754 xmlNodeSetPtr ret, list;
6755 xmlXPathTraversalFunction next = NULL;
6756 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
6757 xmlNodePtr cur = NULL;
6758 xmlXPathObjectPtr obj;
6759 xmlNodeSetPtr nodelist;
6760 xmlNodePtr tmp;
6761
6762 CHECK_TYPE(XPATH_NODESET);
6763 obj = valuePop(ctxt);
6764 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006765 if (prefix != NULL) {
6766 URI = xmlXPathNsLookup(ctxt->context, prefix);
6767 if (URI == NULL)
6768 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
6769 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006770
6771#ifdef DEBUG_STEP
6772 xmlGenericError(xmlGenericErrorContext,
6773 "new step : ");
6774#endif
6775 switch (axis) {
6776 case AXIS_ANCESTOR:
6777#ifdef DEBUG_STEP
6778 xmlGenericError(xmlGenericErrorContext,
6779 "axis 'ancestors' ");
6780#endif
6781 next = xmlXPathNextAncestor; break;
6782 case AXIS_ANCESTOR_OR_SELF:
6783#ifdef DEBUG_STEP
6784 xmlGenericError(xmlGenericErrorContext,
6785 "axis 'ancestors-or-self' ");
6786#endif
6787 next = xmlXPathNextAncestorOrSelf; break;
6788 case AXIS_ATTRIBUTE:
6789#ifdef DEBUG_STEP
6790 xmlGenericError(xmlGenericErrorContext,
6791 "axis 'attributes' ");
6792#endif
6793 next = xmlXPathNextAttribute; break;
6794 break;
6795 case AXIS_CHILD:
6796#ifdef DEBUG_STEP
6797 xmlGenericError(xmlGenericErrorContext,
6798 "axis 'child' ");
6799#endif
6800 next = xmlXPathNextChild; break;
6801 case AXIS_DESCENDANT:
6802#ifdef DEBUG_STEP
6803 xmlGenericError(xmlGenericErrorContext,
6804 "axis 'descendant' ");
6805#endif
6806 next = xmlXPathNextDescendant; break;
6807 case AXIS_DESCENDANT_OR_SELF:
6808#ifdef DEBUG_STEP
6809 xmlGenericError(xmlGenericErrorContext,
6810 "axis 'descendant-or-self' ");
6811#endif
6812 next = xmlXPathNextDescendantOrSelf; break;
6813 case AXIS_FOLLOWING:
6814#ifdef DEBUG_STEP
6815 xmlGenericError(xmlGenericErrorContext,
6816 "axis 'following' ");
6817#endif
6818 next = xmlXPathNextFollowing; break;
6819 case AXIS_FOLLOWING_SIBLING:
6820#ifdef DEBUG_STEP
6821 xmlGenericError(xmlGenericErrorContext,
6822 "axis 'following-siblings' ");
6823#endif
6824 next = xmlXPathNextFollowingSibling; break;
6825 case AXIS_NAMESPACE:
6826#ifdef DEBUG_STEP
6827 xmlGenericError(xmlGenericErrorContext,
6828 "axis 'namespace' ");
6829#endif
6830 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
6831 break;
6832 case AXIS_PARENT:
6833#ifdef DEBUG_STEP
6834 xmlGenericError(xmlGenericErrorContext,
6835 "axis 'parent' ");
6836#endif
6837 next = xmlXPathNextParent; break;
6838 case AXIS_PRECEDING:
6839#ifdef DEBUG_STEP
6840 xmlGenericError(xmlGenericErrorContext,
6841 "axis 'preceding' ");
6842#endif
6843 next = xmlXPathNextPreceding; break;
6844 case AXIS_PRECEDING_SIBLING:
6845#ifdef DEBUG_STEP
6846 xmlGenericError(xmlGenericErrorContext,
6847 "axis 'preceding-sibling' ");
6848#endif
6849 next = xmlXPathNextPrecedingSibling; break;
6850 case AXIS_SELF:
6851#ifdef DEBUG_STEP
6852 xmlGenericError(xmlGenericErrorContext,
6853 "axis 'self' ");
6854#endif
6855 next = xmlXPathNextSelf; break;
6856 }
6857 if (next == NULL)
6858 return;
6859
6860 nodelist = obj->nodesetval;
6861 if (nodelist == NULL) {
6862 xmlXPathFreeObject(obj);
6863 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
6864 return;
6865 }
6866 addNode = xmlXPathNodeSetAddUnique;
6867 ret = NULL;
6868#ifdef DEBUG_STEP
6869 xmlGenericError(xmlGenericErrorContext,
6870 " context contains %d nodes\n",
6871 nodelist->nodeNr);
6872 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006873 case NODE_TEST_NONE:
6874 xmlGenericError(xmlGenericErrorContext,
6875 " searching for none !!!\n");
6876 break;
6877 case NODE_TEST_TYPE:
6878 xmlGenericError(xmlGenericErrorContext,
6879 " searching for type %d\n", type);
6880 break;
6881 case NODE_TEST_PI:
6882 xmlGenericError(xmlGenericErrorContext,
6883 " searching for PI !!!\n");
6884 break;
6885 case NODE_TEST_ALL:
6886 xmlGenericError(xmlGenericErrorContext,
6887 " searching for *\n");
6888 break;
6889 case NODE_TEST_NS:
6890 xmlGenericError(xmlGenericErrorContext,
6891 " searching for namespace %s\n",
6892 prefix);
6893 break;
6894 case NODE_TEST_NAME:
6895 xmlGenericError(xmlGenericErrorContext,
6896 " searching for name %s\n", name);
6897 if (prefix != NULL)
6898 xmlGenericError(xmlGenericErrorContext,
6899 " with namespace %s\n",
6900 prefix);
6901 break;
6902 }
6903 xmlGenericError(xmlGenericErrorContext, "Testing : ");
6904#endif
6905 /*
6906 * 2.3 Node Tests
6907 * - For the attribute axis, the principal node type is attribute.
6908 * - For the namespace axis, the principal node type is namespace.
6909 * - For other axes, the principal node type is element.
6910 *
6911 * A node test * is true for any node of the
6912 * principal node type. For example, child::* willi
6913 * select all element children of the context node
6914 */
6915 tmp = ctxt->context->node;
6916 for (i = 0;i < nodelist->nodeNr; i++) {
6917 ctxt->context->node = nodelist->nodeTab[i];
6918
6919 cur = NULL;
6920 list = xmlXPathNodeSetCreate(NULL);
6921 do {
6922 cur = next(ctxt, cur);
6923 if (cur == NULL) break;
6924#ifdef DEBUG_STEP
6925 t++;
6926 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
6927#endif
6928 switch (test) {
6929 case NODE_TEST_NONE:
6930 ctxt->context->node = tmp;
6931 STRANGE
6932 return;
6933 case NODE_TEST_TYPE:
6934 if ((cur->type == type) ||
6935 ((type == NODE_TYPE_NODE) &&
6936 ((cur->type == XML_DOCUMENT_NODE) ||
6937 (cur->type == XML_HTML_DOCUMENT_NODE) ||
6938 (cur->type == XML_ELEMENT_NODE) ||
6939 (cur->type == XML_PI_NODE) ||
6940 (cur->type == XML_COMMENT_NODE) ||
6941 (cur->type == XML_CDATA_SECTION_NODE) ||
6942 (cur->type == XML_TEXT_NODE)))) {
6943#ifdef DEBUG_STEP
6944 n++;
6945#endif
6946 addNode(list, cur);
6947 }
6948 break;
6949 case NODE_TEST_PI:
6950 if (cur->type == XML_PI_NODE) {
6951 if ((name != NULL) &&
6952 (!xmlStrEqual(name, cur->name)))
6953 break;
6954#ifdef DEBUG_STEP
6955 n++;
6956#endif
6957 addNode(list, cur);
6958 }
6959 break;
6960 case NODE_TEST_ALL:
6961 if (axis == AXIS_ATTRIBUTE) {
6962 if (cur->type == XML_ATTRIBUTE_NODE) {
6963#ifdef DEBUG_STEP
6964 n++;
6965#endif
6966 addNode(list, cur);
6967 }
6968 } else if (axis == AXIS_NAMESPACE) {
6969 if (cur->type == XML_NAMESPACE_DECL) {
6970#ifdef DEBUG_STEP
6971 n++;
6972#endif
6973 addNode(list, cur);
6974 }
6975 } else {
6976 if ((cur->type == XML_ELEMENT_NODE) ||
6977 (cur->type == XML_DOCUMENT_NODE) ||
6978 (cur->type == XML_HTML_DOCUMENT_NODE)) {
6979 if (prefix == NULL) {
6980#ifdef DEBUG_STEP
6981 n++;
6982#endif
6983 addNode(list, cur);
6984 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00006985 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006986 cur->ns->href))) {
6987#ifdef DEBUG_STEP
6988 n++;
6989#endif
6990 addNode(list, cur);
6991 }
6992 }
6993 }
6994 break;
6995 case NODE_TEST_NS: {
6996 TODO;
6997 break;
6998 }
6999 case NODE_TEST_NAME:
7000 switch (cur->type) {
7001 case XML_ELEMENT_NODE:
7002 if (xmlStrEqual(name, cur->name)) {
7003 if (prefix == NULL) {
7004 if ((cur->ns == NULL) ||
7005 (cur->ns->prefix == NULL)) {
7006#ifdef DEBUG_STEP
7007 n++;
7008#endif
7009 addNode(list, cur);
7010 }
7011 } else {
7012 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007013 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007014 cur->ns->href))) {
7015#ifdef DEBUG_STEP
7016 n++;
7017#endif
7018 addNode(list, cur);
7019 }
7020 }
7021 }
7022 break;
7023 case XML_ATTRIBUTE_NODE: {
7024 xmlAttrPtr attr = (xmlAttrPtr) cur;
7025 if (xmlStrEqual(name, attr->name)) {
7026 if (prefix == NULL) {
7027 if ((attr->ns == NULL) ||
7028 (attr->ns->prefix == NULL)) {
7029#ifdef DEBUG_STEP
7030 n++;
7031#endif
7032 addNode(list, (xmlNodePtr) attr);
7033 }
7034 } else {
7035 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007036 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007037 attr->ns->href))) {
7038#ifdef DEBUG_STEP
7039 n++;
7040#endif
7041 addNode(list, (xmlNodePtr) attr);
7042 }
7043 }
7044 }
7045 break;
7046 }
7047 case XML_NAMESPACE_DECL: {
7048 TODO;
7049 break;
7050 }
7051 default:
7052 break;
7053 }
7054 break;
7055 }
7056 } while (cur != NULL);
7057
7058 /*
7059 * If there is some predicate filtering do it now
7060 */
7061 if (op->ch2 != -1) {
7062 xmlXPathObjectPtr obj2;
7063
7064 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7065 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7066 CHECK_TYPE(XPATH_NODESET);
7067 obj2 = valuePop(ctxt);
7068 list = obj2->nodesetval;
7069 obj2->nodesetval = NULL;
7070 xmlXPathFreeObject(obj2);
7071 }
7072 if (ret == NULL) {
7073 ret = list;
7074 } else {
7075 ret = xmlXPathNodeSetMerge(ret, list);
7076 xmlXPathFreeNodeSet(list);
7077 }
7078 }
7079 ctxt->context->node = tmp;
7080#ifdef DEBUG_STEP
7081 xmlGenericError(xmlGenericErrorContext,
7082 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7083#endif
7084 xmlXPathFreeObject(obj);
7085 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7086}
7087
Owen Taylor3473f882001-02-23 17:55:21 +00007088/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007089 * xmlXPathCompOpEval:
7090 * @ctxt: the XPath parser context with the compiled expression
7091 * @op: an XPath compiled operation
7092 *
7093 * Evaluate the Precompiled XPath operation
7094 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007095static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007096xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7097 int equal, ret;
7098 xmlXPathCompExprPtr comp;
7099 xmlXPathObjectPtr arg1, arg2;
7100
7101 comp = ctxt->comp;
7102 switch (op->op) {
7103 case XPATH_OP_END:
7104 return;
7105 case XPATH_OP_AND:
7106 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7107 xmlXPathBooleanFunction(ctxt, 1);
7108 if (ctxt->value->boolval == 0)
7109 return;
7110 arg2 = valuePop(ctxt);
7111 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7112 xmlXPathBooleanFunction(ctxt, 1);
7113 arg1 = valuePop(ctxt);
7114 arg1->boolval &= arg2->boolval;
7115 valuePush(ctxt, arg1);
7116 xmlXPathFreeObject(arg2);
7117 return;
7118 case XPATH_OP_OR:
7119 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7120 xmlXPathBooleanFunction(ctxt, 1);
7121 if (ctxt->value->boolval == 1)
7122 return;
7123 arg2 = valuePop(ctxt);
7124 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7125 xmlXPathBooleanFunction(ctxt, 1);
7126 arg1 = valuePop(ctxt);
7127 arg1->boolval |= arg2->boolval;
7128 valuePush(ctxt, arg1);
7129 xmlXPathFreeObject(arg2);
7130 return;
7131 case XPATH_OP_EQUAL:
7132 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7133 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7134 equal = xmlXPathEqualValues(ctxt);
7135 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7136 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7137 return;
7138 case XPATH_OP_CMP:
7139 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7140 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7141 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7142 valuePush(ctxt, xmlXPathNewBoolean(ret));
7143 return;
7144 case XPATH_OP_PLUS:
7145 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7146 if (op->ch2 != -1)
7147 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7148 if (op->value == 0) xmlXPathSubValues(ctxt);
7149 else if (op->value == 1) xmlXPathAddValues(ctxt);
7150 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7151 else if (op->value == 3) {
7152 xmlXPathObjectPtr arg;
7153
7154 POP_FLOAT
7155 valuePush(ctxt, arg);
7156 }
7157 return;
7158 case XPATH_OP_MULT:
7159 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7160 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7161 if (op->value == 0) xmlXPathMultValues(ctxt);
7162 else if (op->value == 1) xmlXPathDivValues(ctxt);
7163 else if (op->value == 2) xmlXPathModValues(ctxt);
7164 return;
7165 case XPATH_OP_UNION:
7166 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7167 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7168 CHECK_TYPE(XPATH_NODESET);
7169 arg2 = valuePop(ctxt);
7170
7171 CHECK_TYPE(XPATH_NODESET);
7172 arg1 = valuePop(ctxt);
7173
7174 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7175 arg2->nodesetval);
7176 valuePush(ctxt, arg1);
7177 xmlXPathFreeObject(arg2);
7178 return;
7179 case XPATH_OP_ROOT:
7180 xmlXPathRoot(ctxt);
7181 return;
7182 case XPATH_OP_NODE:
7183 if (op->ch1 != -1)
7184 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7185 if (op->ch2 != -1)
7186 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7187 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7188 return;
7189 case XPATH_OP_RESET:
7190 if (op->ch1 != -1)
7191 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7192 if (op->ch2 != -1)
7193 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7194 ctxt->context->node = NULL;
7195 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007196 case XPATH_OP_COLLECT: {
7197 if (op->ch1 == -1)
7198 return;
7199
7200 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7201 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007202 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007203 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007204 case XPATH_OP_VALUE:
7205 valuePush(ctxt,
7206 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7207 return;
7208 case XPATH_OP_VARIABLE: {
7209 if (op->ch1 != -1)
7210 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7211 if (op->value5 == NULL)
7212 valuePush(ctxt,
7213 xmlXPathVariableLookup(ctxt->context, op->value4));
7214 else {
7215 const xmlChar *URI;
7216 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7217 if (URI == NULL) {
7218 xmlGenericError(xmlGenericErrorContext,
7219 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7220 op->value4, op->value5);
7221 return;
7222 }
7223 valuePush(ctxt,
7224 xmlXPathVariableLookupNS(ctxt->context,
7225 op->value4, URI));
7226 }
7227 return;
7228 }
7229 case XPATH_OP_FUNCTION: {
7230 xmlXPathFunction func;
7231
7232 if (op->ch1 != -1)
7233 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007234 if (op->cache != NULL)
7235 func = (xmlXPathFunction) op->cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007236 else {
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007237 if (op->value5 == NULL)
7238 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7239 else {
7240 const xmlChar *URI;
7241 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7242 if (URI == NULL) {
7243 xmlGenericError(xmlGenericErrorContext,
7244 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7245 op->value4, op->value5);
7246 return;
7247 }
7248 func = xmlXPathFunctionLookupNS(ctxt->context,
7249 op->value4, URI);
7250 }
7251 if (func == NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007252 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007253 "xmlXPathRunEval: function %s not found\n",
7254 op->value4);
7255 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007256 return;
7257 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007258 op->cache = (void *) func;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007259 }
7260 func(ctxt, op->value);
7261 return;
7262 }
7263 case XPATH_OP_ARG:
7264 if (op->ch1 != -1)
7265 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7266 if (op->ch2 != -1)
7267 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7268 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007269 case XPATH_OP_PREDICATE:
7270 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007271 xmlXPathObjectPtr res;
7272 xmlXPathObjectPtr obj, tmp;
7273 xmlNodeSetPtr newset = NULL;
7274 xmlNodeSetPtr oldset;
7275 xmlNodePtr oldnode;
7276 int i;
7277
7278 if (op->ch1 != -1)
7279 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7280 if (op->ch2 == -1)
7281 return;
7282
7283 oldnode = ctxt->context->node;
7284
7285#ifdef LIBXML_XPTR_ENABLED
7286 /*
7287 * Hum are we filtering the result of an XPointer expression
7288 */
7289 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007290 xmlLocationSetPtr newlocset = NULL;
7291 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007292
7293 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007294 * Extract the old locset, and then evaluate the result of the
7295 * expression for all the element in the locset. use it to grow
7296 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007297 */
7298 CHECK_TYPE(XPATH_LOCATIONSET);
7299 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007300 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007301 ctxt->context->node = NULL;
7302
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007303 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007304 ctxt->context->contextSize = 0;
7305 ctxt->context->proximityPosition = 0;
7306 if (op->ch2 != -1)
7307 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7308 res = valuePop(ctxt);
7309 if (res != NULL)
7310 xmlXPathFreeObject(res);
7311 valuePush(ctxt, obj);
7312 CHECK_ERROR;
7313 return;
7314 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007315 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007316
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007317 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007318 /*
7319 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007320 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007321 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007322 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007323 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7324 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007325 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007326 ctxt->context->proximityPosition = i + 1;
7327
7328 if (op->ch2 != -1)
7329 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7330 CHECK_ERROR;
7331
7332 /*
7333 * The result of the evaluation need to be tested to
7334 * decided whether the filter succeeded or not
7335 */
7336 res = valuePop(ctxt);
7337 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007338 xmlXPtrLocationSetAdd(newlocset,
7339 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007340 }
7341
7342 /*
7343 * Cleanup
7344 */
7345 if (res != NULL)
7346 xmlXPathFreeObject(res);
7347 if (ctxt->value == tmp) {
7348 res = valuePop(ctxt);
7349 xmlXPathFreeObject(res);
7350 }
7351
7352 ctxt->context->node = NULL;
7353 }
7354
7355 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007356 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007357 */
7358 xmlXPathFreeObject(obj);
7359 ctxt->context->node = NULL;
7360 ctxt->context->contextSize = -1;
7361 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007362 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007363 ctxt->context->node = oldnode;
7364 return;
7365 }
7366#endif /* LIBXML_XPTR_ENABLED */
7367
7368 /*
7369 * Extract the old set, and then evaluate the result of the
7370 * expression for all the element in the set. use it to grow
7371 * up a new set.
7372 */
7373 CHECK_TYPE(XPATH_NODESET);
7374 obj = valuePop(ctxt);
7375 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007376
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007377 oldnode = ctxt->context->node;
7378 ctxt->context->node = NULL;
7379
7380 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7381 ctxt->context->contextSize = 0;
7382 ctxt->context->proximityPosition = 0;
7383 if (op->ch2 != -1)
7384 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7385 res = valuePop(ctxt);
7386 if (res != NULL)
7387 xmlXPathFreeObject(res);
7388 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007389 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007390 CHECK_ERROR;
7391 } else {
7392 /*
7393 * Initialize the new set.
7394 */
7395 newset = xmlXPathNodeSetCreate(NULL);
7396
7397 for (i = 0; i < oldset->nodeNr; i++) {
7398 /*
7399 * Run the evaluation with a node list made of
7400 * a single item in the nodeset.
7401 */
7402 ctxt->context->node = oldset->nodeTab[i];
7403 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7404 valuePush(ctxt, tmp);
7405 ctxt->context->contextSize = oldset->nodeNr;
7406 ctxt->context->proximityPosition = i + 1;
7407
7408 if (op->ch2 != -1)
7409 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7410 CHECK_ERROR;
7411
7412 /*
7413 * The result of the evaluation need to be tested to
7414 * decided whether the filter succeeded or not
7415 */
7416 res = valuePop(ctxt);
7417 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7418 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7419 }
7420
7421 /*
7422 * Cleanup
7423 */
7424 if (res != NULL)
7425 xmlXPathFreeObject(res);
7426 if (ctxt->value == tmp) {
7427 res = valuePop(ctxt);
7428 xmlXPathFreeObject(res);
7429 }
7430
7431 ctxt->context->node = NULL;
7432 }
7433
7434 /*
7435 * The result is used as the new evaluation set.
7436 */
7437 xmlXPathFreeObject(obj);
7438 ctxt->context->node = NULL;
7439 ctxt->context->contextSize = -1;
7440 ctxt->context->proximityPosition = -1;
7441 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7442 }
7443 ctxt->context->node = oldnode;
7444 return;
7445 }
7446 case XPATH_OP_SORT:
7447 if (op->ch1 != -1)
7448 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7449 if ((ctxt->value != NULL) &&
7450 (ctxt->value->type == XPATH_NODESET) &&
7451 (ctxt->value->nodesetval != NULL))
7452 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7453 return;
7454#ifdef LIBXML_XPTR_ENABLED
7455 case XPATH_OP_RANGETO: {
7456 xmlXPathObjectPtr range;
7457 xmlXPathObjectPtr res, obj;
7458 xmlXPathObjectPtr tmp;
7459 xmlLocationSetPtr newset = NULL;
7460 xmlNodeSetPtr oldset;
7461 int i;
7462
7463 if (op->ch1 != -1)
7464 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7465 if (op->ch2 == -1)
7466 return;
7467
7468 CHECK_TYPE(XPATH_NODESET);
7469 obj = valuePop(ctxt);
7470 oldset = obj->nodesetval;
7471 ctxt->context->node = NULL;
7472
7473 newset = xmlXPtrLocationSetCreate(NULL);
7474
Daniel Veillard911f49a2001-04-07 15:39:35 +00007475 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007476 for (i = 0; i < oldset->nodeNr; i++) {
7477 /*
7478 * Run the evaluation with a node list made of a single item
7479 * in the nodeset.
7480 */
7481 ctxt->context->node = oldset->nodeTab[i];
7482 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7483 valuePush(ctxt, tmp);
7484
7485 if (op->ch2 != -1)
7486 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7487 CHECK_ERROR;
7488
7489 /*
7490 * The result of the evaluation need to be tested to
7491 * decided whether the filter succeeded or not
7492 */
7493 res = valuePop(ctxt);
7494 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7495 if (range != NULL) {
7496 xmlXPtrLocationSetAdd(newset, range);
7497 }
7498
7499 /*
7500 * Cleanup
7501 */
7502 if (res != NULL)
7503 xmlXPathFreeObject(res);
7504 if (ctxt->value == tmp) {
7505 res = valuePop(ctxt);
7506 xmlXPathFreeObject(res);
7507 }
7508
7509 ctxt->context->node = NULL;
7510 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007511 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007512
7513 /*
7514 * The result is used as the new evaluation set.
7515 */
7516 xmlXPathFreeObject(obj);
7517 ctxt->context->node = NULL;
7518 ctxt->context->contextSize = -1;
7519 ctxt->context->proximityPosition = -1;
7520 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7521 return;
7522 }
7523#endif /* LIBXML_XPTR_ENABLED */
7524 }
7525 xmlGenericError(xmlGenericErrorContext,
7526 "XPath: unknown precompiled operation %d\n",
7527 op->op);
7528 return;
7529}
7530
7531/**
7532 * xmlXPathRunEval:
7533 * @ctxt: the XPath parser context with the compiled expression
7534 *
7535 * Evaluate the Precompiled XPath expression in the given context.
7536 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007537static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007538xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7539 xmlXPathCompExprPtr comp;
7540
7541 if ((ctxt == NULL) || (ctxt->comp == NULL))
7542 return;
7543
7544 if (ctxt->valueTab == NULL) {
7545 /* Allocate the value stack */
7546 ctxt->valueTab = (xmlXPathObjectPtr *)
7547 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7548 if (ctxt->valueTab == NULL) {
7549 xmlFree(ctxt);
7550 xmlGenericError(xmlGenericErrorContext,
7551 "xmlXPathRunEval: out of memory\n");
7552 return;
7553 }
7554 ctxt->valueNr = 0;
7555 ctxt->valueMax = 10;
7556 ctxt->value = NULL;
7557 }
7558 comp = ctxt->comp;
7559 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7560}
7561
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007562/************************************************************************
7563 * *
7564 * Public interfaces *
7565 * *
7566 ************************************************************************/
7567
7568/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007569 * xmlXPathEvalPredicate:
7570 * @ctxt: the XPath context
7571 * @res: the Predicate Expression evaluation result
7572 *
7573 * Evaluate a predicate result for the current node.
7574 * A PredicateExpr is evaluated by evaluating the Expr and converting
7575 * the result to a boolean. If the result is a number, the result will
7576 * be converted to true if the number is equal to the position of the
7577 * context node in the context node list (as returned by the position
7578 * function) and will be converted to false otherwise; if the result
7579 * is not a number, then the result will be converted as if by a call
7580 * to the boolean function.
7581 *
7582 * Return 1 if predicate is true, 0 otherwise
7583 */
7584int
7585xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7586 if (res == NULL) return(0);
7587 switch (res->type) {
7588 case XPATH_BOOLEAN:
7589 return(res->boolval);
7590 case XPATH_NUMBER:
7591 return(res->floatval == ctxt->proximityPosition);
7592 case XPATH_NODESET:
7593 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007594 if (res->nodesetval == NULL)
7595 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007596 return(res->nodesetval->nodeNr != 0);
7597 case XPATH_STRING:
7598 return((res->stringval != NULL) &&
7599 (xmlStrlen(res->stringval) != 0));
7600 default:
7601 STRANGE
7602 }
7603 return(0);
7604}
7605
7606/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007607 * xmlXPathEvaluatePredicateResult:
7608 * @ctxt: the XPath Parser context
7609 * @res: the Predicate Expression evaluation result
7610 *
7611 * Evaluate a predicate result for the current node.
7612 * A PredicateExpr is evaluated by evaluating the Expr and converting
7613 * the result to a boolean. If the result is a number, the result will
7614 * be converted to true if the number is equal to the position of the
7615 * context node in the context node list (as returned by the position
7616 * function) and will be converted to false otherwise; if the result
7617 * is not a number, then the result will be converted as if by a call
7618 * to the boolean function.
7619 *
7620 * Return 1 if predicate is true, 0 otherwise
7621 */
7622int
7623xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
7624 xmlXPathObjectPtr res) {
7625 if (res == NULL) return(0);
7626 switch (res->type) {
7627 case XPATH_BOOLEAN:
7628 return(res->boolval);
7629 case XPATH_NUMBER:
7630 return(res->floatval == ctxt->context->proximityPosition);
7631 case XPATH_NODESET:
7632 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00007633 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00007634 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007635 return(res->nodesetval->nodeNr != 0);
7636 case XPATH_STRING:
7637 return((res->stringval != NULL) &&
7638 (xmlStrlen(res->stringval) != 0));
7639 default:
7640 STRANGE
7641 }
7642 return(0);
7643}
7644
7645/**
7646 * xmlXPathCompile:
7647 * @str: the XPath expression
7648 *
7649 * Compile an XPath expression
7650 *
7651 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7652 * the caller has to free the object.
7653 */
7654xmlXPathCompExprPtr
7655xmlXPathCompile(const xmlChar *str) {
7656 xmlXPathParserContextPtr ctxt;
7657 xmlXPathCompExprPtr comp;
7658
7659 xmlXPathInit();
7660
7661 ctxt = xmlXPathNewParserContext(str, NULL);
7662 xmlXPathCompileExpr(ctxt);
7663
Daniel Veillard40af6492001-04-22 08:50:55 +00007664 if (*ctxt->cur != 0) {
7665 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7666 comp = NULL;
7667 } else {
7668 comp = ctxt->comp;
7669 ctxt->comp = NULL;
7670 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007671 xmlXPathFreeParserContext(ctxt);
7672 return(comp);
7673}
7674
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007675/**
7676 * xmlXPathCompiledEval:
7677 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00007678 * @ctx: the XPath context
7679 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007680 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00007681 *
7682 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7683 * the caller has to free the object.
7684 */
7685xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007686xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00007687 xmlXPathParserContextPtr ctxt;
7688 xmlXPathObjectPtr res, tmp, init = NULL;
7689 int stack = 0;
7690
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007691 if ((comp == NULL) || (ctx == NULL))
7692 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007693 xmlXPathInit();
7694
7695 CHECK_CONTEXT(ctx)
7696
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007697 ctxt = xmlXPathCompParserContext(comp, ctx);
7698 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007699
7700 if (ctxt->value == NULL) {
7701 xmlGenericError(xmlGenericErrorContext,
7702 "xmlXPathEval: evaluation failed\n");
7703 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007704 } else {
7705 res = valuePop(ctxt);
7706 }
7707
7708 do {
7709 tmp = valuePop(ctxt);
7710 if (tmp != NULL) {
7711 if (tmp != init)
7712 stack++;
7713 xmlXPathFreeObject(tmp);
7714 }
7715 } while (tmp != NULL);
7716 if ((stack != 0) && (res != NULL)) {
7717 xmlGenericError(xmlGenericErrorContext,
7718 "xmlXPathEval: %d object left on the stack\n",
7719 stack);
7720 }
7721 if (ctxt->error != XPATH_EXPRESSION_OK) {
7722 xmlXPathFreeObject(res);
7723 res = NULL;
7724 }
7725
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007726
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007727 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007728 xmlXPathFreeParserContext(ctxt);
7729 return(res);
7730}
7731
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007732/**
7733 * xmlXPathEvalExpr:
7734 * @ctxt: the XPath Parser context
7735 *
7736 * Parse and evaluate an XPath expression in the given context,
7737 * then push the result on the context stack
7738 */
7739void
7740xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
7741 xmlXPathCompileExpr(ctxt);
7742 xmlXPathRunEval(ctxt);
7743}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007744
7745/**
7746 * xmlXPathEval:
7747 * @str: the XPath expression
7748 * @ctx: the XPath context
7749 *
7750 * Evaluate the XPath Location Path in the given context.
7751 *
7752 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7753 * the caller has to free the object.
7754 */
7755xmlXPathObjectPtr
7756xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
7757 xmlXPathParserContextPtr ctxt;
7758 xmlXPathObjectPtr res, tmp, init = NULL;
7759 int stack = 0;
7760
7761 xmlXPathInit();
7762
7763 CHECK_CONTEXT(ctx)
7764
7765 ctxt = xmlXPathNewParserContext(str, ctx);
7766 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007767
7768 if (ctxt->value == NULL) {
7769 xmlGenericError(xmlGenericErrorContext,
7770 "xmlXPathEval: evaluation failed\n");
7771 res = NULL;
7772 } else if (*ctxt->cur != 0) {
7773 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7774 res = NULL;
7775 } else {
7776 res = valuePop(ctxt);
7777 }
7778
7779 do {
7780 tmp = valuePop(ctxt);
7781 if (tmp != NULL) {
7782 if (tmp != init)
7783 stack++;
7784 xmlXPathFreeObject(tmp);
7785 }
7786 } while (tmp != NULL);
7787 if ((stack != 0) && (res != NULL)) {
7788 xmlGenericError(xmlGenericErrorContext,
7789 "xmlXPathEval: %d object left on the stack\n",
7790 stack);
7791 }
7792 if (ctxt->error != XPATH_EXPRESSION_OK) {
7793 xmlXPathFreeObject(res);
7794 res = NULL;
7795 }
7796
Owen Taylor3473f882001-02-23 17:55:21 +00007797 xmlXPathFreeParserContext(ctxt);
7798 return(res);
7799}
7800
7801/**
7802 * xmlXPathEvalExpression:
7803 * @str: the XPath expression
7804 * @ctxt: the XPath context
7805 *
7806 * Evaluate the XPath expression in the given context.
7807 *
7808 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
7809 * the caller has to free the object.
7810 */
7811xmlXPathObjectPtr
7812xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
7813 xmlXPathParserContextPtr pctxt;
7814 xmlXPathObjectPtr res, tmp;
7815 int stack = 0;
7816
7817 xmlXPathInit();
7818
7819 CHECK_CONTEXT(ctxt)
7820
7821 pctxt = xmlXPathNewParserContext(str, ctxt);
7822 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007823
7824 if (*pctxt->cur != 0) {
7825 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7826 res = NULL;
7827 } else {
7828 res = valuePop(pctxt);
7829 }
7830 do {
7831 tmp = valuePop(pctxt);
7832 if (tmp != NULL) {
7833 xmlXPathFreeObject(tmp);
7834 stack++;
7835 }
7836 } while (tmp != NULL);
7837 if ((stack != 0) && (res != NULL)) {
7838 xmlGenericError(xmlGenericErrorContext,
7839 "xmlXPathEvalExpression: %d object left on the stack\n",
7840 stack);
7841 }
7842 xmlXPathFreeParserContext(pctxt);
7843 return(res);
7844}
7845
7846/**
7847 * xmlXPathRegisterAllFunctions:
7848 * @ctxt: the XPath context
7849 *
7850 * Registers all default XPath functions in this context
7851 */
7852void
7853xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
7854{
7855 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
7856 xmlXPathBooleanFunction);
7857 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
7858 xmlXPathCeilingFunction);
7859 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
7860 xmlXPathCountFunction);
7861 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
7862 xmlXPathConcatFunction);
7863 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
7864 xmlXPathContainsFunction);
7865 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
7866 xmlXPathIdFunction);
7867 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
7868 xmlXPathFalseFunction);
7869 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
7870 xmlXPathFloorFunction);
7871 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
7872 xmlXPathLastFunction);
7873 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
7874 xmlXPathLangFunction);
7875 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
7876 xmlXPathLocalNameFunction);
7877 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
7878 xmlXPathNotFunction);
7879 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
7880 xmlXPathNameFunction);
7881 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
7882 xmlXPathNamespaceURIFunction);
7883 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
7884 xmlXPathNormalizeFunction);
7885 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
7886 xmlXPathNumberFunction);
7887 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
7888 xmlXPathPositionFunction);
7889 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
7890 xmlXPathRoundFunction);
7891 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
7892 xmlXPathStringFunction);
7893 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
7894 xmlXPathStringLengthFunction);
7895 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
7896 xmlXPathStartsWithFunction);
7897 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
7898 xmlXPathSubstringFunction);
7899 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
7900 xmlXPathSubstringBeforeFunction);
7901 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
7902 xmlXPathSubstringAfterFunction);
7903 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
7904 xmlXPathSumFunction);
7905 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
7906 xmlXPathTrueFunction);
7907 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
7908 xmlXPathTranslateFunction);
7909}
7910
7911#endif /* LIBXML_XPATH_ENABLED */