blob: ba069c650461b9ae8d29a0faede744e51905e553 [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;
255};
256
257struct _xmlXPathCompExpr {
258 int nbStep;
259 int maxStep;
260 xmlXPathStepOp *steps; /* ops for computation */
261 int last;
262};
263
264/************************************************************************
265 * *
266 * Parser Type functions *
267 * *
268 ************************************************************************/
269
270/**
271 * xmlXPathNewCompExpr:
272 *
273 * Create a new Xpath component
274 *
275 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
276 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000277static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000278xmlXPathNewCompExpr(void) {
279 xmlXPathCompExprPtr cur;
280
281 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
282 if (cur == NULL) {
283 xmlGenericError(xmlGenericErrorContext,
284 "xmlXPathNewCompExpr : malloc failed\n");
285 return(NULL);
286 }
287 memset(cur, 0, sizeof(xmlXPathCompExpr));
288 cur->maxStep = 10;
289 cur->nbStep = 0;
290 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
291 sizeof(xmlXPathStepOp));
292 if (cur->steps == NULL) {
293 xmlGenericError(xmlGenericErrorContext,
294 "xmlXPathNewCompExpr : malloc failed\n");
295 xmlFree(cur);
296 return(NULL);
297 }
298 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
299 cur->last = -1;
300 return(cur);
301}
302
303/**
304 * xmlXPathFreeCompExpr:
305 * @comp: an XPATH comp
306 *
307 * Free up the memory allocated by @comp
308 */
309void
310xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) {
311 xmlXPathStepOpPtr op;
312 int i;
313
314 if (comp == NULL)
315 return;
316 for (i = 0;i < comp->nbStep;i++) {
317 op = &comp->steps[i];
318 if (op->value4 != NULL) {
319 if (op->op == XPATH_OP_VALUE)
320 xmlXPathFreeObject(op->value4);
321 else
322 xmlFree(op->value4);
323 }
324 if (op->value5 != NULL)
325 xmlFree(op->value5);
326 }
327 if (comp->steps != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000328 xmlFree(comp->steps);
329 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000330 xmlFree(comp);
331}
332
333/**
334 * xmlXPathCompExprAdd:
335 * @comp: the compiled expression
336 * @ch1: first child index
337 * @ch2: second child index
338 * @op: an op
339 * @value: the first int value
340 * @value2: the second int value
341 * @value3: the third int value
342 * @value4: the first string value
343 * @value5: the second string value
344 *
345 * Add an step to an XPath Compiled Expression
346 *
347 * Returns -1 in case of failure, the index otherwise
348 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000349static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000350xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
351 xmlXPathOp op, int value,
352 int value2, int value3, void *value4, void *value5) {
353 if (comp->nbStep >= comp->maxStep) {
354 xmlXPathStepOp *real;
355
356 comp->maxStep *= 2;
357 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
358 comp->maxStep * sizeof(xmlXPathStepOp));
359 if (real == NULL) {
360 comp->maxStep /= 2;
361 xmlGenericError(xmlGenericErrorContext,
362 "xmlXPathCompExprAdd : realloc failed\n");
363 return(-1);
364 }
365 comp->steps = real;
366 }
367 comp->last = comp->nbStep;
368 comp->steps[comp->nbStep].ch1 = ch1;
369 comp->steps[comp->nbStep].ch2 = ch2;
370 comp->steps[comp->nbStep].op = op;
371 comp->steps[comp->nbStep].value = value;
372 comp->steps[comp->nbStep].value2 = value2;
373 comp->steps[comp->nbStep].value3 = value3;
374 comp->steps[comp->nbStep].value4 = value4;
375 comp->steps[comp->nbStep].value5 = value5;
376 return(comp->nbStep++);
377}
378
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000379#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
380 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
381 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000382#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
383 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
384 (op), (val), (val2), (val3), (val4), (val5))
385
386#define PUSH_LEAVE_EXPR(op, val, val2) \
387xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
388
389#define PUSH_UNARY_EXPR(op, ch, val, val2) \
390xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
391
392#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
393xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
394
395/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000396 * *
397 * Debugging related functions *
398 * *
399 ************************************************************************/
400
401#define TODO \
402 xmlGenericError(xmlGenericErrorContext, \
403 "Unimplemented block at %s:%d\n", \
404 __FILE__, __LINE__);
405
406#define STRANGE \
407 xmlGenericError(xmlGenericErrorContext, \
408 "Internal error at %s:%d\n", \
409 __FILE__, __LINE__);
410
411#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000412static void
413xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000414 int i;
415 char shift[100];
416
417 for (i = 0;((i < depth) && (i < 25));i++)
418 shift[2 * i] = shift[2 * i + 1] = ' ';
419 shift[2 * i] = shift[2 * i + 1] = 0;
420 if (cur == NULL) {
421 fprintf(output, shift);
422 fprintf(output, "Node is NULL !\n");
423 return;
424
425 }
426
427 if ((cur->type == XML_DOCUMENT_NODE) ||
428 (cur->type == XML_HTML_DOCUMENT_NODE)) {
429 fprintf(output, shift);
430 fprintf(output, " /\n");
431 } else if (cur->type == XML_ATTRIBUTE_NODE)
432 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
433 else
434 xmlDebugDumpOneNode(output, cur, depth);
435}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000436static void
437xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000438 xmlNodePtr tmp;
439 int i;
440 char shift[100];
441
442 for (i = 0;((i < depth) && (i < 25));i++)
443 shift[2 * i] = shift[2 * i + 1] = ' ';
444 shift[2 * i] = shift[2 * i + 1] = 0;
445 if (cur == NULL) {
446 fprintf(output, shift);
447 fprintf(output, "Node is NULL !\n");
448 return;
449
450 }
451
452 while (cur != NULL) {
453 tmp = cur;
454 cur = cur->next;
455 xmlDebugDumpOneNode(output, tmp, depth);
456 }
457}
Owen Taylor3473f882001-02-23 17:55:21 +0000458
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000459static void
460xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000461 int i;
462 char shift[100];
463
464 for (i = 0;((i < depth) && (i < 25));i++)
465 shift[2 * i] = shift[2 * i + 1] = ' ';
466 shift[2 * i] = shift[2 * i + 1] = 0;
467
468 if (cur == NULL) {
469 fprintf(output, shift);
470 fprintf(output, "NodeSet is NULL !\n");
471 return;
472
473 }
474
Daniel Veillard911f49a2001-04-07 15:39:35 +0000475 if (cur != NULL) {
476 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
477 for (i = 0;i < cur->nodeNr;i++) {
478 fprintf(output, shift);
479 fprintf(output, "%d", i + 1);
480 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
481 }
Owen Taylor3473f882001-02-23 17:55:21 +0000482 }
483}
484
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000485static void
486xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000487 int i;
488 char shift[100];
489
490 for (i = 0;((i < depth) && (i < 25));i++)
491 shift[2 * i] = shift[2 * i + 1] = ' ';
492 shift[2 * i] = shift[2 * i + 1] = 0;
493
494 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
495 fprintf(output, shift);
496 fprintf(output, "Value Tree is NULL !\n");
497 return;
498
499 }
500
501 fprintf(output, shift);
502 fprintf(output, "%d", i + 1);
503 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
504}
Owen Taylor3473f882001-02-23 17:55:21 +0000505#if defined(LIBXML_XPTR_ENABLED)
506void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000507static void
508xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000509 int i;
510 char shift[100];
511
512 for (i = 0;((i < depth) && (i < 25));i++)
513 shift[2 * i] = shift[2 * i + 1] = ' ';
514 shift[2 * i] = shift[2 * i + 1] = 0;
515
516 if (cur == NULL) {
517 fprintf(output, shift);
518 fprintf(output, "LocationSet is NULL !\n");
519 return;
520
521 }
522
523 for (i = 0;i < cur->locNr;i++) {
524 fprintf(output, shift);
525 fprintf(output, "%d : ", i + 1);
526 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
527 }
528}
529#endif
530
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000531/**
532 * xmlXPathDebugDumpObject:
533 * @output: the FILE * to dump the output
534 * @cur: the object to inspect
535 * @depth: indentation level
536 *
537 * Dump the content of the object for debugging purposes
538 */
539void
540xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000541 int i;
542 char shift[100];
543
544 for (i = 0;((i < depth) && (i < 25));i++)
545 shift[2 * i] = shift[2 * i + 1] = ' ';
546 shift[2 * i] = shift[2 * i + 1] = 0;
547
548 fprintf(output, shift);
549
550 if (cur == NULL) {
551 fprintf(output, "Object is empty (NULL)\n");
552 return;
553 }
554 switch(cur->type) {
555 case XPATH_UNDEFINED:
556 fprintf(output, "Object is uninitialized\n");
557 break;
558 case XPATH_NODESET:
559 fprintf(output, "Object is a Node Set :\n");
560 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
561 break;
562 case XPATH_XSLT_TREE:
563 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000564 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000565 break;
566 case XPATH_BOOLEAN:
567 fprintf(output, "Object is a Boolean : ");
568 if (cur->boolval) fprintf(output, "true\n");
569 else fprintf(output, "false\n");
570 break;
571 case XPATH_NUMBER:
572 fprintf(output, "Object is a number : %0g\n", cur->floatval);
573 break;
574 case XPATH_STRING:
575 fprintf(output, "Object is a string : ");
576 xmlDebugDumpString(output, cur->stringval);
577 fprintf(output, "\n");
578 break;
579 case XPATH_POINT:
580 fprintf(output, "Object is a point : index %d in node", cur->index);
581 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
582 fprintf(output, "\n");
583 break;
584 case XPATH_RANGE:
585 if ((cur->user2 == NULL) ||
586 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
587 fprintf(output, "Object is a collapsed range :\n");
588 fprintf(output, shift);
589 if (cur->index >= 0)
590 fprintf(output, "index %d in ", cur->index);
591 fprintf(output, "node\n");
592 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
593 depth + 1);
594 } else {
595 fprintf(output, "Object is a range :\n");
596 fprintf(output, shift);
597 fprintf(output, "From ");
598 if (cur->index >= 0)
599 fprintf(output, "index %d in ", cur->index);
600 fprintf(output, "node\n");
601 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
602 depth + 1);
603 fprintf(output, shift);
604 fprintf(output, "To ");
605 if (cur->index2 >= 0)
606 fprintf(output, "index %d in ", cur->index2);
607 fprintf(output, "node\n");
608 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
609 depth + 1);
610 fprintf(output, "\n");
611 }
612 break;
613 case XPATH_LOCATIONSET:
614#if defined(LIBXML_XPTR_ENABLED)
615 fprintf(output, "Object is a Location Set:\n");
616 xmlXPathDebugDumpLocationSet(output,
617 (xmlLocationSetPtr) cur->user, depth);
618#endif
619 break;
620 case XPATH_USERS:
621 fprintf(output, "Object is user defined\n");
622 break;
623 }
624}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000625
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000626static void
627xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000628 xmlXPathStepOpPtr op, int depth) {
629 int i;
630 char shift[100];
631
632 for (i = 0;((i < depth) && (i < 25));i++)
633 shift[2 * i] = shift[2 * i + 1] = ' ';
634 shift[2 * i] = shift[2 * i + 1] = 0;
635
636 fprintf(output, shift);
637 if (op == NULL) {
638 fprintf(output, "Step is NULL\n");
639 return;
640 }
641 switch (op->op) {
642 case XPATH_OP_END:
643 fprintf(output, "END"); break;
644 case XPATH_OP_AND:
645 fprintf(output, "AND"); break;
646 case XPATH_OP_OR:
647 fprintf(output, "OR"); break;
648 case XPATH_OP_EQUAL:
649 if (op->value)
650 fprintf(output, "EQUAL =");
651 else
652 fprintf(output, "EQUAL !=");
653 break;
654 case XPATH_OP_CMP:
655 if (op->value)
656 fprintf(output, "CMP <");
657 else
658 fprintf(output, "CMP >");
659 if (!op->value2)
660 fprintf(output, "=");
661 break;
662 case XPATH_OP_PLUS:
663 if (op->value == 0)
664 fprintf(output, "PLUS -");
665 else if (op->value == 1)
666 fprintf(output, "PLUS +");
667 else if (op->value == 2)
668 fprintf(output, "PLUS unary -");
669 else if (op->value == 3)
670 fprintf(output, "PLUS unary - -");
671 break;
672 case XPATH_OP_MULT:
673 if (op->value == 0)
674 fprintf(output, "MULT *");
675 else if (op->value == 1)
676 fprintf(output, "MULT div");
677 else
678 fprintf(output, "MULT mod");
679 break;
680 case XPATH_OP_UNION:
681 fprintf(output, "UNION"); break;
682 case XPATH_OP_ROOT:
683 fprintf(output, "ROOT"); break;
684 case XPATH_OP_NODE:
685 fprintf(output, "NODE"); break;
686 case XPATH_OP_RESET:
687 fprintf(output, "RESET"); break;
688 case XPATH_OP_SORT:
689 fprintf(output, "SORT"); break;
690 case XPATH_OP_COLLECT: {
691 xmlXPathAxisVal axis = op->value;
692 xmlXPathTestVal test = op->value2;
693 xmlXPathTypeVal type = op->value3;
694 const xmlChar *prefix = op->value4;
695 const xmlChar *name = op->value5;
696
697 fprintf(output, "COLLECT ");
698 switch (axis) {
699 case AXIS_ANCESTOR:
700 fprintf(output, " 'ancestors' "); break;
701 case AXIS_ANCESTOR_OR_SELF:
702 fprintf(output, " 'ancestors-or-self' "); break;
703 case AXIS_ATTRIBUTE:
704 fprintf(output, " 'attributes' "); break;
705 case AXIS_CHILD:
706 fprintf(output, " 'child' "); break;
707 case AXIS_DESCENDANT:
708 fprintf(output, " 'descendant' "); break;
709 case AXIS_DESCENDANT_OR_SELF:
710 fprintf(output, " 'descendant-or-self' "); break;
711 case AXIS_FOLLOWING:
712 fprintf(output, " 'following' "); break;
713 case AXIS_FOLLOWING_SIBLING:
714 fprintf(output, " 'following-siblings' "); break;
715 case AXIS_NAMESPACE:
716 fprintf(output, " 'namespace' "); break;
717 case AXIS_PARENT:
718 fprintf(output, " 'parent' "); break;
719 case AXIS_PRECEDING:
720 fprintf(output, " 'preceding' "); break;
721 case AXIS_PRECEDING_SIBLING:
722 fprintf(output, " 'preceding-sibling' "); break;
723 case AXIS_SELF:
724 fprintf(output, " 'self' "); break;
725 }
726 switch (test) {
727 case NODE_TEST_NONE:
728 fprintf(output, "'none' "); break;
729 case NODE_TEST_TYPE:
730 fprintf(output, "'type' "); break;
731 case NODE_TEST_PI:
732 fprintf(output, "'PI' "); break;
733 case NODE_TEST_ALL:
734 fprintf(output, "'all' "); break;
735 case NODE_TEST_NS:
736 fprintf(output, "'namespace' "); break;
737 case NODE_TEST_NAME:
738 fprintf(output, "'name' "); break;
739 }
740 switch (type) {
741 case NODE_TYPE_NODE:
742 fprintf(output, "'node' "); break;
743 case NODE_TYPE_COMMENT:
744 fprintf(output, "'comment' "); break;
745 case NODE_TYPE_TEXT:
746 fprintf(output, "'text' "); break;
747 case NODE_TYPE_PI:
748 fprintf(output, "'PI' "); break;
749 }
750 if (prefix != NULL)
751 fprintf(output, "%s:", prefix);
752 if (name != NULL)
753 fprintf(output, "%s", name);
754 break;
755
756 }
757 case XPATH_OP_VALUE: {
758 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
759
760 fprintf(output, "ELEM ");
761 xmlXPathDebugDumpObject(output, object, 0);
762 goto finish;
763 }
764 case XPATH_OP_VARIABLE: {
765 const xmlChar *prefix = op->value5;
766 const xmlChar *name = op->value4;
767
768 if (prefix != NULL)
769 fprintf(output, "VARIABLE %s:%s", prefix, name);
770 else
771 fprintf(output, "VARIABLE %s", name);
772 break;
773 }
774 case XPATH_OP_FUNCTION: {
775 int nbargs = op->value;
776 const xmlChar *prefix = op->value5;
777 const xmlChar *name = op->value4;
778
779 if (prefix != NULL)
780 fprintf(output, "FUNCTION %s:%s(%d args)",
781 prefix, name, nbargs);
782 else
783 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
784 break;
785 }
786 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
787 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000788 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000789#ifdef LIBXML_XPTR_ENABLED
790 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
791#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000792 default:
793 fprintf(output, "UNKNOWN %d\n", op->op); return;
794 }
795 fprintf(output, "\n");
796finish:
797 if (op->ch1 >= 0)
798 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
799 if (op->ch2 >= 0)
800 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
801}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000802
803void
804xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
805 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000806 int i;
807 char shift[100];
808
809 for (i = 0;((i < depth) && (i < 25));i++)
810 shift[2 * i] = shift[2 * i + 1] = ' ';
811 shift[2 * i] = shift[2 * i + 1] = 0;
812
813 fprintf(output, shift);
814
815 if (comp == NULL) {
816 fprintf(output, "Compiled Expression is NULL\n");
817 return;
818 }
819 fprintf(output, "Compiled Expression : %d elements\n",
820 comp->nbStep);
821 i = comp->last;
822 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
823}
Owen Taylor3473f882001-02-23 17:55:21 +0000824#endif
825
826/************************************************************************
827 * *
828 * Parser stacks related functions and macros *
829 * *
830 ************************************************************************/
831
832/*
833 * Generic function for accessing stacks in the Parser Context
834 */
835
836#define PUSH_AND_POP(type, name) \
837extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
838 if (ctxt->name##Nr >= ctxt->name##Max) { \
839 ctxt->name##Max *= 2; \
840 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
841 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
842 if (ctxt->name##Tab == NULL) { \
843 xmlGenericError(xmlGenericErrorContext, \
844 "realloc failed !\n"); \
845 return(0); \
846 } \
847 } \
848 ctxt->name##Tab[ctxt->name##Nr] = value; \
849 ctxt->name = value; \
850 return(ctxt->name##Nr++); \
851} \
852extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
853 type ret; \
854 if (ctxt->name##Nr <= 0) return(0); \
855 ctxt->name##Nr--; \
856 if (ctxt->name##Nr > 0) \
857 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
858 else \
859 ctxt->name = NULL; \
860 ret = ctxt->name##Tab[ctxt->name##Nr]; \
861 ctxt->name##Tab[ctxt->name##Nr] = 0; \
862 return(ret); \
863} \
864
865PUSH_AND_POP(xmlXPathObjectPtr, value)
866
867/*
868 * Macros for accessing the content. Those should be used only by the parser,
869 * and not exported.
870 *
871 * Dirty macros, i.e. one need to make assumption on the context to use them
872 *
873 * CUR_PTR return the current pointer to the xmlChar to be parsed.
874 * CUR returns the current xmlChar value, i.e. a 8 bit value
875 * in ISO-Latin or UTF-8.
876 * This should be used internally by the parser
877 * only to compare to ASCII values otherwise it would break when
878 * running with UTF-8 encoding.
879 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
880 * to compare on ASCII based substring.
881 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
882 * strings within the parser.
883 * CURRENT Returns the current char value, with the full decoding of
884 * UTF-8 if we are using this mode. It returns an int.
885 * NEXT Skip to the next character, this does the proper decoding
886 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
887 * It returns the pointer to the current xmlChar.
888 */
889
890#define CUR (*ctxt->cur)
891#define SKIP(val) ctxt->cur += (val)
892#define NXT(val) ctxt->cur[(val)]
893#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +0000894#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
895
896#define COPY_BUF(l,b,i,v) \
897 if (l == 1) b[i++] = (xmlChar) v; \
898 else i += xmlCopyChar(l,&b[i],v)
899
900#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +0000901
902#define SKIP_BLANKS \
903 while (IS_BLANK(*(ctxt->cur))) NEXT
904
905#define CURRENT (*ctxt->cur)
906#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
907
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000908
909#ifndef DBL_DIG
910#define DBL_DIG 16
911#endif
912#ifndef DBL_EPSILON
913#define DBL_EPSILON 1E-9
914#endif
915
916#define UPPER_DOUBLE 1E9
917#define LOWER_DOUBLE 1E-5
918
919#define INTEGER_DIGITS DBL_DIG
920#define FRACTION_DIGITS (DBL_DIG + 1)
921#define EXPONENT_DIGITS (3 + 2)
922
923/**
924 * xmlXPathFormatNumber:
925 * @number: number to format
926 * @buffer: output buffer
927 * @buffersize: size of output buffer
928 *
929 * Convert the number into a string representation.
930 */
931static void
932xmlXPathFormatNumber(double number, char buffer[], int buffersize)
933{
934 switch (isinf(number)) {
935 case 1:
936 if (buffersize > (int)sizeof("+Infinity"))
937 sprintf(buffer, "+Infinity");
938 break;
939 case -1:
940 if (buffersize > (int)sizeof("-Infinity"))
941 sprintf(buffer, "-Infinity");
942 break;
943 default:
944 if (isnan(number)) {
945 if (buffersize > (int)sizeof("NaN"))
946 sprintf(buffer, "NaN");
947 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000948 /* 3 is sign, decimal point, and terminating zero */
949 char work[DBL_DIG + EXPONENT_DIGITS + 3];
950 int integer_place, fraction_place;
951 char *ptr;
952 char *after_fraction;
953 double absolute_value;
954 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000955
Bjorn Reese70a9da52001-04-21 16:57:29 +0000956 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000957
Bjorn Reese70a9da52001-04-21 16:57:29 +0000958 /*
959 * First choose format - scientific or regular floating point.
960 * In either case, result is in work, and after_fraction points
961 * just past the fractional part.
962 */
963 if ( ((absolute_value > UPPER_DOUBLE) ||
964 (absolute_value < LOWER_DOUBLE)) &&
965 (absolute_value != 0.0) ) {
966 /* Use scientific notation */
967 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
968 fraction_place = DBL_DIG - 1;
969 snprintf(work, sizeof(work),"%*.*e",
970 integer_place, fraction_place, number);
971 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000972 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000973 else {
974 /* Use regular notation */
975 integer_place = 1 + (int)log10(absolute_value);
976 fraction_place = (integer_place > 0)
977 ? DBL_DIG - integer_place
978 : DBL_DIG;
979 size = snprintf(work, sizeof(work), "%0.*f",
980 fraction_place, number);
981 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000982 }
983
Bjorn Reese70a9da52001-04-21 16:57:29 +0000984 /* Remove fractional trailing zeroes */
985 ptr = after_fraction;
986 while (*(--ptr) == '0')
987 ;
988 if (*ptr != '.')
989 ptr++;
990 strcpy(ptr, after_fraction);
991
992 /* Finally copy result back to caller */
993 size = strlen(work) + 1;
994 if (size > buffersize) {
995 work[buffersize - 1] = 0;
996 size = buffersize;
997 }
998 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000999 }
1000 break;
1001 }
1002}
1003
Owen Taylor3473f882001-02-23 17:55:21 +00001004/************************************************************************
1005 * *
1006 * Error handling routines *
1007 * *
1008 ************************************************************************/
1009
1010
1011const char *xmlXPathErrorMessages[] = {
1012 "Ok",
1013 "Number encoding",
1014 "Unfinished litteral",
1015 "Start of litteral",
1016 "Expected $ for variable reference",
1017 "Undefined variable",
1018 "Invalid predicate",
1019 "Invalid expression",
1020 "Missing closing curly brace",
1021 "Unregistered function",
1022 "Invalid operand",
1023 "Invalid type",
1024 "Invalid number of arguments",
1025 "Invalid context size",
1026 "Invalid context position",
1027 "Memory allocation error",
1028 "Syntax error",
1029 "Resource error",
1030 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001031 "Undefined namespace prefix",
1032 "Encoding error",
1033 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001034};
1035
1036/**
1037 * xmlXPathError:
1038 * @ctxt: the XPath Parser context
1039 * @file: the file name
1040 * @line: the line number
1041 * @no: the error number
1042 *
1043 * Create a new xmlNodeSetPtr of type double and of value @val
1044 *
1045 * Returns the newly created object.
1046 */
1047void
1048xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1049 int line, int no) {
1050 int n;
1051 const xmlChar *cur;
1052 const xmlChar *base;
1053
1054 xmlGenericError(xmlGenericErrorContext,
1055 "Error %s:%d: %s\n", file, line,
1056 xmlXPathErrorMessages[no]);
1057
1058 cur = ctxt->cur;
1059 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001060 if ((cur == NULL) || (base == NULL))
1061 return;
1062
Owen Taylor3473f882001-02-23 17:55:21 +00001063 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1064 cur--;
1065 }
1066 n = 0;
1067 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1068 cur--;
1069 if ((*cur == '\n') || (*cur == '\r')) cur++;
1070 base = cur;
1071 n = 0;
1072 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1073 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1074 n++;
1075 }
1076 xmlGenericError(xmlGenericErrorContext, "\n");
1077 cur = ctxt->cur;
1078 while ((*cur == '\n') || (*cur == '\r'))
1079 cur--;
1080 n = 0;
1081 while ((cur != base) && (n++ < 80)) {
1082 xmlGenericError(xmlGenericErrorContext, " ");
1083 base++;
1084 }
1085 xmlGenericError(xmlGenericErrorContext,"^\n");
1086}
1087
1088
1089/************************************************************************
1090 * *
1091 * Routines to handle NodeSets *
1092 * *
1093 ************************************************************************/
1094
1095/**
1096 * xmlXPathCmpNodes:
1097 * @node1: the first node
1098 * @node2: the second node
1099 *
1100 * Compare two nodes w.r.t document order
1101 *
1102 * Returns -2 in case of error 1 if first point < second point, 0 if
1103 * that's the same node, -1 otherwise
1104 */
1105int
1106xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1107 int depth1, depth2;
1108 xmlNodePtr cur, root;
1109
1110 if ((node1 == NULL) || (node2 == NULL))
1111 return(-2);
1112 /*
1113 * a couple of optimizations which will avoid computations in most cases
1114 */
1115 if (node1 == node2)
1116 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001117 if ((node1->type == XML_NAMESPACE_DECL) ||
1118 (node2->type == XML_NAMESPACE_DECL))
1119 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001120 if (node1 == node2->prev)
1121 return(1);
1122 if (node1 == node2->next)
1123 return(-1);
1124
1125 /*
1126 * compute depth to root
1127 */
1128 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1129 if (cur == node1)
1130 return(1);
1131 depth2++;
1132 }
1133 root = cur;
1134 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1135 if (cur == node2)
1136 return(-1);
1137 depth1++;
1138 }
1139 /*
1140 * Distinct document (or distinct entities :-( ) case.
1141 */
1142 if (root != cur) {
1143 return(-2);
1144 }
1145 /*
1146 * get the nearest common ancestor.
1147 */
1148 while (depth1 > depth2) {
1149 depth1--;
1150 node1 = node1->parent;
1151 }
1152 while (depth2 > depth1) {
1153 depth2--;
1154 node2 = node2->parent;
1155 }
1156 while (node1->parent != node2->parent) {
1157 node1 = node1->parent;
1158 node2 = node2->parent;
1159 /* should not happen but just in case ... */
1160 if ((node1 == NULL) || (node2 == NULL))
1161 return(-2);
1162 }
1163 /*
1164 * Find who's first.
1165 */
1166 if (node1 == node2->next)
1167 return(-1);
1168 for (cur = node1->next;cur != NULL;cur = cur->next)
1169 if (cur == node2)
1170 return(1);
1171 return(-1); /* assume there is no sibling list corruption */
1172}
1173
1174/**
1175 * xmlXPathNodeSetSort:
1176 * @set: the node set
1177 *
1178 * Sort the node set in document order
1179 */
1180void
1181xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001182 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001183 xmlNodePtr tmp;
1184
1185 if (set == NULL)
1186 return;
1187
1188 /* Use Shell's sort to sort the node-set */
1189 len = set->nodeNr;
1190 for (incr = len / 2; incr > 0; incr /= 2) {
1191 for (i = incr; i < len; i++) {
1192 j = i - incr;
1193 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001194 if (xmlXPathCmpNodes(set->nodeTab[j],
1195 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001196 tmp = set->nodeTab[j];
1197 set->nodeTab[j] = set->nodeTab[j + incr];
1198 set->nodeTab[j + incr] = tmp;
1199 j -= incr;
1200 } else
1201 break;
1202 }
1203 }
1204 }
1205}
1206
1207#define XML_NODESET_DEFAULT 10
1208/**
1209 * xmlXPathNodeSetCreate:
1210 * @val: an initial xmlNodePtr, or NULL
1211 *
1212 * Create a new xmlNodeSetPtr of type double and of value @val
1213 *
1214 * Returns the newly created object.
1215 */
1216xmlNodeSetPtr
1217xmlXPathNodeSetCreate(xmlNodePtr val) {
1218 xmlNodeSetPtr ret;
1219
1220 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1221 if (ret == NULL) {
1222 xmlGenericError(xmlGenericErrorContext,
1223 "xmlXPathNewNodeSet: out of memory\n");
1224 return(NULL);
1225 }
1226 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1227 if (val != NULL) {
1228 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1229 sizeof(xmlNodePtr));
1230 if (ret->nodeTab == NULL) {
1231 xmlGenericError(xmlGenericErrorContext,
1232 "xmlXPathNewNodeSet: out of memory\n");
1233 return(NULL);
1234 }
1235 memset(ret->nodeTab, 0 ,
1236 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1237 ret->nodeMax = XML_NODESET_DEFAULT;
1238 ret->nodeTab[ret->nodeNr++] = val;
1239 }
1240 return(ret);
1241}
1242
1243/**
1244 * xmlXPathNodeSetAdd:
1245 * @cur: the initial node set
1246 * @val: a new xmlNodePtr
1247 *
1248 * add a new xmlNodePtr ot an existing NodeSet
1249 */
1250void
1251xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1252 int i;
1253
1254 if (val == NULL) return;
1255
1256 /*
1257 * check against doublons
1258 */
1259 for (i = 0;i < cur->nodeNr;i++)
1260 if (cur->nodeTab[i] == val) return;
1261
1262 /*
1263 * grow the nodeTab if needed
1264 */
1265 if (cur->nodeMax == 0) {
1266 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1267 sizeof(xmlNodePtr));
1268 if (cur->nodeTab == NULL) {
1269 xmlGenericError(xmlGenericErrorContext,
1270 "xmlXPathNodeSetAdd: out of memory\n");
1271 return;
1272 }
1273 memset(cur->nodeTab, 0 ,
1274 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1275 cur->nodeMax = XML_NODESET_DEFAULT;
1276 } else if (cur->nodeNr == cur->nodeMax) {
1277 xmlNodePtr *temp;
1278
1279 cur->nodeMax *= 2;
1280 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1281 sizeof(xmlNodePtr));
1282 if (temp == NULL) {
1283 xmlGenericError(xmlGenericErrorContext,
1284 "xmlXPathNodeSetAdd: out of memory\n");
1285 return;
1286 }
1287 cur->nodeTab = temp;
1288 }
1289 cur->nodeTab[cur->nodeNr++] = val;
1290}
1291
1292/**
1293 * xmlXPathNodeSetAddUnique:
1294 * @cur: the initial node set
1295 * @val: a new xmlNodePtr
1296 *
1297 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1298 * when we are sure the node is not already in the set.
1299 */
1300void
1301xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1302 if (val == NULL) return;
1303
1304 /*
1305 * grow the nodeTab if needed
1306 */
1307 if (cur->nodeMax == 0) {
1308 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1309 sizeof(xmlNodePtr));
1310 if (cur->nodeTab == NULL) {
1311 xmlGenericError(xmlGenericErrorContext,
1312 "xmlXPathNodeSetAddUnique: out of memory\n");
1313 return;
1314 }
1315 memset(cur->nodeTab, 0 ,
1316 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1317 cur->nodeMax = XML_NODESET_DEFAULT;
1318 } else if (cur->nodeNr == cur->nodeMax) {
1319 xmlNodePtr *temp;
1320
1321 cur->nodeMax *= 2;
1322 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1323 sizeof(xmlNodePtr));
1324 if (temp == NULL) {
1325 xmlGenericError(xmlGenericErrorContext,
1326 "xmlXPathNodeSetAddUnique: out of memory\n");
1327 return;
1328 }
1329 cur->nodeTab = temp;
1330 }
1331 cur->nodeTab[cur->nodeNr++] = val;
1332}
1333
1334/**
1335 * xmlXPathNodeSetMerge:
1336 * @val1: the first NodeSet or NULL
1337 * @val2: the second NodeSet
1338 *
1339 * Merges two nodesets, all nodes from @val2 are added to @val1
1340 * if @val1 is NULL, a new set is created and copied from @val2
1341 *
1342 * Returns val1 once extended or NULL in case of error.
1343 */
1344xmlNodeSetPtr
1345xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001346 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001347
1348 if (val2 == NULL) return(val1);
1349 if (val1 == NULL) {
1350 val1 = xmlXPathNodeSetCreate(NULL);
1351 }
1352
1353 initNr = val1->nodeNr;
1354
1355 for (i = 0;i < val2->nodeNr;i++) {
1356 /*
1357 * check against doublons
1358 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001359 skip = 0;
1360 for (j = 0; j < initNr; j++) {
1361 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1362 skip = 1;
1363 break;
1364 }
1365 }
1366 if (skip)
1367 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001368
1369 /*
1370 * grow the nodeTab if needed
1371 */
1372 if (val1->nodeMax == 0) {
1373 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1374 sizeof(xmlNodePtr));
1375 if (val1->nodeTab == NULL) {
1376 xmlGenericError(xmlGenericErrorContext,
1377 "xmlXPathNodeSetMerge: out of memory\n");
1378 return(NULL);
1379 }
1380 memset(val1->nodeTab, 0 ,
1381 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1382 val1->nodeMax = XML_NODESET_DEFAULT;
1383 } else if (val1->nodeNr == val1->nodeMax) {
1384 xmlNodePtr *temp;
1385
1386 val1->nodeMax *= 2;
1387 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1388 sizeof(xmlNodePtr));
1389 if (temp == NULL) {
1390 xmlGenericError(xmlGenericErrorContext,
1391 "xmlXPathNodeSetMerge: out of memory\n");
1392 return(NULL);
1393 }
1394 val1->nodeTab = temp;
1395 }
1396 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1397 }
1398
1399 return(val1);
1400}
1401
1402/**
1403 * xmlXPathNodeSetDel:
1404 * @cur: the initial node set
1405 * @val: an xmlNodePtr
1406 *
1407 * Removes an xmlNodePtr from an existing NodeSet
1408 */
1409void
1410xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1411 int i;
1412
1413 if (cur == NULL) return;
1414 if (val == NULL) return;
1415
1416 /*
1417 * check against doublons
1418 */
1419 for (i = 0;i < cur->nodeNr;i++)
1420 if (cur->nodeTab[i] == val) break;
1421
1422 if (i >= cur->nodeNr) {
1423#ifdef DEBUG
1424 xmlGenericError(xmlGenericErrorContext,
1425 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1426 val->name);
1427#endif
1428 return;
1429 }
1430 cur->nodeNr--;
1431 for (;i < cur->nodeNr;i++)
1432 cur->nodeTab[i] = cur->nodeTab[i + 1];
1433 cur->nodeTab[cur->nodeNr] = NULL;
1434}
1435
1436/**
1437 * xmlXPathNodeSetRemove:
1438 * @cur: the initial node set
1439 * @val: the index to remove
1440 *
1441 * Removes an entry from an existing NodeSet list.
1442 */
1443void
1444xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1445 if (cur == NULL) return;
1446 if (val >= cur->nodeNr) return;
1447 cur->nodeNr--;
1448 for (;val < cur->nodeNr;val++)
1449 cur->nodeTab[val] = cur->nodeTab[val + 1];
1450 cur->nodeTab[cur->nodeNr] = NULL;
1451}
1452
1453/**
1454 * xmlXPathFreeNodeSet:
1455 * @obj: the xmlNodeSetPtr to free
1456 *
1457 * Free the NodeSet compound (not the actual nodes !).
1458 */
1459void
1460xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1461 if (obj == NULL) return;
1462 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001463 xmlFree(obj->nodeTab);
1464 }
Owen Taylor3473f882001-02-23 17:55:21 +00001465 xmlFree(obj);
1466}
1467
1468/**
1469 * xmlXPathFreeValueTree:
1470 * @obj: the xmlNodeSetPtr to free
1471 *
1472 * Free the NodeSet compound and the actual tree, this is different
1473 * from xmlXPathFreeNodeSet()
1474 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001475static void
Owen Taylor3473f882001-02-23 17:55:21 +00001476xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1477 int i;
1478
1479 if (obj == NULL) return;
1480 for (i = 0;i < obj->nodeNr;i++)
1481 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001482 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001483
1484 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001485 xmlFree(obj->nodeTab);
1486 }
Owen Taylor3473f882001-02-23 17:55:21 +00001487 xmlFree(obj);
1488}
1489
1490#if defined(DEBUG) || defined(DEBUG_STEP)
1491/**
1492 * xmlGenericErrorContextNodeSet:
1493 * @output: a FILE * for the output
1494 * @obj: the xmlNodeSetPtr to free
1495 *
1496 * Quick display of a NodeSet
1497 */
1498void
1499xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1500 int i;
1501
1502 if (output == NULL) output = xmlGenericErrorContext;
1503 if (obj == NULL) {
1504 fprintf(output, "NodeSet == NULL !\n");
1505 return;
1506 }
1507 if (obj->nodeNr == 0) {
1508 fprintf(output, "NodeSet is empty\n");
1509 return;
1510 }
1511 if (obj->nodeTab == NULL) {
1512 fprintf(output, " nodeTab == NULL !\n");
1513 return;
1514 }
1515 for (i = 0; i < obj->nodeNr; i++) {
1516 if (obj->nodeTab[i] == NULL) {
1517 fprintf(output, " NULL !\n");
1518 return;
1519 }
1520 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1521 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1522 fprintf(output, " /");
1523 else if (obj->nodeTab[i]->name == NULL)
1524 fprintf(output, " noname!");
1525 else fprintf(output, " %s", obj->nodeTab[i]->name);
1526 }
1527 fprintf(output, "\n");
1528}
1529#endif
1530
1531/**
1532 * xmlXPathNewNodeSet:
1533 * @val: the NodePtr value
1534 *
1535 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1536 * it with the single Node @val
1537 *
1538 * Returns the newly created object.
1539 */
1540xmlXPathObjectPtr
1541xmlXPathNewNodeSet(xmlNodePtr val) {
1542 xmlXPathObjectPtr ret;
1543
1544 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1545 if (ret == NULL) {
1546 xmlGenericError(xmlGenericErrorContext,
1547 "xmlXPathNewNodeSet: out of memory\n");
1548 return(NULL);
1549 }
1550 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1551 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001552 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001553 ret->nodesetval = xmlXPathNodeSetCreate(val);
1554 return(ret);
1555}
1556
1557/**
1558 * xmlXPathNewValueTree:
1559 * @val: the NodePtr value
1560 *
1561 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1562 * it with the tree root @val
1563 *
1564 * Returns the newly created object.
1565 */
1566xmlXPathObjectPtr
1567xmlXPathNewValueTree(xmlNodePtr val) {
1568 xmlXPathObjectPtr ret;
1569
1570 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1571 if (ret == NULL) {
1572 xmlGenericError(xmlGenericErrorContext,
1573 "xmlXPathNewNodeSet: out of memory\n");
1574 return(NULL);
1575 }
1576 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1577 ret->type = XPATH_XSLT_TREE;
1578 ret->nodesetval = xmlXPathNodeSetCreate(val);
1579 return(ret);
1580}
1581
1582/**
1583 * xmlXPathNewNodeSetList:
1584 * @val: an existing NodeSet
1585 *
1586 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1587 * it with the Nodeset @val
1588 *
1589 * Returns the newly created object.
1590 */
1591xmlXPathObjectPtr
1592xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1593 xmlXPathObjectPtr ret;
1594 int i;
1595
1596 if (val == NULL)
1597 ret = NULL;
1598 else if (val->nodeTab == NULL)
1599 ret = xmlXPathNewNodeSet(NULL);
1600 else
1601 {
1602 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1603 for (i = 1; i < val->nodeNr; ++i)
1604 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1605 }
1606
1607 return(ret);
1608}
1609
1610/**
1611 * xmlXPathWrapNodeSet:
1612 * @val: the NodePtr value
1613 *
1614 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1615 *
1616 * Returns the newly created object.
1617 */
1618xmlXPathObjectPtr
1619xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1620 xmlXPathObjectPtr ret;
1621
1622 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1623 if (ret == NULL) {
1624 xmlGenericError(xmlGenericErrorContext,
1625 "xmlXPathWrapNodeSet: out of memory\n");
1626 return(NULL);
1627 }
1628 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1629 ret->type = XPATH_NODESET;
1630 ret->nodesetval = val;
1631 return(ret);
1632}
1633
1634/**
1635 * xmlXPathFreeNodeSetList:
1636 * @obj: an existing NodeSetList object
1637 *
1638 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1639 * the list contrary to xmlXPathFreeObject().
1640 */
1641void
1642xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1643 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001644 xmlFree(obj);
1645}
1646
1647/************************************************************************
1648 * *
1649 * Routines to handle extra functions *
1650 * *
1651 ************************************************************************/
1652
1653/**
1654 * xmlXPathRegisterFunc:
1655 * @ctxt: the XPath context
1656 * @name: the function name
1657 * @f: the function implementation or NULL
1658 *
1659 * Register a new function. If @f is NULL it unregisters the function
1660 *
1661 * Returns 0 in case of success, -1 in case of error
1662 */
1663int
1664xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1665 xmlXPathFunction f) {
1666 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1667}
1668
1669/**
1670 * xmlXPathRegisterFuncNS:
1671 * @ctxt: the XPath context
1672 * @name: the function name
1673 * @ns_uri: the function namespace URI
1674 * @f: the function implementation or NULL
1675 *
1676 * Register a new function. If @f is NULL it unregisters the function
1677 *
1678 * Returns 0 in case of success, -1 in case of error
1679 */
1680int
1681xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1682 const xmlChar *ns_uri, xmlXPathFunction f) {
1683 if (ctxt == NULL)
1684 return(-1);
1685 if (name == NULL)
1686 return(-1);
1687
1688 if (ctxt->funcHash == NULL)
1689 ctxt->funcHash = xmlHashCreate(0);
1690 if (ctxt->funcHash == NULL)
1691 return(-1);
1692 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1693}
1694
1695/**
1696 * xmlXPathFunctionLookup:
1697 * @ctxt: the XPath context
1698 * @name: the function name
1699 *
1700 * Search in the Function array of the context for the given
1701 * function.
1702 *
1703 * Returns the xmlXPathFunction or NULL if not found
1704 */
1705xmlXPathFunction
1706xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1707 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1708}
1709
1710/**
1711 * xmlXPathFunctionLookupNS:
1712 * @ctxt: the XPath context
1713 * @name: the function name
1714 * @ns_uri: the function namespace URI
1715 *
1716 * Search in the Function array of the context for the given
1717 * function.
1718 *
1719 * Returns the xmlXPathFunction or NULL if not found
1720 */
1721xmlXPathFunction
1722xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1723 const xmlChar *ns_uri) {
1724 if (ctxt == NULL)
1725 return(NULL);
1726 if (ctxt->funcHash == NULL)
1727 return(NULL);
1728 if (name == NULL)
1729 return(NULL);
1730
1731 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1732}
1733
1734/**
1735 * xmlXPathRegisteredFuncsCleanup:
1736 * @ctxt: the XPath context
1737 *
1738 * Cleanup the XPath context data associated to registered functions
1739 */
1740void
1741xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1742 if (ctxt == NULL)
1743 return;
1744
1745 xmlHashFree(ctxt->funcHash, NULL);
1746 ctxt->funcHash = NULL;
1747}
1748
1749/************************************************************************
1750 * *
1751 * Routines to handle Variable *
1752 * *
1753 ************************************************************************/
1754
1755/**
1756 * xmlXPathRegisterVariable:
1757 * @ctxt: the XPath context
1758 * @name: the variable name
1759 * @value: the variable value or NULL
1760 *
1761 * Register a new variable value. If @value is NULL it unregisters
1762 * the variable
1763 *
1764 * Returns 0 in case of success, -1 in case of error
1765 */
1766int
1767xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1768 xmlXPathObjectPtr value) {
1769 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1770}
1771
1772/**
1773 * xmlXPathRegisterVariableNS:
1774 * @ctxt: the XPath context
1775 * @name: the variable name
1776 * @ns_uri: the variable namespace URI
1777 * @value: the variable value or NULL
1778 *
1779 * Register a new variable value. If @value is NULL it unregisters
1780 * the variable
1781 *
1782 * Returns 0 in case of success, -1 in case of error
1783 */
1784int
1785xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1786 const xmlChar *ns_uri,
1787 xmlXPathObjectPtr value) {
1788 if (ctxt == NULL)
1789 return(-1);
1790 if (name == NULL)
1791 return(-1);
1792
1793 if (ctxt->varHash == NULL)
1794 ctxt->varHash = xmlHashCreate(0);
1795 if (ctxt->varHash == NULL)
1796 return(-1);
1797 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1798 (void *) value,
1799 (xmlHashDeallocator)xmlXPathFreeObject));
1800}
1801
1802/**
1803 * xmlXPathRegisterVariableLookup:
1804 * @ctxt: the XPath context
1805 * @f: the lookup function
1806 * @data: the lookup data
1807 *
1808 * register an external mechanism to do variable lookup
1809 */
1810void
1811xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1812 xmlXPathVariableLookupFunc f, void *data) {
1813 if (ctxt == NULL)
1814 return;
1815 ctxt->varLookupFunc = (void *) f;
1816 ctxt->varLookupData = data;
1817}
1818
1819/**
1820 * xmlXPathVariableLookup:
1821 * @ctxt: the XPath context
1822 * @name: the variable name
1823 *
1824 * Search in the Variable array of the context for the given
1825 * variable value.
1826 *
1827 * Returns the value or NULL if not found
1828 */
1829xmlXPathObjectPtr
1830xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1831 if (ctxt == NULL)
1832 return(NULL);
1833
1834 if (ctxt->varLookupFunc != NULL) {
1835 xmlXPathObjectPtr ret;
1836
1837 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1838 (ctxt->varLookupData, name, NULL);
1839 if (ret != NULL) return(ret);
1840 }
1841 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1842}
1843
1844/**
1845 * xmlXPathVariableLookupNS:
1846 * @ctxt: the XPath context
1847 * @name: the variable name
1848 * @ns_uri: the variable namespace URI
1849 *
1850 * Search in the Variable array of the context for the given
1851 * variable value.
1852 *
1853 * Returns the value or NULL if not found
1854 */
1855xmlXPathObjectPtr
1856xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1857 const xmlChar *ns_uri) {
1858 if (ctxt == NULL)
1859 return(NULL);
1860
1861 if (ctxt->varLookupFunc != NULL) {
1862 xmlXPathObjectPtr ret;
1863
1864 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1865 (ctxt->varLookupData, name, ns_uri);
1866 if (ret != NULL) return(ret);
1867 }
1868
1869 if (ctxt->varHash == NULL)
1870 return(NULL);
1871 if (name == NULL)
1872 return(NULL);
1873
1874 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1875}
1876
1877/**
1878 * xmlXPathRegisteredVariablesCleanup:
1879 * @ctxt: the XPath context
1880 *
1881 * Cleanup the XPath context data associated to registered variables
1882 */
1883void
1884xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1885 if (ctxt == NULL)
1886 return;
1887
1888 xmlHashFree(ctxt->varHash, NULL);
1889 ctxt->varHash = NULL;
1890}
1891
1892/**
1893 * xmlXPathRegisterNs:
1894 * @ctxt: the XPath context
1895 * @prefix: the namespace prefix
1896 * @ns_uri: the namespace name
1897 *
1898 * Register a new namespace. If @ns_uri is NULL it unregisters
1899 * the namespace
1900 *
1901 * Returns 0 in case of success, -1 in case of error
1902 */
1903int
1904xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1905 const xmlChar *ns_uri) {
1906 if (ctxt == NULL)
1907 return(-1);
1908 if (prefix == NULL)
1909 return(-1);
1910
1911 if (ctxt->nsHash == NULL)
1912 ctxt->nsHash = xmlHashCreate(10);
1913 if (ctxt->nsHash == NULL)
1914 return(-1);
1915 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1916 (xmlHashDeallocator)xmlFree));
1917}
1918
1919/**
1920 * xmlXPathNsLookup:
1921 * @ctxt: the XPath context
1922 * @prefix: the namespace prefix value
1923 *
1924 * Search in the namespace declaration array of the context for the given
1925 * namespace name associated to the given prefix
1926 *
1927 * Returns the value or NULL if not found
1928 */
1929const xmlChar *
1930xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1931 if (ctxt == NULL)
1932 return(NULL);
1933 if (prefix == NULL)
1934 return(NULL);
1935
1936#ifdef XML_XML_NAMESPACE
1937 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1938 return(XML_XML_NAMESPACE);
1939#endif
1940
1941 if (ctxt->nsHash == NULL)
1942 return(NULL);
1943
1944 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1945}
1946
1947/**
1948 * xmlXPathRegisteredVariablesCleanup:
1949 * @ctxt: the XPath context
1950 *
1951 * Cleanup the XPath context data associated to registered variables
1952 */
1953void
1954xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
1955 if (ctxt == NULL)
1956 return;
1957
1958 xmlHashFree(ctxt->nsHash, NULL);
1959 ctxt->nsHash = NULL;
1960}
1961
1962/************************************************************************
1963 * *
1964 * Routines to handle Values *
1965 * *
1966 ************************************************************************/
1967
1968/* Allocations are terrible, one need to optimize all this !!! */
1969
1970/**
1971 * xmlXPathNewFloat:
1972 * @val: the double value
1973 *
1974 * Create a new xmlXPathObjectPtr of type double and of value @val
1975 *
1976 * Returns the newly created object.
1977 */
1978xmlXPathObjectPtr
1979xmlXPathNewFloat(double val) {
1980 xmlXPathObjectPtr ret;
1981
1982 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1983 if (ret == NULL) {
1984 xmlGenericError(xmlGenericErrorContext,
1985 "xmlXPathNewFloat: out of memory\n");
1986 return(NULL);
1987 }
1988 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1989 ret->type = XPATH_NUMBER;
1990 ret->floatval = val;
1991 return(ret);
1992}
1993
1994/**
1995 * xmlXPathNewBoolean:
1996 * @val: the boolean value
1997 *
1998 * Create a new xmlXPathObjectPtr of type boolean and of value @val
1999 *
2000 * Returns the newly created object.
2001 */
2002xmlXPathObjectPtr
2003xmlXPathNewBoolean(int val) {
2004 xmlXPathObjectPtr ret;
2005
2006 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2007 if (ret == NULL) {
2008 xmlGenericError(xmlGenericErrorContext,
2009 "xmlXPathNewBoolean: out of memory\n");
2010 return(NULL);
2011 }
2012 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2013 ret->type = XPATH_BOOLEAN;
2014 ret->boolval = (val != 0);
2015 return(ret);
2016}
2017
2018/**
2019 * xmlXPathNewString:
2020 * @val: the xmlChar * value
2021 *
2022 * Create a new xmlXPathObjectPtr of type string and of value @val
2023 *
2024 * Returns the newly created object.
2025 */
2026xmlXPathObjectPtr
2027xmlXPathNewString(const xmlChar *val) {
2028 xmlXPathObjectPtr ret;
2029
2030 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2031 if (ret == NULL) {
2032 xmlGenericError(xmlGenericErrorContext,
2033 "xmlXPathNewString: out of memory\n");
2034 return(NULL);
2035 }
2036 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2037 ret->type = XPATH_STRING;
2038 if (val != NULL)
2039 ret->stringval = xmlStrdup(val);
2040 else
2041 ret->stringval = xmlStrdup((const xmlChar *)"");
2042 return(ret);
2043}
2044
2045/**
2046 * xmlXPathNewCString:
2047 * @val: the char * value
2048 *
2049 * Create a new xmlXPathObjectPtr of type string and of value @val
2050 *
2051 * Returns the newly created object.
2052 */
2053xmlXPathObjectPtr
2054xmlXPathNewCString(const char *val) {
2055 xmlXPathObjectPtr ret;
2056
2057 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2058 if (ret == NULL) {
2059 xmlGenericError(xmlGenericErrorContext,
2060 "xmlXPathNewCString: out of memory\n");
2061 return(NULL);
2062 }
2063 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2064 ret->type = XPATH_STRING;
2065 ret->stringval = xmlStrdup(BAD_CAST val);
2066 return(ret);
2067}
2068
2069/**
2070 * xmlXPathObjectCopy:
2071 * @val: the original object
2072 *
2073 * allocate a new copy of a given object
2074 *
2075 * Returns the newly created object.
2076 */
2077xmlXPathObjectPtr
2078xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2079 xmlXPathObjectPtr ret;
2080
2081 if (val == NULL)
2082 return(NULL);
2083
2084 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2085 if (ret == NULL) {
2086 xmlGenericError(xmlGenericErrorContext,
2087 "xmlXPathObjectCopy: out of memory\n");
2088 return(NULL);
2089 }
2090 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2091 switch (val->type) {
2092 case XPATH_BOOLEAN:
2093 case XPATH_NUMBER:
2094 case XPATH_POINT:
2095 case XPATH_RANGE:
2096 break;
2097 case XPATH_STRING:
2098 ret->stringval = xmlStrdup(val->stringval);
2099 break;
2100 case XPATH_XSLT_TREE:
2101 if ((val->nodesetval != NULL) &&
2102 (val->nodesetval->nodeTab != NULL))
2103 ret->nodesetval = xmlXPathNodeSetCreate(
2104 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2105 else
2106 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2107 break;
2108 case XPATH_NODESET:
2109 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2110 break;
2111 case XPATH_LOCATIONSET:
2112#ifdef LIBXML_XPTR_ENABLED
2113 {
2114 xmlLocationSetPtr loc = val->user;
2115 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2116 break;
2117 }
2118#endif
2119 case XPATH_UNDEFINED:
2120 case XPATH_USERS:
2121 xmlGenericError(xmlGenericErrorContext,
2122 "xmlXPathObjectCopy: unsupported type %d\n",
2123 val->type);
2124 break;
2125 }
2126 return(ret);
2127}
2128
2129/**
2130 * xmlXPathFreeObject:
2131 * @obj: the object to free
2132 *
2133 * Free up an xmlXPathObjectPtr object.
2134 */
2135void
2136xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2137 if (obj == NULL) return;
2138 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002139 if (obj->boolval) {
2140 obj->type = XPATH_XSLT_TREE;
2141 if (obj->nodesetval != NULL)
2142 xmlXPathFreeValueTree(obj->nodesetval);
2143 } else {
2144 if (obj->nodesetval != NULL)
2145 xmlXPathFreeNodeSet(obj->nodesetval);
2146 }
Owen Taylor3473f882001-02-23 17:55:21 +00002147#ifdef LIBXML_XPTR_ENABLED
2148 } else if (obj->type == XPATH_LOCATIONSET) {
2149 if (obj->user != NULL)
2150 xmlXPtrFreeLocationSet(obj->user);
2151#endif
2152 } else if (obj->type == XPATH_STRING) {
2153 if (obj->stringval != NULL)
2154 xmlFree(obj->stringval);
2155 } else if (obj->type == XPATH_XSLT_TREE) {
2156 if (obj->nodesetval != NULL)
2157 xmlXPathFreeValueTree(obj->nodesetval);
2158 }
2159
Owen Taylor3473f882001-02-23 17:55:21 +00002160 xmlFree(obj);
2161}
2162
2163/************************************************************************
2164 * *
2165 * Routines to handle XPath contexts *
2166 * *
2167 ************************************************************************/
2168
2169/**
2170 * xmlXPathNewContext:
2171 * @doc: the XML document
2172 *
2173 * Create a new xmlXPathContext
2174 *
2175 * Returns the xmlXPathContext just allocated.
2176 */
2177xmlXPathContextPtr
2178xmlXPathNewContext(xmlDocPtr doc) {
2179 xmlXPathContextPtr ret;
2180
2181 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2182 if (ret == NULL) {
2183 xmlGenericError(xmlGenericErrorContext,
2184 "xmlXPathNewContext: out of memory\n");
2185 return(NULL);
2186 }
2187 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2188 ret->doc = doc;
2189 ret->node = NULL;
2190
2191 ret->varHash = NULL;
2192
2193 ret->nb_types = 0;
2194 ret->max_types = 0;
2195 ret->types = NULL;
2196
2197 ret->funcHash = xmlHashCreate(0);
2198
2199 ret->nb_axis = 0;
2200 ret->max_axis = 0;
2201 ret->axis = NULL;
2202
2203 ret->nsHash = NULL;
2204 ret->user = NULL;
2205
2206 ret->contextSize = -1;
2207 ret->proximityPosition = -1;
2208
2209 xmlXPathRegisterAllFunctions(ret);
2210
2211 return(ret);
2212}
2213
2214/**
2215 * xmlXPathFreeContext:
2216 * @ctxt: the context to free
2217 *
2218 * Free up an xmlXPathContext
2219 */
2220void
2221xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2222 xmlXPathRegisteredNsCleanup(ctxt);
2223 xmlXPathRegisteredFuncsCleanup(ctxt);
2224 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002225 xmlFree(ctxt);
2226}
2227
2228/************************************************************************
2229 * *
2230 * Routines to handle XPath parser contexts *
2231 * *
2232 ************************************************************************/
2233
2234#define CHECK_CTXT(ctxt) \
2235 if (ctxt == NULL) { \
2236 xmlGenericError(xmlGenericErrorContext, \
2237 "%s:%d Internal error: ctxt == NULL\n", \
2238 __FILE__, __LINE__); \
2239 } \
2240
2241
2242#define CHECK_CONTEXT(ctxt) \
2243 if (ctxt == NULL) { \
2244 xmlGenericError(xmlGenericErrorContext, \
2245 "%s:%d Internal error: no context\n", \
2246 __FILE__, __LINE__); \
2247 } \
2248 else if (ctxt->doc == NULL) { \
2249 xmlGenericError(xmlGenericErrorContext, \
2250 "%s:%d Internal error: no document\n", \
2251 __FILE__, __LINE__); \
2252 } \
2253 else if (ctxt->doc->children == NULL) { \
2254 xmlGenericError(xmlGenericErrorContext, \
2255 "%s:%d Internal error: document without root\n", \
2256 __FILE__, __LINE__); \
2257 } \
2258
2259
2260/**
2261 * xmlXPathNewParserContext:
2262 * @str: the XPath expression
2263 * @ctxt: the XPath context
2264 *
2265 * Create a new xmlXPathParserContext
2266 *
2267 * Returns the xmlXPathParserContext just allocated.
2268 */
2269xmlXPathParserContextPtr
2270xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2271 xmlXPathParserContextPtr ret;
2272
2273 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2274 if (ret == NULL) {
2275 xmlGenericError(xmlGenericErrorContext,
2276 "xmlXPathNewParserContext: out of memory\n");
2277 return(NULL);
2278 }
2279 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2280 ret->cur = ret->base = str;
2281 ret->context = ctxt;
2282
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002283 ret->comp = xmlXPathNewCompExpr();
2284 if (ret->comp == NULL) {
2285 xmlFree(ret->valueTab);
2286 xmlFree(ret);
2287 return(NULL);
2288 }
2289
2290 return(ret);
2291}
2292
2293/**
2294 * xmlXPathCompParserContext:
2295 * @comp: the XPath compiled expression
2296 * @ctxt: the XPath context
2297 *
2298 * Create a new xmlXPathParserContext when processing a compiled expression
2299 *
2300 * Returns the xmlXPathParserContext just allocated.
2301 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002302static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002303xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2304 xmlXPathParserContextPtr ret;
2305
2306 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2307 if (ret == NULL) {
2308 xmlGenericError(xmlGenericErrorContext,
2309 "xmlXPathNewParserContext: out of memory\n");
2310 return(NULL);
2311 }
2312 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2313
Owen Taylor3473f882001-02-23 17:55:21 +00002314 /* Allocate the value stack */
2315 ret->valueTab = (xmlXPathObjectPtr *)
2316 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002317 if (ret->valueTab == NULL) {
2318 xmlFree(ret);
2319 xmlGenericError(xmlGenericErrorContext,
2320 "xmlXPathNewParserContext: out of memory\n");
2321 return(NULL);
2322 }
Owen Taylor3473f882001-02-23 17:55:21 +00002323 ret->valueNr = 0;
2324 ret->valueMax = 10;
2325 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002326
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002327 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002328 ret->comp = comp;
2329
Owen Taylor3473f882001-02-23 17:55:21 +00002330 return(ret);
2331}
2332
2333/**
2334 * xmlXPathFreeParserContext:
2335 * @ctxt: the context to free
2336 *
2337 * Free up an xmlXPathParserContext
2338 */
2339void
2340xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2341 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002342 xmlFree(ctxt->valueTab);
2343 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002344 if (ctxt->comp)
2345 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002346 xmlFree(ctxt);
2347}
2348
2349/************************************************************************
2350 * *
2351 * The implicit core function library *
2352 * *
2353 ************************************************************************/
2354
2355/*
2356 * Auto-pop and cast to a number
2357 */
2358void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
2359
2360
2361#define POP_FLOAT \
2362 arg = valuePop(ctxt); \
2363 if (arg == NULL) { \
2364 XP_ERROR(XPATH_INVALID_OPERAND); \
2365 } \
2366 if (arg->type != XPATH_NUMBER) { \
2367 valuePush(ctxt, arg); \
2368 xmlXPathNumberFunction(ctxt, 1); \
2369 arg = valuePop(ctxt); \
2370 }
2371
2372/**
2373 * xmlXPathCompareNodeSetFloat:
2374 * @ctxt: the XPath Parser context
2375 * @inf: less than (1) or greater than (0)
2376 * @strict: is the comparison strict
2377 * @arg: the node set
2378 * @f: the value
2379 *
2380 * Implement the compare operation between a nodeset and a number
2381 * @ns < @val (1, 1, ...
2382 * @ns <= @val (1, 0, ...
2383 * @ns > @val (0, 1, ...
2384 * @ns >= @val (0, 0, ...
2385 *
2386 * If one object to be compared is a node-set and the other is a number,
2387 * then the comparison will be true if and only if there is a node in the
2388 * node-set such that the result of performing the comparison on the number
2389 * to be compared and on the result of converting the string-value of that
2390 * node to a number using the number function is true.
2391 *
2392 * Returns 0 or 1 depending on the results of the test.
2393 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002394static int
Owen Taylor3473f882001-02-23 17:55:21 +00002395xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2396 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2397 int i, ret = 0;
2398 xmlNodeSetPtr ns;
2399 xmlChar *str2;
2400
2401 if ((f == NULL) || (arg == NULL) ||
2402 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2403 xmlXPathFreeObject(arg);
2404 xmlXPathFreeObject(f);
2405 return(0);
2406 }
2407 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002408 if (ns != NULL) {
2409 for (i = 0;i < ns->nodeNr;i++) {
2410 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2411 if (str2 != NULL) {
2412 valuePush(ctxt,
2413 xmlXPathNewString(str2));
2414 xmlFree(str2);
2415 xmlXPathNumberFunction(ctxt, 1);
2416 valuePush(ctxt, xmlXPathObjectCopy(f));
2417 ret = xmlXPathCompareValues(ctxt, inf, strict);
2418 if (ret)
2419 break;
2420 }
2421 }
Owen Taylor3473f882001-02-23 17:55:21 +00002422 }
2423 xmlXPathFreeObject(arg);
2424 xmlXPathFreeObject(f);
2425 return(ret);
2426}
2427
2428/**
2429 * xmlXPathCompareNodeSetString:
2430 * @ctxt: the XPath Parser context
2431 * @inf: less than (1) or greater than (0)
2432 * @strict: is the comparison strict
2433 * @arg: the node set
2434 * @s: the value
2435 *
2436 * Implement the compare operation between a nodeset and a string
2437 * @ns < @val (1, 1, ...
2438 * @ns <= @val (1, 0, ...
2439 * @ns > @val (0, 1, ...
2440 * @ns >= @val (0, 0, ...
2441 *
2442 * If one object to be compared is a node-set and the other is a string,
2443 * then the comparison will be true if and only if there is a node in
2444 * the node-set such that the result of performing the comparison on the
2445 * string-value of the node and the other string is true.
2446 *
2447 * Returns 0 or 1 depending on the results of the test.
2448 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002449static int
Owen Taylor3473f882001-02-23 17:55:21 +00002450xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2451 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2452 int i, ret = 0;
2453 xmlNodeSetPtr ns;
2454 xmlChar *str2;
2455
2456 if ((s == NULL) || (arg == NULL) ||
2457 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2458 xmlXPathFreeObject(arg);
2459 xmlXPathFreeObject(s);
2460 return(0);
2461 }
2462 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002463 if (ns != NULL) {
2464 for (i = 0;i < ns->nodeNr;i++) {
2465 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2466 if (str2 != NULL) {
2467 valuePush(ctxt,
2468 xmlXPathNewString(str2));
2469 xmlFree(str2);
2470 valuePush(ctxt, xmlXPathObjectCopy(s));
2471 ret = xmlXPathCompareValues(ctxt, inf, strict);
2472 if (ret)
2473 break;
2474 }
2475 }
Owen Taylor3473f882001-02-23 17:55:21 +00002476 }
2477 xmlXPathFreeObject(arg);
2478 xmlXPathFreeObject(s);
2479 return(ret);
2480}
2481
2482/**
2483 * xmlXPathCompareNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00002484 * @op: less than (-1), equal (0) or greater than (1)
2485 * @strict: is the comparison strict
2486 * @arg1: the fist node set object
2487 * @arg2: the second node set object
2488 *
2489 * Implement the compare operation on nodesets:
2490 *
2491 * If both objects to be compared are node-sets, then the comparison
2492 * will be true if and only if there is a node in the first node-set
2493 * and a node in the second node-set such that the result of performing
2494 * the comparison on the string-values of the two nodes is true.
2495 * ....
2496 * When neither object to be compared is a node-set and the operator
2497 * is <=, <, >= or >, then the objects are compared by converting both
2498 * objects to numbers and comparing the numbers according to IEEE 754.
2499 * ....
2500 * The number function converts its argument to a number as follows:
2501 * - a string that consists of optional whitespace followed by an
2502 * optional minus sign followed by a Number followed by whitespace
2503 * is converted to the IEEE 754 number that is nearest (according
2504 * to the IEEE 754 round-to-nearest rule) to the mathematical value
2505 * represented by the string; any other string is converted to NaN
2506 *
2507 * Conclusion all nodes need to be converted first to their string value
2508 * and then the comparison must be done when possible
2509 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002510static int
2511xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00002512 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2513 int i, j, init = 0;
2514 double val1;
2515 double *values2;
2516 int ret = 0;
2517 xmlChar *str;
2518 xmlNodeSetPtr ns1;
2519 xmlNodeSetPtr ns2;
2520
2521 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002522 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
2523 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002524 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002525 }
Owen Taylor3473f882001-02-23 17:55:21 +00002526 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002527 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
2528 xmlXPathFreeObject(arg1);
2529 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002530 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002531 }
Owen Taylor3473f882001-02-23 17:55:21 +00002532
2533 ns1 = arg1->nodesetval;
2534 ns2 = arg2->nodesetval;
2535
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002536 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002537 xmlXPathFreeObject(arg1);
2538 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002539 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002540 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002541 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002542 xmlXPathFreeObject(arg1);
2543 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002544 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002545 }
Owen Taylor3473f882001-02-23 17:55:21 +00002546
2547 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
2548 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002549 xmlXPathFreeObject(arg1);
2550 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002551 return(0);
2552 }
2553 for (i = 0;i < ns1->nodeNr;i++) {
2554 str = xmlNodeGetContent(ns1->nodeTab[i]);
2555 if (str == NULL)
2556 continue;
2557 val1 = xmlXPathStringEvalNumber(str);
2558 xmlFree(str);
2559 if (isnan(val1))
2560 continue;
2561 for (j = 0;j < ns2->nodeNr;j++) {
2562 if (init == 0) {
2563 str = xmlNodeGetContent(ns2->nodeTab[j]);
2564 if (str == NULL) {
2565 values2[j] = xmlXPathNAN;
2566 } else {
2567 values2[j] = xmlXPathStringEvalNumber(str);
2568 xmlFree(str);
2569 }
2570 }
2571 if (isnan(values2[j]))
2572 continue;
2573 if (inf && strict)
2574 ret = (val1 < values2[j]);
2575 else 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 if (ret)
2582 break;
2583 }
2584 if (ret)
2585 break;
2586 init = 1;
2587 }
2588 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002589 xmlXPathFreeObject(arg1);
2590 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002591 return(ret);
2592 return(0);
2593}
2594
2595/**
2596 * xmlXPathCompareNodeSetValue:
2597 * @ctxt: the XPath Parser context
2598 * @inf: less than (1) or greater than (0)
2599 * @strict: is the comparison strict
2600 * @arg: the node set
2601 * @val: the value
2602 *
2603 * Implement the compare operation between a nodeset and a value
2604 * @ns < @val (1, 1, ...
2605 * @ns <= @val (1, 0, ...
2606 * @ns > @val (0, 1, ...
2607 * @ns >= @val (0, 0, ...
2608 *
2609 * If one object to be compared is a node-set and the other is a boolean,
2610 * then the comparison will be true if and only if the result of performing
2611 * the comparison on the boolean and on the result of converting
2612 * the node-set to a boolean using the boolean function is true.
2613 *
2614 * Returns 0 or 1 depending on the results of the test.
2615 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002616static int
Owen Taylor3473f882001-02-23 17:55:21 +00002617xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
2618 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
2619 if ((val == NULL) || (arg == NULL) ||
2620 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2621 return(0);
2622
2623 switch(val->type) {
2624 case XPATH_NUMBER:
2625 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
2626 case XPATH_NODESET:
2627 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002628 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00002629 case XPATH_STRING:
2630 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
2631 case XPATH_BOOLEAN:
2632 valuePush(ctxt, arg);
2633 xmlXPathBooleanFunction(ctxt, 1);
2634 valuePush(ctxt, val);
2635 return(xmlXPathCompareValues(ctxt, inf, strict));
2636 default:
2637 TODO
2638 return(0);
2639 }
2640 return(0);
2641}
2642
2643/**
2644 * xmlXPathEqualNodeSetString
2645 * @arg: the nodeset object argument
2646 * @str: the string to compare to.
2647 *
2648 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2649 * If one object to be compared is a node-set and the other is a string,
2650 * then the comparison will be true if and only if there is a node in
2651 * the node-set such that the result of performing the comparison on the
2652 * string-value of the node and the other string is true.
2653 *
2654 * Returns 0 or 1 depending on the results of the test.
2655 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002656static int
Owen Taylor3473f882001-02-23 17:55:21 +00002657xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
2658 int i;
2659 xmlNodeSetPtr ns;
2660 xmlChar *str2;
2661
2662 if ((str == NULL) || (arg == NULL) ||
2663 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2664 return(0);
2665 ns = arg->nodesetval;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002666 if (ns == NULL)
2667 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002668 if (ns->nodeNr <= 0)
2669 return(0);
2670 for (i = 0;i < ns->nodeNr;i++) {
2671 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2672 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
2673 xmlFree(str2);
2674 return(1);
2675 }
2676 if (str2 != NULL)
2677 xmlFree(str2);
2678 }
2679 return(0);
2680}
2681
2682/**
2683 * xmlXPathEqualNodeSetFloat
2684 * @arg: the nodeset object argument
2685 * @f: the float to compare to
2686 *
2687 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2688 * If one object to be compared is a node-set and the other is a number,
2689 * then the comparison will be true if and only if there is a node in
2690 * the node-set such that the result of performing the comparison on the
2691 * number to be compared and on the result of converting the string-value
2692 * of that node to a number using the number function is true.
2693 *
2694 * Returns 0 or 1 depending on the results of the test.
2695 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002696static int
Owen Taylor3473f882001-02-23 17:55:21 +00002697xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
2698 char buf[100] = "";
2699
2700 if ((arg == NULL) ||
2701 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2702 return(0);
2703
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002704 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00002705 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
2706}
2707
2708
2709/**
2710 * xmlXPathEqualNodeSets
2711 * @arg1: first nodeset object argument
2712 * @arg2: second nodeset object argument
2713 *
2714 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
2715 * If both objects to be compared are node-sets, then the comparison
2716 * will be true if and only if there is a node in the first node-set and
2717 * a node in the second node-set such that the result of performing the
2718 * comparison on the string-values of the two nodes is true.
2719 *
2720 * (needless to say, this is a costly operation)
2721 *
2722 * Returns 0 or 1 depending on the results of the test.
2723 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002724static int
Owen Taylor3473f882001-02-23 17:55:21 +00002725xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2726 int i, j;
2727 xmlChar **values1;
2728 xmlChar **values2;
2729 int ret = 0;
2730 xmlNodeSetPtr ns1;
2731 xmlNodeSetPtr ns2;
2732
2733 if ((arg1 == NULL) ||
2734 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
2735 return(0);
2736 if ((arg2 == NULL) ||
2737 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
2738 return(0);
2739
2740 ns1 = arg1->nodesetval;
2741 ns2 = arg2->nodesetval;
2742
Daniel Veillard911f49a2001-04-07 15:39:35 +00002743 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00002744 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002745 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00002746 return(0);
2747
2748 /*
2749 * check if there is a node pertaining to both sets
2750 */
2751 for (i = 0;i < ns1->nodeNr;i++)
2752 for (j = 0;j < ns2->nodeNr;j++)
2753 if (ns1->nodeTab[i] == ns2->nodeTab[j])
2754 return(1);
2755
2756 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
2757 if (values1 == NULL)
2758 return(0);
2759 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
2760 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
2761 if (values2 == NULL) {
2762 xmlFree(values1);
2763 return(0);
2764 }
2765 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
2766 for (i = 0;i < ns1->nodeNr;i++) {
2767 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
2768 for (j = 0;j < ns2->nodeNr;j++) {
2769 if (i == 0)
2770 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
2771 ret = xmlStrEqual(values1[i], values2[j]);
2772 if (ret)
2773 break;
2774 }
2775 if (ret)
2776 break;
2777 }
2778 for (i = 0;i < ns1->nodeNr;i++)
2779 if (values1[i] != NULL)
2780 xmlFree(values1[i]);
2781 for (j = 0;j < ns2->nodeNr;j++)
2782 if (values2[j] != NULL)
2783 xmlFree(values2[j]);
2784 xmlFree(values1);
2785 xmlFree(values2);
2786 return(ret);
2787}
2788
2789/**
2790 * xmlXPathEqualValues:
2791 * @ctxt: the XPath Parser context
2792 *
2793 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2794 *
2795 * Returns 0 or 1 depending on the results of the test.
2796 */
2797int
2798xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
2799 xmlXPathObjectPtr arg1, arg2;
2800 int ret = 0;
2801
2802 arg1 = valuePop(ctxt);
2803 if (arg1 == NULL)
2804 XP_ERROR0(XPATH_INVALID_OPERAND);
2805
2806 arg2 = valuePop(ctxt);
2807 if (arg2 == NULL) {
2808 xmlXPathFreeObject(arg1);
2809 XP_ERROR0(XPATH_INVALID_OPERAND);
2810 }
2811
2812 if (arg1 == arg2) {
2813#ifdef DEBUG_EXPR
2814 xmlGenericError(xmlGenericErrorContext,
2815 "Equal: by pointer\n");
2816#endif
2817 return(1);
2818 }
2819
2820 switch (arg1->type) {
2821 case XPATH_UNDEFINED:
2822#ifdef DEBUG_EXPR
2823 xmlGenericError(xmlGenericErrorContext,
2824 "Equal: undefined\n");
2825#endif
2826 break;
2827 case XPATH_XSLT_TREE:
2828 case XPATH_NODESET:
2829 switch (arg2->type) {
2830 case XPATH_UNDEFINED:
2831#ifdef DEBUG_EXPR
2832 xmlGenericError(xmlGenericErrorContext,
2833 "Equal: undefined\n");
2834#endif
2835 break;
2836 case XPATH_XSLT_TREE:
2837 case XPATH_NODESET:
2838 ret = xmlXPathEqualNodeSets(arg1, arg2);
2839 break;
2840 case XPATH_BOOLEAN:
2841 if ((arg1->nodesetval == NULL) ||
2842 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2843 else
2844 ret = 1;
2845 ret = (ret == arg2->boolval);
2846 break;
2847 case XPATH_NUMBER:
2848 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2849 break;
2850 case XPATH_STRING:
2851 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2852 break;
2853 case XPATH_USERS:
2854 case XPATH_POINT:
2855 case XPATH_RANGE:
2856 case XPATH_LOCATIONSET:
2857 TODO
2858 break;
2859 }
2860 break;
2861 case XPATH_BOOLEAN:
2862 switch (arg2->type) {
2863 case XPATH_UNDEFINED:
2864#ifdef DEBUG_EXPR
2865 xmlGenericError(xmlGenericErrorContext,
2866 "Equal: undefined\n");
2867#endif
2868 break;
2869 case XPATH_NODESET:
2870 case XPATH_XSLT_TREE:
2871 if ((arg2->nodesetval == NULL) ||
2872 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2873 else
2874 ret = 1;
2875 break;
2876 case XPATH_BOOLEAN:
2877#ifdef DEBUG_EXPR
2878 xmlGenericError(xmlGenericErrorContext,
2879 "Equal: %d boolean %d \n",
2880 arg1->boolval, arg2->boolval);
2881#endif
2882 ret = (arg1->boolval == arg2->boolval);
2883 break;
2884 case XPATH_NUMBER:
2885 if (arg2->floatval) ret = 1;
2886 else ret = 0;
2887 ret = (arg1->boolval == ret);
2888 break;
2889 case XPATH_STRING:
2890 if ((arg2->stringval == NULL) ||
2891 (arg2->stringval[0] == 0)) ret = 0;
2892 else
2893 ret = 1;
2894 ret = (arg1->boolval == ret);
2895 break;
2896 case XPATH_USERS:
2897 case XPATH_POINT:
2898 case XPATH_RANGE:
2899 case XPATH_LOCATIONSET:
2900 TODO
2901 break;
2902 }
2903 break;
2904 case XPATH_NUMBER:
2905 switch (arg2->type) {
2906 case XPATH_UNDEFINED:
2907#ifdef DEBUG_EXPR
2908 xmlGenericError(xmlGenericErrorContext,
2909 "Equal: undefined\n");
2910#endif
2911 break;
2912 case XPATH_NODESET:
2913 case XPATH_XSLT_TREE:
2914 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2915 break;
2916 case XPATH_BOOLEAN:
2917 if (arg1->floatval) ret = 1;
2918 else ret = 0;
2919 ret = (arg2->boolval == ret);
2920 break;
2921 case XPATH_STRING:
2922 valuePush(ctxt, arg2);
2923 xmlXPathNumberFunction(ctxt, 1);
2924 arg2 = valuePop(ctxt);
2925 /* no break on purpose */
2926 case XPATH_NUMBER:
2927 ret = (arg1->floatval == arg2->floatval);
2928 break;
2929 case XPATH_USERS:
2930 case XPATH_POINT:
2931 case XPATH_RANGE:
2932 case XPATH_LOCATIONSET:
2933 TODO
2934 break;
2935 }
2936 break;
2937 case XPATH_STRING:
2938 switch (arg2->type) {
2939 case XPATH_UNDEFINED:
2940#ifdef DEBUG_EXPR
2941 xmlGenericError(xmlGenericErrorContext,
2942 "Equal: undefined\n");
2943#endif
2944 break;
2945 case XPATH_NODESET:
2946 case XPATH_XSLT_TREE:
2947 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2948 break;
2949 case XPATH_BOOLEAN:
2950 if ((arg1->stringval == NULL) ||
2951 (arg1->stringval[0] == 0)) ret = 0;
2952 else
2953 ret = 1;
2954 ret = (arg2->boolval == ret);
2955 break;
2956 case XPATH_STRING:
2957 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
2958 break;
2959 case XPATH_NUMBER:
2960 valuePush(ctxt, arg1);
2961 xmlXPathNumberFunction(ctxt, 1);
2962 arg1 = valuePop(ctxt);
2963 ret = (arg1->floatval == arg2->floatval);
2964 break;
2965 case XPATH_USERS:
2966 case XPATH_POINT:
2967 case XPATH_RANGE:
2968 case XPATH_LOCATIONSET:
2969 TODO
2970 break;
2971 }
2972 break;
2973 case XPATH_USERS:
2974 case XPATH_POINT:
2975 case XPATH_RANGE:
2976 case XPATH_LOCATIONSET:
2977 TODO
2978 break;
2979 }
2980 xmlXPathFreeObject(arg1);
2981 xmlXPathFreeObject(arg2);
2982 return(ret);
2983}
2984
2985
2986/**
2987 * xmlXPathCompareValues:
2988 * @ctxt: the XPath Parser context
2989 * @inf: less than (1) or greater than (0)
2990 * @strict: is the comparison strict
2991 *
2992 * Implement the compare operation on XPath objects:
2993 * @arg1 < @arg2 (1, 1, ...
2994 * @arg1 <= @arg2 (1, 0, ...
2995 * @arg1 > @arg2 (0, 1, ...
2996 * @arg1 >= @arg2 (0, 0, ...
2997 *
2998 * When neither object to be compared is a node-set and the operator is
2999 * <=, <, >=, >, then the objects are compared by converted both objects
3000 * to numbers and comparing the numbers according to IEEE 754. The <
3001 * comparison will be true if and only if the first number is less than the
3002 * second number. The <= comparison will be true if and only if the first
3003 * number is less than or equal to the second number. The > comparison
3004 * will be true if and only if the first number is greater than the second
3005 * number. The >= comparison will be true if and only if the first number
3006 * is greater than or equal to the second number.
3007 *
3008 * Returns 1 if the comparaison succeeded, 0 if it failed
3009 */
3010int
3011xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3012 int ret = 0;
3013 xmlXPathObjectPtr arg1, arg2;
3014
3015 arg2 = valuePop(ctxt);
3016 if (arg2 == NULL) {
3017 XP_ERROR0(XPATH_INVALID_OPERAND);
3018 }
3019
3020 arg1 = valuePop(ctxt);
3021 if (arg1 == NULL) {
3022 xmlXPathFreeObject(arg2);
3023 XP_ERROR0(XPATH_INVALID_OPERAND);
3024 }
3025
3026 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3027 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003028 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003029 } else {
3030 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003031 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3032 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003033 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003034 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3035 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003036 }
3037 }
3038 return(ret);
3039 }
3040
3041 if (arg1->type != XPATH_NUMBER) {
3042 valuePush(ctxt, arg1);
3043 xmlXPathNumberFunction(ctxt, 1);
3044 arg1 = valuePop(ctxt);
3045 }
3046 if (arg1->type != XPATH_NUMBER) {
3047 xmlXPathFreeObject(arg1);
3048 xmlXPathFreeObject(arg2);
3049 XP_ERROR0(XPATH_INVALID_OPERAND);
3050 }
3051 if (arg2->type != XPATH_NUMBER) {
3052 valuePush(ctxt, arg2);
3053 xmlXPathNumberFunction(ctxt, 1);
3054 arg2 = valuePop(ctxt);
3055 }
3056 if (arg2->type != XPATH_NUMBER) {
3057 xmlXPathFreeObject(arg1);
3058 xmlXPathFreeObject(arg2);
3059 XP_ERROR0(XPATH_INVALID_OPERAND);
3060 }
3061 /*
3062 * Add tests for infinity and nan
3063 * => feedback on 3.4 for Inf and NaN
3064 */
3065 if (inf && strict)
3066 ret = (arg1->floatval < arg2->floatval);
3067 else 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 xmlXPathFreeObject(arg1);
3074 xmlXPathFreeObject(arg2);
3075 return(ret);
3076}
3077
3078/**
3079 * xmlXPathValueFlipSign:
3080 * @ctxt: the XPath Parser context
3081 *
3082 * Implement the unary - operation on an XPath object
3083 * The numeric operators convert their operands to numbers as if
3084 * by calling the number function.
3085 */
3086void
3087xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
3088 xmlXPathObjectPtr arg;
3089
3090 POP_FLOAT
3091 arg->floatval = -arg->floatval;
3092 valuePush(ctxt, arg);
3093}
3094
3095/**
3096 * xmlXPathAddValues:
3097 * @ctxt: the XPath Parser context
3098 *
3099 * Implement the add operation on XPath objects:
3100 * The numeric operators convert their operands to numbers as if
3101 * by calling the number function.
3102 */
3103void
3104xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3105 xmlXPathObjectPtr arg;
3106 double val;
3107
3108 POP_FLOAT
3109 val = arg->floatval;
3110 xmlXPathFreeObject(arg);
3111
3112 POP_FLOAT
3113 arg->floatval += val;
3114 valuePush(ctxt, arg);
3115}
3116
3117/**
3118 * xmlXPathSubValues:
3119 * @ctxt: the XPath Parser context
3120 *
3121 * Implement the substraction operation on XPath objects:
3122 * The numeric operators convert their operands to numbers as if
3123 * by calling the number function.
3124 */
3125void
3126xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3127 xmlXPathObjectPtr arg;
3128 double val;
3129
3130 POP_FLOAT
3131 val = arg->floatval;
3132 xmlXPathFreeObject(arg);
3133
3134 POP_FLOAT
3135 arg->floatval -= val;
3136 valuePush(ctxt, arg);
3137}
3138
3139/**
3140 * xmlXPathMultValues:
3141 * @ctxt: the XPath Parser context
3142 *
3143 * Implement the multiply operation on XPath objects:
3144 * The numeric operators convert their operands to numbers as if
3145 * by calling the number function.
3146 */
3147void
3148xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3149 xmlXPathObjectPtr arg;
3150 double val;
3151
3152 POP_FLOAT
3153 val = arg->floatval;
3154 xmlXPathFreeObject(arg);
3155
3156 POP_FLOAT
3157 arg->floatval *= val;
3158 valuePush(ctxt, arg);
3159}
3160
3161/**
3162 * xmlXPathDivValues:
3163 * @ctxt: the XPath Parser context
3164 *
3165 * Implement the div operation on XPath objects @arg1 / @arg2:
3166 * The numeric operators convert their operands to numbers as if
3167 * by calling the number function.
3168 */
3169void
3170xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3171 xmlXPathObjectPtr arg;
3172 double val;
3173
3174 POP_FLOAT
3175 val = arg->floatval;
3176 xmlXPathFreeObject(arg);
3177
3178 POP_FLOAT
3179 arg->floatval /= val;
3180 valuePush(ctxt, arg);
3181}
3182
3183/**
3184 * xmlXPathModValues:
3185 * @ctxt: the XPath Parser context
3186 *
3187 * Implement the mod operation on XPath objects: @arg1 / @arg2
3188 * The numeric operators convert their operands to numbers as if
3189 * by calling the number function.
3190 */
3191void
3192xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3193 xmlXPathObjectPtr arg;
3194 int arg1, arg2;
3195
3196 POP_FLOAT
3197 arg2 = (int) arg->floatval;
3198 xmlXPathFreeObject(arg);
3199
3200 POP_FLOAT
3201 arg1 = (int) arg->floatval;
3202 arg->floatval = arg1 % arg2;
3203 valuePush(ctxt, arg);
3204}
3205
3206/************************************************************************
3207 * *
3208 * The traversal functions *
3209 * *
3210 ************************************************************************/
3211
Owen Taylor3473f882001-02-23 17:55:21 +00003212/*
3213 * A traversal function enumerates nodes along an axis.
3214 * Initially it must be called with NULL, and it indicates
3215 * termination on the axis by returning NULL.
3216 */
3217typedef xmlNodePtr (*xmlXPathTraversalFunction)
3218 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3219
3220/**
3221 * xmlXPathNextSelf:
3222 * @ctxt: the XPath Parser context
3223 * @cur: the current node in the traversal
3224 *
3225 * Traversal function for the "self" direction
3226 * The self axis contains just the context node itself
3227 *
3228 * Returns the next element following that axis
3229 */
3230xmlNodePtr
3231xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3232 if (cur == NULL)
3233 return(ctxt->context->node);
3234 return(NULL);
3235}
3236
3237/**
3238 * xmlXPathNextChild:
3239 * @ctxt: the XPath Parser context
3240 * @cur: the current node in the traversal
3241 *
3242 * Traversal function for the "child" direction
3243 * The child axis contains the children of the context node in document order.
3244 *
3245 * Returns the next element following that axis
3246 */
3247xmlNodePtr
3248xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3249 if (cur == NULL) {
3250 if (ctxt->context->node == NULL) return(NULL);
3251 switch (ctxt->context->node->type) {
3252 case XML_ELEMENT_NODE:
3253 case XML_TEXT_NODE:
3254 case XML_CDATA_SECTION_NODE:
3255 case XML_ENTITY_REF_NODE:
3256 case XML_ENTITY_NODE:
3257 case XML_PI_NODE:
3258 case XML_COMMENT_NODE:
3259 case XML_NOTATION_NODE:
3260 case XML_DTD_NODE:
3261 return(ctxt->context->node->children);
3262 case XML_DOCUMENT_NODE:
3263 case XML_DOCUMENT_TYPE_NODE:
3264 case XML_DOCUMENT_FRAG_NODE:
3265 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003266#ifdef LIBXML_DOCB_ENABLED
3267 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003268#endif
3269 return(((xmlDocPtr) ctxt->context->node)->children);
3270 case XML_ELEMENT_DECL:
3271 case XML_ATTRIBUTE_DECL:
3272 case XML_ENTITY_DECL:
3273 case XML_ATTRIBUTE_NODE:
3274 case XML_NAMESPACE_DECL:
3275 case XML_XINCLUDE_START:
3276 case XML_XINCLUDE_END:
3277 return(NULL);
3278 }
3279 return(NULL);
3280 }
3281 if ((cur->type == XML_DOCUMENT_NODE) ||
3282 (cur->type == XML_HTML_DOCUMENT_NODE))
3283 return(NULL);
3284 return(cur->next);
3285}
3286
3287/**
3288 * xmlXPathNextDescendant:
3289 * @ctxt: the XPath Parser context
3290 * @cur: the current node in the traversal
3291 *
3292 * Traversal function for the "descendant" direction
3293 * the descendant axis contains the descendants of the context node in document
3294 * order; a descendant is a child or a child of a child and so on.
3295 *
3296 * Returns the next element following that axis
3297 */
3298xmlNodePtr
3299xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3300 if (cur == NULL) {
3301 if (ctxt->context->node == NULL)
3302 return(NULL);
3303 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3304 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3305 return(NULL);
3306
3307 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3308 return(ctxt->context->doc->children);
3309 return(ctxt->context->node->children);
3310 }
3311
3312 if (cur->children != NULL)
3313 {
3314 if (cur->children->type != XML_ENTITY_DECL)
3315 return(cur->children);
3316 }
3317 if (cur->next != NULL) return(cur->next);
3318
3319 do {
3320 cur = cur->parent;
3321 if (cur == NULL) return(NULL);
3322 if (cur == ctxt->context->node) return(NULL);
3323 if (cur->next != NULL) {
3324 cur = cur->next;
3325 return(cur);
3326 }
3327 } while (cur != NULL);
3328 return(cur);
3329}
3330
3331/**
3332 * xmlXPathNextDescendantOrSelf:
3333 * @ctxt: the XPath Parser context
3334 * @cur: the current node in the traversal
3335 *
3336 * Traversal function for the "descendant-or-self" direction
3337 * the descendant-or-self axis contains the context node and the descendants
3338 * of the context node in document order; thus the context node is the first
3339 * node on the axis, and the first child of the context node is the second node
3340 * on the axis
3341 *
3342 * Returns the next element following that axis
3343 */
3344xmlNodePtr
3345xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3346 if (cur == NULL) {
3347 if (ctxt->context->node == NULL)
3348 return(NULL);
3349 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3350 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3351 return(NULL);
3352 return(ctxt->context->node);
3353 }
3354
3355 return(xmlXPathNextDescendant(ctxt, cur));
3356}
3357
3358/**
3359 * xmlXPathNextParent:
3360 * @ctxt: the XPath Parser context
3361 * @cur: the current node in the traversal
3362 *
3363 * Traversal function for the "parent" direction
3364 * The parent axis contains the parent of the context node, if there is one.
3365 *
3366 * Returns the next element following that axis
3367 */
3368xmlNodePtr
3369xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3370 /*
3371 * the parent of an attribute or namespace node is the element
3372 * to which the attribute or namespace node is attached
3373 * Namespace handling !!!
3374 */
3375 if (cur == NULL) {
3376 if (ctxt->context->node == NULL) return(NULL);
3377 switch (ctxt->context->node->type) {
3378 case XML_ELEMENT_NODE:
3379 case XML_TEXT_NODE:
3380 case XML_CDATA_SECTION_NODE:
3381 case XML_ENTITY_REF_NODE:
3382 case XML_ENTITY_NODE:
3383 case XML_PI_NODE:
3384 case XML_COMMENT_NODE:
3385 case XML_NOTATION_NODE:
3386 case XML_DTD_NODE:
3387 case XML_ELEMENT_DECL:
3388 case XML_ATTRIBUTE_DECL:
3389 case XML_XINCLUDE_START:
3390 case XML_XINCLUDE_END:
3391 case XML_ENTITY_DECL:
3392 if (ctxt->context->node->parent == NULL)
3393 return((xmlNodePtr) ctxt->context->doc);
3394 return(ctxt->context->node->parent);
3395 case XML_ATTRIBUTE_NODE: {
3396 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3397
3398 return(att->parent);
3399 }
3400 case XML_DOCUMENT_NODE:
3401 case XML_DOCUMENT_TYPE_NODE:
3402 case XML_DOCUMENT_FRAG_NODE:
3403 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003404#ifdef LIBXML_DOCB_ENABLED
3405 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003406#endif
3407 return(NULL);
3408 case XML_NAMESPACE_DECL:
3409 /*
3410 * TODO !!! may require extending struct _xmlNs with
3411 * parent field
3412 * C.f. Infoset case...
3413 */
3414 return(NULL);
3415 }
3416 }
3417 return(NULL);
3418}
3419
3420/**
3421 * xmlXPathNextAncestor:
3422 * @ctxt: the XPath Parser context
3423 * @cur: the current node in the traversal
3424 *
3425 * Traversal function for the "ancestor" direction
3426 * the ancestor axis contains the ancestors of the context node; the ancestors
3427 * of the context node consist of the parent of context node and the parent's
3428 * parent and so on; the nodes are ordered in reverse document order; thus the
3429 * parent is the first node on the axis, and the parent's parent is the second
3430 * node on the axis
3431 *
3432 * Returns the next element following that axis
3433 */
3434xmlNodePtr
3435xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3436 /*
3437 * the parent of an attribute or namespace node is the element
3438 * to which the attribute or namespace node is attached
3439 * !!!!!!!!!!!!!
3440 */
3441 if (cur == NULL) {
3442 if (ctxt->context->node == NULL) return(NULL);
3443 switch (ctxt->context->node->type) {
3444 case XML_ELEMENT_NODE:
3445 case XML_TEXT_NODE:
3446 case XML_CDATA_SECTION_NODE:
3447 case XML_ENTITY_REF_NODE:
3448 case XML_ENTITY_NODE:
3449 case XML_PI_NODE:
3450 case XML_COMMENT_NODE:
3451 case XML_DTD_NODE:
3452 case XML_ELEMENT_DECL:
3453 case XML_ATTRIBUTE_DECL:
3454 case XML_ENTITY_DECL:
3455 case XML_NOTATION_NODE:
3456 case XML_XINCLUDE_START:
3457 case XML_XINCLUDE_END:
3458 if (ctxt->context->node->parent == NULL)
3459 return((xmlNodePtr) ctxt->context->doc);
3460 return(ctxt->context->node->parent);
3461 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003462 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00003463
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003464 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003465 }
3466 case XML_DOCUMENT_NODE:
3467 case XML_DOCUMENT_TYPE_NODE:
3468 case XML_DOCUMENT_FRAG_NODE:
3469 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003470#ifdef LIBXML_DOCB_ENABLED
3471 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003472#endif
3473 return(NULL);
3474 case XML_NAMESPACE_DECL:
3475 /*
3476 * TODO !!! may require extending struct _xmlNs with
3477 * parent field
3478 * C.f. Infoset case...
3479 */
3480 return(NULL);
3481 }
3482 return(NULL);
3483 }
3484 if (cur == ctxt->context->doc->children)
3485 return((xmlNodePtr) ctxt->context->doc);
3486 if (cur == (xmlNodePtr) ctxt->context->doc)
3487 return(NULL);
3488 switch (cur->type) {
3489 case XML_ELEMENT_NODE:
3490 case XML_TEXT_NODE:
3491 case XML_CDATA_SECTION_NODE:
3492 case XML_ENTITY_REF_NODE:
3493 case XML_ENTITY_NODE:
3494 case XML_PI_NODE:
3495 case XML_COMMENT_NODE:
3496 case XML_NOTATION_NODE:
3497 case XML_DTD_NODE:
3498 case XML_ELEMENT_DECL:
3499 case XML_ATTRIBUTE_DECL:
3500 case XML_ENTITY_DECL:
3501 case XML_XINCLUDE_START:
3502 case XML_XINCLUDE_END:
3503 return(cur->parent);
3504 case XML_ATTRIBUTE_NODE: {
3505 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3506
3507 return(att->parent);
3508 }
3509 case XML_DOCUMENT_NODE:
3510 case XML_DOCUMENT_TYPE_NODE:
3511 case XML_DOCUMENT_FRAG_NODE:
3512 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003513#ifdef LIBXML_DOCB_ENABLED
3514 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003515#endif
3516 return(NULL);
3517 case XML_NAMESPACE_DECL:
3518 /*
3519 * TODO !!! may require extending struct _xmlNs with
3520 * parent field
3521 * C.f. Infoset case...
3522 */
3523 return(NULL);
3524 }
3525 return(NULL);
3526}
3527
3528/**
3529 * xmlXPathNextAncestorOrSelf:
3530 * @ctxt: the XPath Parser context
3531 * @cur: the current node in the traversal
3532 *
3533 * Traversal function for the "ancestor-or-self" direction
3534 * he ancestor-or-self axis contains the context node and ancestors of
3535 * the context node in reverse document order; thus the context node is
3536 * the first node on the axis, and the context node's parent the second;
3537 * parent here is defined the same as with the parent axis.
3538 *
3539 * Returns the next element following that axis
3540 */
3541xmlNodePtr
3542xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3543 if (cur == NULL)
3544 return(ctxt->context->node);
3545 return(xmlXPathNextAncestor(ctxt, cur));
3546}
3547
3548/**
3549 * xmlXPathNextFollowingSibling:
3550 * @ctxt: the XPath Parser context
3551 * @cur: the current node in the traversal
3552 *
3553 * Traversal function for the "following-sibling" direction
3554 * The following-sibling axis contains the following siblings of the context
3555 * node in document order.
3556 *
3557 * Returns the next element following that axis
3558 */
3559xmlNodePtr
3560xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3561 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3562 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3563 return(NULL);
3564 if (cur == (xmlNodePtr) ctxt->context->doc)
3565 return(NULL);
3566 if (cur == NULL)
3567 return(ctxt->context->node->next);
3568 return(cur->next);
3569}
3570
3571/**
3572 * xmlXPathNextPrecedingSibling:
3573 * @ctxt: the XPath Parser context
3574 * @cur: the current node in the traversal
3575 *
3576 * Traversal function for the "preceding-sibling" direction
3577 * The preceding-sibling axis contains the preceding siblings of the context
3578 * node in reverse document order; the first preceding sibling is first on the
3579 * axis; the sibling preceding that node is the second on the axis and so on.
3580 *
3581 * Returns the next element following that axis
3582 */
3583xmlNodePtr
3584xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3585 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3586 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3587 return(NULL);
3588 if (cur == (xmlNodePtr) ctxt->context->doc)
3589 return(NULL);
3590 if (cur == NULL)
3591 return(ctxt->context->node->prev);
3592 return(cur->prev);
3593}
3594
3595/**
3596 * xmlXPathNextFollowing:
3597 * @ctxt: the XPath Parser context
3598 * @cur: the current node in the traversal
3599 *
3600 * Traversal function for the "following" direction
3601 * The following axis contains all nodes in the same document as the context
3602 * node that are after the context node in document order, excluding any
3603 * descendants and excluding attribute nodes and namespace nodes; the nodes
3604 * are ordered in document order
3605 *
3606 * Returns the next element following that axis
3607 */
3608xmlNodePtr
3609xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3610 if (cur != NULL && cur->children != NULL)
3611 return cur->children ;
3612 if (cur == NULL) cur = ctxt->context->node;
3613 if (cur == NULL) return(NULL) ; /* ERROR */
3614 if (cur->next != NULL) return(cur->next) ;
3615 do {
3616 cur = cur->parent;
3617 if (cur == NULL) return(NULL);
3618 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
3619 if (cur->next != NULL) return(cur->next);
3620 } while (cur != NULL);
3621 return(cur);
3622}
3623
3624/*
3625 * xmlXPathIsAncestor:
3626 * @ancestor: the ancestor node
3627 * @node: the current node
3628 *
3629 * Check that @ancestor is a @node's ancestor
3630 *
3631 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
3632 */
3633static int
3634xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
3635 if ((ancestor == NULL) || (node == NULL)) return(0);
3636 /* nodes need to be in the same document */
3637 if (ancestor->doc != node->doc) return(0);
3638 /* avoid searching if ancestor or node is the root node */
3639 if (ancestor == (xmlNodePtr) node->doc) return(1);
3640 if (node == (xmlNodePtr) ancestor->doc) return(0);
3641 while (node->parent != NULL) {
3642 if (node->parent == ancestor)
3643 return(1);
3644 node = node->parent;
3645 }
3646 return(0);
3647}
3648
3649/**
3650 * xmlXPathNextPreceding:
3651 * @ctxt: the XPath Parser context
3652 * @cur: the current node in the traversal
3653 *
3654 * Traversal function for the "preceding" direction
3655 * the preceding axis contains all nodes in the same document as the context
3656 * node that are before the context node in document order, excluding any
3657 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
3658 * ordered in reverse document order
3659 *
3660 * Returns the next element following that axis
3661 */
3662xmlNodePtr
3663xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3664 if (cur == NULL)
3665 cur = ctxt->context->node ;
3666 do {
3667 if (cur->prev != NULL) {
3668 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
3669 ;
3670 return(cur) ;
3671 }
3672
3673 cur = cur->parent;
3674 if (cur == NULL) return(NULL);
3675 if (cur == ctxt->context->doc->children) return(NULL);
3676 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
3677 return(cur);
3678}
3679
3680/**
3681 * xmlXPathNextNamespace:
3682 * @ctxt: the XPath Parser context
3683 * @cur: the current attribute in the traversal
3684 *
3685 * Traversal function for the "namespace" direction
3686 * the namespace axis contains the namespace nodes of the context node;
3687 * the order of nodes on this axis is implementation-defined; the axis will
3688 * be empty unless the context node is an element
3689 *
3690 * Returns the next element following that axis
3691 */
3692xmlNodePtr
3693xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3694 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3695 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
3696 if (ctxt->context->namespaces != NULL)
3697 xmlFree(ctxt->context->namespaces);
3698 ctxt->context->namespaces =
3699 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
3700 if (ctxt->context->namespaces == NULL) return(NULL);
3701 ctxt->context->nsNr = 0;
3702 }
3703 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
3704}
3705
3706/**
3707 * xmlXPathNextAttribute:
3708 * @ctxt: the XPath Parser context
3709 * @cur: the current attribute in the traversal
3710 *
3711 * Traversal function for the "attribute" direction
3712 * TODO: support DTD inherited default attributes
3713 *
3714 * Returns the next element following that axis
3715 */
3716xmlNodePtr
3717xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00003718 if (ctxt->context->node == NULL)
3719 return(NULL);
3720 if (ctxt->context->node->type != XML_ELEMENT_NODE)
3721 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003722 if (cur == NULL) {
3723 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3724 return(NULL);
3725 return((xmlNodePtr)ctxt->context->node->properties);
3726 }
3727 return((xmlNodePtr)cur->next);
3728}
3729
3730/************************************************************************
3731 * *
3732 * NodeTest Functions *
3733 * *
3734 ************************************************************************/
3735
Owen Taylor3473f882001-02-23 17:55:21 +00003736#define IS_FUNCTION 200
3737
Owen Taylor3473f882001-02-23 17:55:21 +00003738
3739/************************************************************************
3740 * *
3741 * Implicit tree core function library *
3742 * *
3743 ************************************************************************/
3744
3745/**
3746 * xmlXPathRoot:
3747 * @ctxt: the XPath Parser context
3748 *
3749 * Initialize the context to the root of the document
3750 */
3751void
3752xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
3753 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
3754 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3755}
3756
3757/************************************************************************
3758 * *
3759 * The explicit core function library *
3760 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
3761 * *
3762 ************************************************************************/
3763
3764
3765/**
3766 * xmlXPathLastFunction:
3767 * @ctxt: the XPath Parser context
3768 * @nargs: the number of arguments
3769 *
3770 * Implement the last() XPath function
3771 * number last()
3772 * The last function returns the number of nodes in the context node list.
3773 */
3774void
3775xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3776 CHECK_ARITY(0);
3777 if (ctxt->context->contextSize >= 0) {
3778 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
3779#ifdef DEBUG_EXPR
3780 xmlGenericError(xmlGenericErrorContext,
3781 "last() : %d\n", ctxt->context->contextSize);
3782#endif
3783 } else {
3784 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
3785 }
3786}
3787
3788/**
3789 * xmlXPathPositionFunction:
3790 * @ctxt: the XPath Parser context
3791 * @nargs: the number of arguments
3792 *
3793 * Implement the position() XPath function
3794 * number position()
3795 * The position function returns the position of the context node in the
3796 * context node list. The first position is 1, and so the last positionr
3797 * will be equal to last().
3798 */
3799void
3800xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3801 CHECK_ARITY(0);
3802 if (ctxt->context->proximityPosition >= 0) {
3803 valuePush(ctxt,
3804 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
3805#ifdef DEBUG_EXPR
3806 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
3807 ctxt->context->proximityPosition);
3808#endif
3809 } else {
3810 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
3811 }
3812}
3813
3814/**
3815 * xmlXPathCountFunction:
3816 * @ctxt: the XPath Parser context
3817 * @nargs: the number of arguments
3818 *
3819 * Implement the count() XPath function
3820 * number count(node-set)
3821 */
3822void
3823xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3824 xmlXPathObjectPtr cur;
3825
3826 CHECK_ARITY(1);
3827 if ((ctxt->value == NULL) ||
3828 ((ctxt->value->type != XPATH_NODESET) &&
3829 (ctxt->value->type != XPATH_XSLT_TREE)))
3830 XP_ERROR(XPATH_INVALID_TYPE);
3831 cur = valuePop(ctxt);
3832
Daniel Veillard911f49a2001-04-07 15:39:35 +00003833 if ((cur == NULL) || (cur->nodesetval == NULL))
3834 valuePush(ctxt, xmlXPathNewFloat((double) 0));
3835 else
3836 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00003837 xmlXPathFreeObject(cur);
3838}
3839
3840/**
3841 * xmlXPathIdFunction:
3842 * @ctxt: the XPath Parser context
3843 * @nargs: the number of arguments
3844 *
3845 * Implement the id() XPath function
3846 * node-set id(object)
3847 * The id function selects elements by their unique ID
3848 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
3849 * then the result is the union of the result of applying id to the
3850 * string value of each of the nodes in the argument node-set. When the
3851 * argument to id is of any other type, the argument is converted to a
3852 * string as if by a call to the string function; the string is split
3853 * into a whitespace-separated list of tokens (whitespace is any sequence
3854 * of characters matching the production S); the result is a node-set
3855 * containing the elements in the same document as the context node that
3856 * have a unique ID equal to any of the tokens in the list.
3857 */
3858void
3859xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3860 const xmlChar *tokens;
3861 const xmlChar *cur;
3862 xmlChar *ID;
3863 xmlAttrPtr attr;
3864 xmlNodePtr elem = NULL;
3865 xmlXPathObjectPtr ret, obj;
3866
3867 CHECK_ARITY(1);
3868 obj = valuePop(ctxt);
3869 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3870 if (obj->type == XPATH_NODESET) {
3871 xmlXPathObjectPtr newobj;
3872 int i;
3873
3874 ret = xmlXPathNewNodeSet(NULL);
3875
Daniel Veillard911f49a2001-04-07 15:39:35 +00003876 if (obj->nodesetval != NULL) {
3877 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
3878 valuePush(ctxt,
3879 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
3880 xmlXPathStringFunction(ctxt, 1);
3881 xmlXPathIdFunction(ctxt, 1);
3882 newobj = valuePop(ctxt);
3883 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
3884 newobj->nodesetval);
3885 xmlXPathFreeObject(newobj);
3886 }
Owen Taylor3473f882001-02-23 17:55:21 +00003887 }
3888
3889 xmlXPathFreeObject(obj);
3890 valuePush(ctxt, ret);
3891 return;
3892 }
3893 if (obj->type != XPATH_STRING) {
3894 valuePush(ctxt, obj);
3895 xmlXPathStringFunction(ctxt, 1);
3896 obj = valuePop(ctxt);
3897 if (obj->type != XPATH_STRING) {
3898 xmlXPathFreeObject(obj);
3899 return;
3900 }
3901 }
3902 tokens = obj->stringval;
3903
3904 ret = xmlXPathNewNodeSet(NULL);
3905 valuePush(ctxt, ret);
3906 if (tokens == NULL) {
3907 xmlXPathFreeObject(obj);
3908 return;
3909 }
3910
3911 cur = tokens;
3912
3913 while (IS_BLANK(*cur)) cur++;
3914 while (*cur != 0) {
3915 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
3916 (*cur == '.') || (*cur == '-') ||
3917 (*cur == '_') || (*cur == ':') ||
3918 (IS_COMBINING(*cur)) ||
3919 (IS_EXTENDER(*cur)))
3920 cur++;
3921
3922 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
3923
3924 ID = xmlStrndup(tokens, cur - tokens);
3925 attr = xmlGetID(ctxt->context->doc, ID);
3926 if (attr != NULL) {
3927 elem = attr->parent;
3928 xmlXPathNodeSetAdd(ret->nodesetval, elem);
3929 }
3930 if (ID != NULL)
3931 xmlFree(ID);
3932
3933 while (IS_BLANK(*cur)) cur++;
3934 tokens = cur;
3935 }
3936 xmlXPathFreeObject(obj);
3937 return;
3938}
3939
3940/**
3941 * xmlXPathLocalNameFunction:
3942 * @ctxt: the XPath Parser context
3943 * @nargs: the number of arguments
3944 *
3945 * Implement the local-name() XPath function
3946 * string local-name(node-set?)
3947 * The local-name function returns a string containing the local part
3948 * of the name of the node in the argument node-set that is first in
3949 * document order. If the node-set is empty or the first node has no
3950 * name, an empty string is returned. If the argument is omitted it
3951 * defaults to the context node.
3952 */
3953void
3954xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3955 xmlXPathObjectPtr cur;
3956
3957 if (nargs == 0) {
3958 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3959 nargs = 1;
3960 }
3961
3962 CHECK_ARITY(1);
3963 if ((ctxt->value == NULL) ||
3964 ((ctxt->value->type != XPATH_NODESET) &&
3965 (ctxt->value->type != XPATH_XSLT_TREE)))
3966 XP_ERROR(XPATH_INVALID_TYPE);
3967 cur = valuePop(ctxt);
3968
Daniel Veillard911f49a2001-04-07 15:39:35 +00003969 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003970 valuePush(ctxt, xmlXPathNewCString(""));
3971 } else {
3972 int i = 0; /* Should be first in document order !!!!! */
3973 switch (cur->nodesetval->nodeTab[i]->type) {
3974 case XML_ELEMENT_NODE:
3975 case XML_ATTRIBUTE_NODE:
3976 case XML_PI_NODE:
3977 valuePush(ctxt,
3978 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
3979 break;
3980 case XML_NAMESPACE_DECL:
3981 valuePush(ctxt, xmlXPathNewString(
3982 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
3983 break;
3984 default:
3985 valuePush(ctxt, xmlXPathNewCString(""));
3986 }
3987 }
3988 xmlXPathFreeObject(cur);
3989}
3990
3991/**
3992 * xmlXPathNamespaceURIFunction:
3993 * @ctxt: the XPath Parser context
3994 * @nargs: the number of arguments
3995 *
3996 * Implement the namespace-uri() XPath function
3997 * string namespace-uri(node-set?)
3998 * The namespace-uri function returns a string containing the
3999 * namespace URI of the expanded name of the node in the argument
4000 * node-set that is first in document order. If the node-set is empty,
4001 * the first node has no name, or the expanded name has no namespace
4002 * URI, an empty string is returned. If the argument is omitted it
4003 * defaults to the context node.
4004 */
4005void
4006xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4007 xmlXPathObjectPtr cur;
4008
4009 if (nargs == 0) {
4010 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4011 nargs = 1;
4012 }
4013 CHECK_ARITY(1);
4014 if ((ctxt->value == NULL) ||
4015 ((ctxt->value->type != XPATH_NODESET) &&
4016 (ctxt->value->type != XPATH_XSLT_TREE)))
4017 XP_ERROR(XPATH_INVALID_TYPE);
4018 cur = valuePop(ctxt);
4019
Daniel Veillard911f49a2001-04-07 15:39:35 +00004020 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004021 valuePush(ctxt, xmlXPathNewCString(""));
4022 } else {
4023 int i = 0; /* Should be first in document order !!!!! */
4024 switch (cur->nodesetval->nodeTab[i]->type) {
4025 case XML_ELEMENT_NODE:
4026 case XML_ATTRIBUTE_NODE:
4027 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4028 valuePush(ctxt, xmlXPathNewCString(""));
4029 else
4030 valuePush(ctxt, xmlXPathNewString(
4031 cur->nodesetval->nodeTab[i]->ns->href));
4032 break;
4033 default:
4034 valuePush(ctxt, xmlXPathNewCString(""));
4035 }
4036 }
4037 xmlXPathFreeObject(cur);
4038}
4039
4040/**
4041 * xmlXPathNameFunction:
4042 * @ctxt: the XPath Parser context
4043 * @nargs: the number of arguments
4044 *
4045 * Implement the name() XPath function
4046 * string name(node-set?)
4047 * The name function returns a string containing a QName representing
4048 * the name of the node in the argument node-set that is first in documenti
4049 * order. The QName must represent the name with respect to the namespace
4050 * declarations in effect on the node whose name is being represented.
4051 * Typically, this will be the form in which the name occurred in the XML
4052 * source. This need not be the case if there are namespace declarations
4053 * in effect on the node that associate multiple prefixes with the same
4054 * namespace. However, an implementation may include information about
4055 * the original prefix in its representation of nodes; in this case, an
4056 * implementation can ensure that the returned string is always the same
4057 * as the QName used in the XML source. If the argument it omitted it
4058 * defaults to the context node.
4059 * Libxml keep the original prefix so the "real qualified name" used is
4060 * returned.
4061 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004062static void
Owen Taylor3473f882001-02-23 17:55:21 +00004063xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4064 xmlXPathObjectPtr cur;
4065
4066 if (nargs == 0) {
4067 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4068 nargs = 1;
4069 }
4070
4071 CHECK_ARITY(1);
4072 if ((ctxt->value == NULL) ||
4073 ((ctxt->value->type != XPATH_NODESET) &&
4074 (ctxt->value->type != XPATH_XSLT_TREE)))
4075 XP_ERROR(XPATH_INVALID_TYPE);
4076 cur = valuePop(ctxt);
4077
Daniel Veillard911f49a2001-04-07 15:39:35 +00004078 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004079 valuePush(ctxt, xmlXPathNewCString(""));
4080 } else {
4081 int i = 0; /* Should be first in document order !!!!! */
4082
4083 switch (cur->nodesetval->nodeTab[i]->type) {
4084 case XML_ELEMENT_NODE:
4085 case XML_ATTRIBUTE_NODE:
4086 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4087 valuePush(ctxt, xmlXPathNewString(
4088 cur->nodesetval->nodeTab[i]->name));
4089
4090 else {
4091 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004092 snprintf(name, sizeof(name), "%s:%s",
4093 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4094 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004095 name[sizeof(name) - 1] = 0;
4096 valuePush(ctxt, xmlXPathNewCString(name));
4097 }
4098 break;
4099 default:
4100 valuePush(ctxt,
4101 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4102 xmlXPathLocalNameFunction(ctxt, 1);
4103 }
4104 }
4105 xmlXPathFreeObject(cur);
4106}
4107
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004108
4109/**
4110 * xmlXPathConvertString:
4111 * @val: an XPath object
4112 *
4113 * Converts an existing object to its string() equivalent
4114 *
4115 * Returns the new object, the old one is freed (or the operation
4116 * is done directly on @val)
4117 */
4118xmlXPathObjectPtr
4119xmlXPathConvertString(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004120 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004121
4122 if (val == NULL)
4123 return(xmlXPathNewCString(""));
4124 switch (val->type) {
4125 case XPATH_UNDEFINED:
4126#ifdef DEBUG_EXPR
4127 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
4128#endif
4129 ret = xmlXPathNewCString("");
4130 break;
4131 case XPATH_XSLT_TREE:
4132 case XPATH_NODESET:
Daniel Veillard911f49a2001-04-07 15:39:35 +00004133 if ((val->nodesetval == NULL) || (val->nodesetval->nodeNr == 0)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004134 ret = xmlXPathNewCString("");
4135 } else {
4136 xmlChar *res;
4137
4138 xmlXPathNodeSetSort(val->nodesetval);
4139 res = xmlNodeGetContent(val->nodesetval->nodeTab[0]);
4140 /* TODO: avoid allocating res to free it */
4141 ret = xmlXPathNewString(res);
4142 if (res != NULL)
4143 xmlFree(res);
4144 }
4145 break;
4146 case XPATH_STRING:
4147 return(val);
4148 case XPATH_BOOLEAN:
4149 if (val->boolval) ret = xmlXPathNewCString("true");
4150 else ret = xmlXPathNewCString("false");
4151 break;
4152 case XPATH_NUMBER: {
4153 char buf[100];
4154
4155 xmlXPathFormatNumber(val->floatval, buf, sizeof(buf));
4156 ret = xmlXPathNewCString(buf);
4157 break;
4158 }
4159 case XPATH_USERS:
4160 case XPATH_POINT:
4161 case XPATH_RANGE:
4162 case XPATH_LOCATIONSET:
4163 TODO
4164 ret = xmlXPathNewCString("");
4165 break;
4166 }
4167 xmlXPathFreeObject(val);
4168 return(ret);
4169}
4170
Owen Taylor3473f882001-02-23 17:55:21 +00004171/**
4172 * xmlXPathStringFunction:
4173 * @ctxt: the XPath Parser context
4174 * @nargs: the number of arguments
4175 *
4176 * Implement the string() XPath function
4177 * string string(object?)
4178 * he string function converts an object to a string as follows:
4179 * - A node-set is converted to a string by returning the value of
4180 * the node in the node-set that is first in document order.
4181 * If the node-set is empty, an empty string is returned.
4182 * - A number is converted to a string as follows
4183 * + NaN is converted to the string NaN
4184 * + positive zero is converted to the string 0
4185 * + negative zero is converted to the string 0
4186 * + positive infinity is converted to the string Infinity
4187 * + negative infinity is converted to the string -Infinity
4188 * + if the number is an integer, the number is represented in
4189 * decimal form as a Number with no decimal point and no leading
4190 * zeros, preceded by a minus sign (-) if the number is negative
4191 * + otherwise, the number is represented in decimal form as a
4192 * Number including a decimal point with at least one digit
4193 * before the decimal point and at least one digit after the
4194 * decimal point, preceded by a minus sign (-) if the number
4195 * is negative; there must be no leading zeros before the decimal
4196 * point apart possibly from the one required digit immediatelyi
4197 * before the decimal point; beyond the one required digit
4198 * after the decimal point there must be as many, but only as
4199 * many, more digits as are needed to uniquely distinguish the
4200 * number from all other IEEE 754 numeric values.
4201 * - The boolean false value is converted to the string false.
4202 * The boolean true value is converted to the string true.
4203 *
4204 * If the argument is omitted, it defaults to a node-set with the
4205 * context node as its only member.
4206 */
4207void
4208xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4209 xmlXPathObjectPtr cur;
4210
4211 if (nargs == 0) {
4212 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4213 nargs = 1;
4214 }
4215
4216 CHECK_ARITY(1);
4217 cur = valuePop(ctxt);
4218 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004219 cur = xmlXPathConvertString(cur);
4220 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004221}
4222
4223/**
4224 * xmlXPathStringLengthFunction:
4225 * @ctxt: the XPath Parser context
4226 * @nargs: the number of arguments
4227 *
4228 * Implement the string-length() XPath function
4229 * number string-length(string?)
4230 * The string-length returns the number of characters in the string
4231 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4232 * the context node converted to a string, in other words the value
4233 * of the context node.
4234 */
4235void
4236xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4237 xmlXPathObjectPtr cur;
4238
4239 if (nargs == 0) {
4240 if (ctxt->context->node == NULL) {
4241 valuePush(ctxt, xmlXPathNewFloat(0));
4242 } else {
4243 xmlChar *content;
4244
4245 content = xmlNodeGetContent(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004246 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004247 xmlFree(content);
4248 }
4249 return;
4250 }
4251 CHECK_ARITY(1);
4252 CAST_TO_STRING;
4253 CHECK_TYPE(XPATH_STRING);
4254 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004255 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004256 xmlXPathFreeObject(cur);
4257}
4258
4259/**
4260 * xmlXPathConcatFunction:
4261 * @ctxt: the XPath Parser context
4262 * @nargs: the number of arguments
4263 *
4264 * Implement the concat() XPath function
4265 * string concat(string, string, string*)
4266 * The concat function returns the concatenation of its arguments.
4267 */
4268void
4269xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4270 xmlXPathObjectPtr cur, newobj;
4271 xmlChar *tmp;
4272
4273 if (nargs < 2) {
4274 CHECK_ARITY(2);
4275 }
4276
4277 CAST_TO_STRING;
4278 cur = valuePop(ctxt);
4279 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4280 xmlXPathFreeObject(cur);
4281 return;
4282 }
4283 nargs--;
4284
4285 while (nargs > 0) {
4286 CAST_TO_STRING;
4287 newobj = valuePop(ctxt);
4288 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4289 xmlXPathFreeObject(newobj);
4290 xmlXPathFreeObject(cur);
4291 XP_ERROR(XPATH_INVALID_TYPE);
4292 }
4293 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4294 newobj->stringval = cur->stringval;
4295 cur->stringval = tmp;
4296
4297 xmlXPathFreeObject(newobj);
4298 nargs--;
4299 }
4300 valuePush(ctxt, cur);
4301}
4302
4303/**
4304 * xmlXPathContainsFunction:
4305 * @ctxt: the XPath Parser context
4306 * @nargs: the number of arguments
4307 *
4308 * Implement the contains() XPath function
4309 * boolean contains(string, string)
4310 * The contains function returns true if the first argument string
4311 * contains the second argument string, and otherwise returns false.
4312 */
4313void
4314xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4315 xmlXPathObjectPtr hay, needle;
4316
4317 CHECK_ARITY(2);
4318 CAST_TO_STRING;
4319 CHECK_TYPE(XPATH_STRING);
4320 needle = valuePop(ctxt);
4321 CAST_TO_STRING;
4322 hay = valuePop(ctxt);
4323 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4324 xmlXPathFreeObject(hay);
4325 xmlXPathFreeObject(needle);
4326 XP_ERROR(XPATH_INVALID_TYPE);
4327 }
4328 if (xmlStrstr(hay->stringval, needle->stringval))
4329 valuePush(ctxt, xmlXPathNewBoolean(1));
4330 else
4331 valuePush(ctxt, xmlXPathNewBoolean(0));
4332 xmlXPathFreeObject(hay);
4333 xmlXPathFreeObject(needle);
4334}
4335
4336/**
4337 * xmlXPathStartsWithFunction:
4338 * @ctxt: the XPath Parser context
4339 * @nargs: the number of arguments
4340 *
4341 * Implement the starts-with() XPath function
4342 * boolean starts-with(string, string)
4343 * The starts-with function returns true if the first argument string
4344 * starts with the second argument string, and otherwise returns false.
4345 */
4346void
4347xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4348 xmlXPathObjectPtr hay, needle;
4349 int n;
4350
4351 CHECK_ARITY(2);
4352 CAST_TO_STRING;
4353 CHECK_TYPE(XPATH_STRING);
4354 needle = valuePop(ctxt);
4355 CAST_TO_STRING;
4356 hay = valuePop(ctxt);
4357 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4358 xmlXPathFreeObject(hay);
4359 xmlXPathFreeObject(needle);
4360 XP_ERROR(XPATH_INVALID_TYPE);
4361 }
4362 n = xmlStrlen(needle->stringval);
4363 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4364 valuePush(ctxt, xmlXPathNewBoolean(0));
4365 else
4366 valuePush(ctxt, xmlXPathNewBoolean(1));
4367 xmlXPathFreeObject(hay);
4368 xmlXPathFreeObject(needle);
4369}
4370
4371/**
4372 * xmlXPathSubstringFunction:
4373 * @ctxt: the XPath Parser context
4374 * @nargs: the number of arguments
4375 *
4376 * Implement the substring() XPath function
4377 * string substring(string, number, number?)
4378 * The substring function returns the substring of the first argument
4379 * starting at the position specified in the second argument with
4380 * length specified in the third argument. For example,
4381 * substring("12345",2,3) returns "234". If the third argument is not
4382 * specified, it returns the substring starting at the position specified
4383 * in the second argument and continuing to the end of the string. For
4384 * example, substring("12345",2) returns "2345". More precisely, each
4385 * character in the string (see [3.6 Strings]) is considered to have a
4386 * numeric position: the position of the first character is 1, the position
4387 * of the second character is 2 and so on. The returned substring contains
4388 * those characters for which the position of the character is greater than
4389 * or equal to the second argument and, if the third argument is specified,
4390 * less than the sum of the second and third arguments; the comparisons
4391 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4392 * - substring("12345", 1.5, 2.6) returns "234"
4393 * - substring("12345", 0, 3) returns "12"
4394 * - substring("12345", 0 div 0, 3) returns ""
4395 * - substring("12345", 1, 0 div 0) returns ""
4396 * - substring("12345", -42, 1 div 0) returns "12345"
4397 * - substring("12345", -1 div 0, 1 div 0) returns ""
4398 */
4399void
4400xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4401 xmlXPathObjectPtr str, start, len;
4402 double le, in;
4403 int i, l;
4404 xmlChar *ret;
4405
4406 /*
Daniel Veillarde043ee12001-04-16 14:08:07 +00004407 * TODO: need to be converted to UTF8 strings
Owen Taylor3473f882001-02-23 17:55:21 +00004408 */
4409 if (nargs < 2) {
4410 CHECK_ARITY(2);
4411 }
4412 if (nargs > 3) {
4413 CHECK_ARITY(3);
4414 }
4415 if (nargs == 3) {
4416 CAST_TO_NUMBER;
4417 CHECK_TYPE(XPATH_NUMBER);
4418 len = valuePop(ctxt);
4419 le = len->floatval;
4420 xmlXPathFreeObject(len);
4421 } else {
4422 le = 2000000000;
4423 }
4424 CAST_TO_NUMBER;
4425 CHECK_TYPE(XPATH_NUMBER);
4426 start = valuePop(ctxt);
4427 in = start->floatval;
4428 xmlXPathFreeObject(start);
4429 CAST_TO_STRING;
4430 CHECK_TYPE(XPATH_STRING);
4431 str = valuePop(ctxt);
4432 le += in;
4433
4434 /* integer index of the first char */
4435 i = (int) in;
4436 if (((double)i) != in) i++;
4437
4438 /* integer index of the last char */
4439 l = (int) le;
4440 if (((double)l) != le) l++;
4441
4442 /* back to a zero based len */
4443 i--;
4444 l--;
4445
4446 /* check against the string len */
4447 if (l > 1024) {
4448 l = xmlStrlen(str->stringval);
4449 }
4450 if (i < 0) {
4451 i = 0;
4452 }
4453
4454 /* number of chars to copy */
4455 l -= i;
4456
4457 ret = xmlStrsub(str->stringval, i, l);
4458 if (ret == NULL)
4459 valuePush(ctxt, xmlXPathNewCString(""));
4460 else {
4461 valuePush(ctxt, xmlXPathNewString(ret));
4462 xmlFree(ret);
4463 }
4464 xmlXPathFreeObject(str);
4465}
4466
4467/**
4468 * xmlXPathSubstringBeforeFunction:
4469 * @ctxt: the XPath Parser context
4470 * @nargs: the number of arguments
4471 *
4472 * Implement the substring-before() XPath function
4473 * string substring-before(string, string)
4474 * The substring-before function returns the substring of the first
4475 * argument string that precedes the first occurrence of the second
4476 * argument string in the first argument string, or the empty string
4477 * if the first argument string does not contain the second argument
4478 * string. For example, substring-before("1999/04/01","/") returns 1999.
4479 */
4480void
4481xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4482 xmlXPathObjectPtr str;
4483 xmlXPathObjectPtr find;
4484 xmlBufferPtr target;
4485 const xmlChar *point;
4486 int offset;
4487
4488 CHECK_ARITY(2);
4489 CAST_TO_STRING;
4490 find = valuePop(ctxt);
4491 CAST_TO_STRING;
4492 str = valuePop(ctxt);
4493
4494 target = xmlBufferCreate();
4495 if (target) {
4496 point = xmlStrstr(str->stringval, find->stringval);
4497 if (point) {
4498 offset = (int)(point - str->stringval);
4499 xmlBufferAdd(target, str->stringval, offset);
4500 }
4501 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4502 xmlBufferFree(target);
4503 }
4504
4505 xmlXPathFreeObject(str);
4506 xmlXPathFreeObject(find);
4507}
4508
4509/**
4510 * xmlXPathSubstringAfterFunction:
4511 * @ctxt: the XPath Parser context
4512 * @nargs: the number of arguments
4513 *
4514 * Implement the substring-after() XPath function
4515 * string substring-after(string, string)
4516 * The substring-after function returns the substring of the first
4517 * argument string that follows the first occurrence of the second
4518 * argument string in the first argument string, or the empty stringi
4519 * if the first argument string does not contain the second argument
4520 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4521 * and substring-after("1999/04/01","19") returns 99/04/01.
4522 */
4523void
4524xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4525 xmlXPathObjectPtr str;
4526 xmlXPathObjectPtr find;
4527 xmlBufferPtr target;
4528 const xmlChar *point;
4529 int offset;
4530
4531 CHECK_ARITY(2);
4532 CAST_TO_STRING;
4533 find = valuePop(ctxt);
4534 CAST_TO_STRING;
4535 str = valuePop(ctxt);
4536
4537 target = xmlBufferCreate();
4538 if (target) {
4539 point = xmlStrstr(str->stringval, find->stringval);
4540 if (point) {
4541 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4542 xmlBufferAdd(target, &str->stringval[offset],
4543 xmlStrlen(str->stringval) - offset);
4544 }
4545 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4546 xmlBufferFree(target);
4547 }
4548
4549 xmlXPathFreeObject(str);
4550 xmlXPathFreeObject(find);
4551}
4552
4553/**
4554 * xmlXPathNormalizeFunction:
4555 * @ctxt: the XPath Parser context
4556 * @nargs: the number of arguments
4557 *
4558 * Implement the normalize-space() XPath function
4559 * string normalize-space(string?)
4560 * The normalize-space function returns the argument string with white
4561 * space normalized by stripping leading and trailing whitespace
4562 * and replacing sequences of whitespace characters by a single
4563 * space. Whitespace characters are the same allowed by the S production
4564 * in XML. If the argument is omitted, it defaults to the context
4565 * node converted to a string, in other words the value of the context node.
4566 */
4567void
4568xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4569 xmlXPathObjectPtr obj = NULL;
4570 xmlChar *source = NULL;
4571 xmlBufferPtr target;
4572 xmlChar blank;
4573
4574 if (nargs == 0) {
4575 /* Use current context node */
4576 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4577 xmlXPathStringFunction(ctxt, 1);
4578 nargs = 1;
4579 }
4580
4581 CHECK_ARITY(1);
4582 CAST_TO_STRING;
4583 CHECK_TYPE(XPATH_STRING);
4584 obj = valuePop(ctxt);
4585 source = obj->stringval;
4586
4587 target = xmlBufferCreate();
4588 if (target && source) {
4589
4590 /* Skip leading whitespaces */
4591 while (IS_BLANK(*source))
4592 source++;
4593
4594 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4595 blank = 0;
4596 while (*source) {
4597 if (IS_BLANK(*source)) {
4598 blank = *source;
4599 } else {
4600 if (blank) {
4601 xmlBufferAdd(target, &blank, 1);
4602 blank = 0;
4603 }
4604 xmlBufferAdd(target, source, 1);
4605 }
4606 source++;
4607 }
4608
4609 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4610 xmlBufferFree(target);
4611 }
4612 xmlXPathFreeObject(obj);
4613}
4614
4615/**
4616 * xmlXPathTranslateFunction:
4617 * @ctxt: the XPath Parser context
4618 * @nargs: the number of arguments
4619 *
4620 * Implement the translate() XPath function
4621 * string translate(string, string, string)
4622 * The translate function returns the first argument string with
4623 * occurrences of characters in the second argument string replaced
4624 * by the character at the corresponding position in the third argument
4625 * string. For example, translate("bar","abc","ABC") returns the string
4626 * BAr. If there is a character in the second argument string with no
4627 * character at a corresponding position in the third argument string
4628 * (because the second argument string is longer than the third argument
4629 * string), then occurrences of that character in the first argument
4630 * string are removed. For example, translate("--aaa--","abc-","ABC")
4631 * returns "AAA". If a character occurs more than once in second
4632 * argument string, then the first occurrence determines the replacement
4633 * character. If the third argument string is longer than the second
4634 * argument string, then excess characters are ignored.
4635 */
4636void
4637xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00004638 xmlXPathObjectPtr str;
4639 xmlXPathObjectPtr from;
4640 xmlXPathObjectPtr to;
4641 xmlBufferPtr target;
4642 int i, offset, max;
4643 xmlChar ch;
4644 const xmlChar *point;
Owen Taylor3473f882001-02-23 17:55:21 +00004645
Daniel Veillarde043ee12001-04-16 14:08:07 +00004646 /*
4647 * TODO: need to be converted to UTF8 strings
4648 */
4649 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00004650
Daniel Veillarde043ee12001-04-16 14:08:07 +00004651 CAST_TO_STRING;
4652 to = valuePop(ctxt);
4653 CAST_TO_STRING;
4654 from = valuePop(ctxt);
4655 CAST_TO_STRING;
4656 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004657
Daniel Veillarde043ee12001-04-16 14:08:07 +00004658 target = xmlBufferCreate();
4659 if (target) {
4660 max = xmlStrlen(to->stringval);
4661 for (i = 0; (ch = str->stringval[i]); i++) {
4662 point = xmlStrchr(from->stringval, ch);
4663 if (point) {
4664 offset = (int)(point - from->stringval);
4665 if (offset < max)
4666 xmlBufferAdd(target, &to->stringval[offset], 1);
4667 } else
4668 xmlBufferAdd(target, &ch, 1);
4669 }
Owen Taylor3473f882001-02-23 17:55:21 +00004670 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00004671 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4672 xmlBufferFree(target);
4673 xmlXPathFreeObject(str);
4674 xmlXPathFreeObject(from);
4675 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00004676}
4677
4678/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004679 * xmlXPathConvertBoolean:
4680 * @val: an XPath object
4681 *
4682 * Converts an existing object to its boolean() equivalent
4683 *
4684 * Returns the new object, the old one is freed (or the operation
4685 * is done directly on @val)
4686 */
4687xmlXPathObjectPtr
4688xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4689 int res = 0;
4690
4691 if (val == NULL)
4692 return(NULL);
4693 switch (val->type) {
4694 case XPATH_NODESET:
4695 case XPATH_XSLT_TREE:
4696 if ((val->nodesetval == NULL) ||
4697 (val->nodesetval->nodeNr == 0)) res = 0;
4698 else
4699 res = 1;
4700 break;
4701 case XPATH_STRING:
4702 if ((val->stringval == NULL) ||
4703 (val->stringval[0] == 0)) res = 0;
4704 else
4705 res = 1;
4706 break;
4707 case XPATH_BOOLEAN:
4708 return(val);
4709 case XPATH_NUMBER:
4710 if (val->floatval) res = 1;
4711 break;
4712 default:
4713 STRANGE
4714 }
4715 xmlXPathFreeObject(val);
4716 return(xmlXPathNewBoolean(res));
4717}
4718
4719/**
Owen Taylor3473f882001-02-23 17:55:21 +00004720 * xmlXPathBooleanFunction:
4721 * @ctxt: the XPath Parser context
4722 * @nargs: the number of arguments
4723 *
4724 * Implement the boolean() XPath function
4725 * boolean boolean(object)
4726 * he boolean function converts its argument to a boolean as follows:
4727 * - a number is true if and only if it is neither positive or
4728 * negative zero nor NaN
4729 * - a node-set is true if and only if it is non-empty
4730 * - a string is true if and only if its length is non-zero
4731 */
4732void
4733xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4734 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00004735
4736 CHECK_ARITY(1);
4737 cur = valuePop(ctxt);
4738 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004739 cur = xmlXPathConvertBoolean(cur);
4740 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004741}
4742
4743/**
4744 * xmlXPathNotFunction:
4745 * @ctxt: the XPath Parser context
4746 * @nargs: the number of arguments
4747 *
4748 * Implement the not() XPath function
4749 * boolean not(boolean)
4750 * The not function returns true if its argument is false,
4751 * and false otherwise.
4752 */
4753void
4754xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4755 CHECK_ARITY(1);
4756 CAST_TO_BOOLEAN;
4757 CHECK_TYPE(XPATH_BOOLEAN);
4758 ctxt->value->boolval = ! ctxt->value->boolval;
4759}
4760
4761/**
4762 * xmlXPathTrueFunction:
4763 * @ctxt: the XPath Parser context
4764 * @nargs: the number of arguments
4765 *
4766 * Implement the true() XPath function
4767 * boolean true()
4768 */
4769void
4770xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4771 CHECK_ARITY(0);
4772 valuePush(ctxt, xmlXPathNewBoolean(1));
4773}
4774
4775/**
4776 * xmlXPathFalseFunction:
4777 * @ctxt: the XPath Parser context
4778 * @nargs: the number of arguments
4779 *
4780 * Implement the false() XPath function
4781 * boolean false()
4782 */
4783void
4784xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4785 CHECK_ARITY(0);
4786 valuePush(ctxt, xmlXPathNewBoolean(0));
4787}
4788
4789/**
4790 * xmlXPathLangFunction:
4791 * @ctxt: the XPath Parser context
4792 * @nargs: the number of arguments
4793 *
4794 * Implement the lang() XPath function
4795 * boolean lang(string)
4796 * The lang function returns true or false depending on whether the
4797 * language of the context node as specified by xml:lang attributes
4798 * is the same as or is a sublanguage of the language specified by
4799 * the argument string. The language of the context node is determined
4800 * by the value of the xml:lang attribute on the context node, or, if
4801 * the context node has no xml:lang attribute, by the value of the
4802 * xml:lang attribute on the nearest ancestor of the context node that
4803 * has an xml:lang attribute. If there is no such attribute, then lang
4804 * returns false. If there is such an attribute, then lang returns
4805 * true if the attribute value is equal to the argument ignoring case,
4806 * or if there is some suffix starting with - such that the attribute
4807 * value is equal to the argument ignoring that suffix of the attribute
4808 * value and ignoring case.
4809 */
4810void
4811xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4812 xmlXPathObjectPtr val;
4813 const xmlChar *theLang;
4814 const xmlChar *lang;
4815 int ret = 0;
4816 int i;
4817
4818 CHECK_ARITY(1);
4819 CAST_TO_STRING;
4820 CHECK_TYPE(XPATH_STRING);
4821 val = valuePop(ctxt);
4822 lang = val->stringval;
4823 theLang = xmlNodeGetLang(ctxt->context->node);
4824 if ((theLang != NULL) && (lang != NULL)) {
4825 for (i = 0;lang[i] != 0;i++)
4826 if (toupper(lang[i]) != toupper(theLang[i]))
4827 goto not_equal;
4828 ret = 1;
4829 }
4830not_equal:
4831 xmlXPathFreeObject(val);
4832 valuePush(ctxt, xmlXPathNewBoolean(ret));
4833}
4834
4835/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004836 * xmlXPathConvertNumber:
4837 * @val: an XPath object
4838 *
4839 * Converts an existing object to its number() equivalent
4840 *
4841 * Returns the new object, the old one is freed (or the operation
4842 * is done directly on @val)
4843 */
4844xmlXPathObjectPtr
4845xmlXPathConvertNumber(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004846 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004847 double res;
4848
4849 if (val == NULL)
4850 return(xmlXPathNewFloat(0.0));
4851 switch (val->type) {
4852 case XPATH_UNDEFINED:
4853#ifdef DEBUG_EXPR
4854 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
4855#endif
4856 ret = xmlXPathNewFloat(0.0);
4857 break;
4858 case XPATH_XSLT_TREE:
4859 case XPATH_NODESET:
4860 val = xmlXPathConvertString(val);
4861 /* no break on purpose */
4862 case XPATH_STRING:
4863 res = xmlXPathStringEvalNumber(val->stringval);
4864 ret = xmlXPathNewFloat(res);
4865 break;
4866 case XPATH_BOOLEAN:
4867 if (val->boolval) ret = xmlXPathNewFloat(1.0);
4868 else ret = xmlXPathNewFloat(0.0);
4869 break;
4870 case XPATH_NUMBER:
4871 return(val);
4872 case XPATH_USERS:
4873 case XPATH_POINT:
4874 case XPATH_RANGE:
4875 case XPATH_LOCATIONSET:
4876 TODO
4877 ret = xmlXPathNewFloat(0.0);
4878 break;
4879 }
4880 xmlXPathFreeObject(val);
4881 return(ret);
4882}
4883
4884/**
Owen Taylor3473f882001-02-23 17:55:21 +00004885 * xmlXPathNumberFunction:
4886 * @ctxt: the XPath Parser context
4887 * @nargs: the number of arguments
4888 *
4889 * Implement the number() XPath function
4890 * number number(object?)
4891 */
4892void
4893xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4894 xmlXPathObjectPtr cur;
4895 double res;
4896
4897 if (nargs == 0) {
4898 if (ctxt->context->node == NULL) {
4899 valuePush(ctxt, xmlXPathNewFloat(0.0));
4900 } else {
4901 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
4902
4903 res = xmlXPathStringEvalNumber(content);
4904 valuePush(ctxt, xmlXPathNewFloat(res));
4905 xmlFree(content);
4906 }
4907 return;
4908 }
4909
4910 CHECK_ARITY(1);
4911 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004912 cur = xmlXPathConvertNumber(cur);
4913 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004914}
4915
4916/**
4917 * xmlXPathSumFunction:
4918 * @ctxt: the XPath Parser context
4919 * @nargs: the number of arguments
4920 *
4921 * Implement the sum() XPath function
4922 * number sum(node-set)
4923 * The sum function returns the sum of the values of the nodes in
4924 * the argument node-set.
4925 */
4926void
4927xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4928 xmlXPathObjectPtr cur;
4929 int i;
4930
4931 CHECK_ARITY(1);
4932 if ((ctxt->value == NULL) ||
4933 ((ctxt->value->type != XPATH_NODESET) &&
4934 (ctxt->value->type != XPATH_XSLT_TREE)))
4935 XP_ERROR(XPATH_INVALID_TYPE);
4936 cur = valuePop(ctxt);
4937
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004938 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004939 valuePush(ctxt, xmlXPathNewFloat(0.0));
4940 } else {
4941 valuePush(ctxt,
4942 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
4943 xmlXPathNumberFunction(ctxt, 1);
4944 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
4945 valuePush(ctxt,
4946 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4947 xmlXPathAddValues(ctxt);
4948 }
4949 }
4950 xmlXPathFreeObject(cur);
4951}
4952
4953/**
4954 * xmlXPathFloorFunction:
4955 * @ctxt: the XPath Parser context
4956 * @nargs: the number of arguments
4957 *
4958 * Implement the floor() XPath function
4959 * number floor(number)
4960 * The floor function returns the largest (closest to positive infinity)
4961 * number that is not greater than the argument and that is an integer.
4962 */
4963void
4964xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4965 CHECK_ARITY(1);
4966 CAST_TO_NUMBER;
4967 CHECK_TYPE(XPATH_NUMBER);
4968#if 0
4969 ctxt->value->floatval = floor(ctxt->value->floatval);
4970#else
4971 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
4972 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
4973#endif
4974}
4975
4976/**
4977 * xmlXPathCeilingFunction:
4978 * @ctxt: the XPath Parser context
4979 * @nargs: the number of arguments
4980 *
4981 * Implement the ceiling() XPath function
4982 * number ceiling(number)
4983 * The ceiling function returns the smallest (closest to negative infinity)
4984 * number that is not less than the argument and that is an integer.
4985 */
4986void
4987xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4988 double f;
4989
4990 CHECK_ARITY(1);
4991 CAST_TO_NUMBER;
4992 CHECK_TYPE(XPATH_NUMBER);
4993
4994#if 0
4995 ctxt->value->floatval = ceil(ctxt->value->floatval);
4996#else
4997 f = (double)((int) ctxt->value->floatval);
4998 if (f != ctxt->value->floatval)
4999 ctxt->value->floatval = f + 1;
5000#endif
5001}
5002
5003/**
5004 * xmlXPathRoundFunction:
5005 * @ctxt: the XPath Parser context
5006 * @nargs: the number of arguments
5007 *
5008 * Implement the round() XPath function
5009 * number round(number)
5010 * The round function returns the number that is closest to the
5011 * argument and that is an integer. If there are two such numbers,
5012 * then the one that is even is returned.
5013 */
5014void
5015xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5016 double f;
5017
5018 CHECK_ARITY(1);
5019 CAST_TO_NUMBER;
5020 CHECK_TYPE(XPATH_NUMBER);
5021
5022 if ((ctxt->value->floatval == xmlXPathNAN) ||
5023 (ctxt->value->floatval == xmlXPathPINF) ||
5024 (ctxt->value->floatval == xmlXPathNINF) ||
5025 (ctxt->value->floatval == 0.0))
5026 return;
5027
5028#if 0
5029 f = floor(ctxt->value->floatval);
5030#else
5031 f = (double)((int) ctxt->value->floatval);
5032#endif
5033 if (ctxt->value->floatval < f + 0.5)
5034 ctxt->value->floatval = f;
5035 else
5036 ctxt->value->floatval = f + 1;
5037}
5038
5039/************************************************************************
5040 * *
5041 * The Parser *
5042 * *
5043 ************************************************************************/
5044
5045/*
5046 * a couple of forward declarations since we use a recursive call based
5047 * implementation.
5048 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005049static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005050static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005051static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005052#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005053static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5054#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005055#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005056static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005057#endif
5058
5059/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005060 * xmlXPathCurrentChar:
5061 * @ctxt: the XPath parser context
5062 * @cur: pointer to the beginning of the char
5063 * @len: pointer to the length of the char read
5064 *
5065 * The current char value, if using UTF-8 this may actaully span multiple
5066 * bytes in the input buffer.
5067 *
5068 * Returns the current char value and its lenght
5069 */
5070
5071static int
5072xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5073 unsigned char c;
5074 unsigned int val;
5075 const xmlChar *cur;
5076
5077 if (ctxt == NULL)
5078 return(0);
5079 cur = ctxt->cur;
5080
5081 /*
5082 * We are supposed to handle UTF8, check it's valid
5083 * From rfc2044: encoding of the Unicode values on UTF-8:
5084 *
5085 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5086 * 0000 0000-0000 007F 0xxxxxxx
5087 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5088 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5089 *
5090 * Check for the 0x110000 limit too
5091 */
5092 c = *cur;
5093 if (c & 0x80) {
5094 if ((cur[1] & 0xc0) != 0x80)
5095 goto encoding_error;
5096 if ((c & 0xe0) == 0xe0) {
5097
5098 if ((cur[2] & 0xc0) != 0x80)
5099 goto encoding_error;
5100 if ((c & 0xf0) == 0xf0) {
5101 if (((c & 0xf8) != 0xf0) ||
5102 ((cur[3] & 0xc0) != 0x80))
5103 goto encoding_error;
5104 /* 4-byte code */
5105 *len = 4;
5106 val = (cur[0] & 0x7) << 18;
5107 val |= (cur[1] & 0x3f) << 12;
5108 val |= (cur[2] & 0x3f) << 6;
5109 val |= cur[3] & 0x3f;
5110 } else {
5111 /* 3-byte code */
5112 *len = 3;
5113 val = (cur[0] & 0xf) << 12;
5114 val |= (cur[1] & 0x3f) << 6;
5115 val |= cur[2] & 0x3f;
5116 }
5117 } else {
5118 /* 2-byte code */
5119 *len = 2;
5120 val = (cur[0] & 0x1f) << 6;
5121 val |= cur[1] & 0x3f;
5122 }
5123 if (!IS_CHAR(val)) {
5124 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5125 }
5126 return(val);
5127 } else {
5128 /* 1-byte code */
5129 *len = 1;
5130 return((int) *cur);
5131 }
5132encoding_error:
5133 /*
5134 * If we detect an UTF8 error that probably mean that the
5135 * input encoding didn't get properly advertized in the
5136 * declaration header. Report the error and switch the encoding
5137 * to ISO-Latin-1 (if you don't like this policy, just declare the
5138 * encoding !)
5139 */
5140 XP_ERROR0(XPATH_ENCODING_ERROR);
5141 *len = 1;
5142 return((int) *cur);
5143}
5144
5145/**
Owen Taylor3473f882001-02-23 17:55:21 +00005146 * xmlXPathParseNCName:
5147 * @ctxt: the XPath Parser context
5148 *
5149 * parse an XML namespace non qualified name.
5150 *
5151 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5152 *
5153 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5154 * CombiningChar | Extender
5155 *
5156 * Returns the namespace name or NULL
5157 */
5158
5159xmlChar *
5160xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
5161 const xmlChar *q;
5162 xmlChar *ret = NULL;
5163
5164 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
5165 q = NEXT;
5166
5167 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
5168 (CUR == '.') || (CUR == '-') ||
5169 (CUR == '_') ||
5170 (IS_COMBINING(CUR)) ||
5171 (IS_EXTENDER(CUR)))
5172 NEXT;
5173
5174 ret = xmlStrndup(q, CUR_PTR - q);
5175
5176 return(ret);
5177}
5178
5179/**
5180 * xmlXPathParseQName:
5181 * @ctxt: the XPath Parser context
5182 * @prefix: a xmlChar **
5183 *
5184 * parse an XML qualified name
5185 *
5186 * [NS 5] QName ::= (Prefix ':')? LocalPart
5187 *
5188 * [NS 6] Prefix ::= NCName
5189 *
5190 * [NS 7] LocalPart ::= NCName
5191 *
5192 * Returns the function returns the local part, and prefix is updated
5193 * to get the Prefix if any.
5194 */
5195
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005196static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005197xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5198 xmlChar *ret = NULL;
5199
5200 *prefix = NULL;
5201 ret = xmlXPathParseNCName(ctxt);
5202 if (CUR == ':') {
5203 *prefix = ret;
5204 NEXT;
5205 ret = xmlXPathParseNCName(ctxt);
5206 }
5207 return(ret);
5208}
5209
Daniel Veillard61d80a22001-04-27 17:13:01 +00005210static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005211/**
5212 * xmlXPathParseName:
5213 * @ctxt: the XPath Parser context
5214 *
5215 * parse an XML name
5216 *
5217 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5218 * CombiningChar | Extender
5219 *
5220 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5221 *
5222 * Returns the namespace name or NULL
5223 */
5224
5225xmlChar *
5226xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005227 const xmlChar *in;
5228 xmlChar *ret;
5229 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005230
Daniel Veillard61d80a22001-04-27 17:13:01 +00005231 /*
5232 * Accelerator for simple ASCII names
5233 */
5234 in = ctxt->cur;
5235 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5236 ((*in >= 0x41) && (*in <= 0x5A)) ||
5237 (*in == '_') || (*in == ':')) {
5238 in++;
5239 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5240 ((*in >= 0x41) && (*in <= 0x5A)) ||
5241 ((*in >= 0x30) && (*in <= 0x39)) ||
5242 (*in == '_') || (*in == ':'))
5243 in++;
5244 if ((*in == ' ') || (*in == '>') || (*in == '/')) {
5245 count = in - ctxt->cur;
5246 ret = xmlStrndup(ctxt->cur, count);
5247 ctxt->cur = in;
5248 return(ret);
5249 }
5250 }
5251 return(xmlXPathParseNameComplex(ctxt));
Owen Taylor3473f882001-02-23 17:55:21 +00005252}
5253
Daniel Veillard61d80a22001-04-27 17:13:01 +00005254static xmlChar *
5255xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt) {
5256 xmlChar buf[XML_MAX_NAMELEN + 5];
5257 int len = 0, l;
5258 int c;
5259
5260 /*
5261 * Handler for more complex cases
5262 */
5263 c = CUR_CHAR(l);
5264 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
5265 (!IS_LETTER(c) && (c != '_') &&
5266 (c != ':'))) {
5267 return(NULL);
5268 }
5269
5270 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5271 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5272 (c == '.') || (c == '-') ||
5273 (c == '_') || (c == ':') ||
5274 (IS_COMBINING(c)) ||
5275 (IS_EXTENDER(c)))) {
5276 COPY_BUF(l,buf,len,c);
5277 NEXTL(l);
5278 c = CUR_CHAR(l);
5279 if (len >= XML_MAX_NAMELEN) {
5280 /*
5281 * Okay someone managed to make a huge name, so he's ready to pay
5282 * for the processing speed.
5283 */
5284 xmlChar *buffer;
5285 int max = len * 2;
5286
5287 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5288 if (buffer == NULL) {
5289 XP_ERROR0(XPATH_MEMORY_ERROR);
5290 }
5291 memcpy(buffer, buf, len);
5292 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5293 (c == '.') || (c == '-') ||
5294 (c == '_') || (c == ':') ||
5295 (IS_COMBINING(c)) ||
5296 (IS_EXTENDER(c))) {
5297 if (len + 10 > max) {
5298 max *= 2;
5299 buffer = (xmlChar *) xmlRealloc(buffer,
5300 max * sizeof(xmlChar));
5301 XP_ERROR0(XPATH_MEMORY_ERROR);
5302 if (buffer == NULL) {
5303 XP_ERROR0(XPATH_MEMORY_ERROR);
5304 }
5305 }
5306 COPY_BUF(l,buffer,len,c);
5307 NEXTL(l);
5308 c = CUR_CHAR(l);
5309 }
5310 buffer[len] = 0;
5311 return(buffer);
5312 }
5313 }
5314 return(xmlStrndup(buf, len));
5315}
Owen Taylor3473f882001-02-23 17:55:21 +00005316/**
5317 * xmlXPathStringEvalNumber:
5318 * @str: A string to scan
5319 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005320 * [30a] Float ::= Number ('e' Digits?)?
5321 *
Owen Taylor3473f882001-02-23 17:55:21 +00005322 * [30] Number ::= Digits ('.' Digits?)?
5323 * | '.' Digits
5324 * [31] Digits ::= [0-9]+
5325 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005326 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005327 * In complement of the Number expression, this function also handles
5328 * negative values : '-' Number.
5329 *
5330 * Returns the double value.
5331 */
5332double
5333xmlXPathStringEvalNumber(const xmlChar *str) {
5334 const xmlChar *cur = str;
5335 double ret = 0.0;
5336 double mult = 1;
5337 int ok = 0;
5338 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005339 int exponent = 0;
5340 int is_exponent_negative = 0;
5341
Owen Taylor3473f882001-02-23 17:55:21 +00005342 while (IS_BLANK(*cur)) cur++;
5343 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5344 return(xmlXPathNAN);
5345 }
5346 if (*cur == '-') {
5347 isneg = 1;
5348 cur++;
5349 }
5350 while ((*cur >= '0') && (*cur <= '9')) {
5351 ret = ret * 10 + (*cur - '0');
5352 ok = 1;
5353 cur++;
5354 }
5355 if (*cur == '.') {
5356 cur++;
5357 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5358 return(xmlXPathNAN);
5359 }
5360 while ((*cur >= '0') && (*cur <= '9')) {
5361 mult /= 10;
5362 ret = ret + (*cur - '0') * mult;
5363 cur++;
5364 }
5365 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005366 if ((*cur == 'e') || (*cur == 'E')) {
5367 cur++;
5368 if (*cur == '-') {
5369 is_exponent_negative = 1;
5370 cur++;
5371 }
5372 while ((*cur >= '0') && (*cur <= '9')) {
5373 exponent = exponent * 10 + (*cur - '0');
5374 cur++;
5375 }
5376 }
Owen Taylor3473f882001-02-23 17:55:21 +00005377 while (IS_BLANK(*cur)) cur++;
5378 if (*cur != 0) return(xmlXPathNAN);
5379 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005380 if (is_exponent_negative) exponent = -exponent;
5381 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005382 return(ret);
5383}
5384
5385/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005386 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005387 * @ctxt: the XPath Parser context
5388 *
5389 * [30] Number ::= Digits ('.' Digits?)?
5390 * | '.' Digits
5391 * [31] Digits ::= [0-9]+
5392 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005393 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005394 *
5395 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005396static void
5397xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005398 double ret = 0.0;
5399 double mult = 1;
5400 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005401 int exponent = 0;
5402 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005403
5404 CHECK_ERROR;
5405 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5406 XP_ERROR(XPATH_NUMBER_ERROR);
5407 }
5408 while ((CUR >= '0') && (CUR <= '9')) {
5409 ret = ret * 10 + (CUR - '0');
5410 ok = 1;
5411 NEXT;
5412 }
5413 if (CUR == '.') {
5414 NEXT;
5415 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5416 XP_ERROR(XPATH_NUMBER_ERROR);
5417 }
5418 while ((CUR >= '0') && (CUR <= '9')) {
5419 mult /= 10;
5420 ret = ret + (CUR - '0') * mult;
5421 NEXT;
5422 }
5423 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005424 if ((CUR == 'e') || (CUR == 'E')) {
5425 NEXT;
5426 if (CUR == '-') {
5427 is_exponent_negative = 1;
5428 NEXT;
5429 }
5430 while ((CUR >= '0') && (CUR <= '9')) {
5431 exponent = exponent * 10 + (CUR - '0');
5432 NEXT;
5433 }
5434 }
5435 if (is_exponent_negative)
5436 exponent = -exponent;
5437 ret *= pow(10.0, (double)exponent);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005438 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5439 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005440}
5441
5442/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005443 * xmlXPathParseLiteral:
5444 * @ctxt: the XPath Parser context
5445 *
5446 * Parse a Literal
5447 *
5448 * [29] Literal ::= '"' [^"]* '"'
5449 * | "'" [^']* "'"
5450 *
5451 * Returns the value found or NULL in case of error
5452 */
5453static xmlChar *
5454xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5455 const xmlChar *q;
5456 xmlChar *ret = NULL;
5457
5458 if (CUR == '"') {
5459 NEXT;
5460 q = CUR_PTR;
5461 while ((IS_CHAR(CUR)) && (CUR != '"'))
5462 NEXT;
5463 if (!IS_CHAR(CUR)) {
5464 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5465 } else {
5466 ret = xmlStrndup(q, CUR_PTR - q);
5467 NEXT;
5468 }
5469 } else if (CUR == '\'') {
5470 NEXT;
5471 q = CUR_PTR;
5472 while ((IS_CHAR(CUR)) && (CUR != '\''))
5473 NEXT;
5474 if (!IS_CHAR(CUR)) {
5475 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5476 } else {
5477 ret = xmlStrndup(q, CUR_PTR - q);
5478 NEXT;
5479 }
5480 } else {
5481 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5482 }
5483 return(ret);
5484}
5485
5486/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005487 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005488 * @ctxt: the XPath Parser context
5489 *
5490 * Parse a Literal and push it on the stack.
5491 *
5492 * [29] Literal ::= '"' [^"]* '"'
5493 * | "'" [^']* "'"
5494 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005495 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005496 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005497static void
5498xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005499 const xmlChar *q;
5500 xmlChar *ret = NULL;
5501
5502 if (CUR == '"') {
5503 NEXT;
5504 q = CUR_PTR;
5505 while ((IS_CHAR(CUR)) && (CUR != '"'))
5506 NEXT;
5507 if (!IS_CHAR(CUR)) {
5508 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5509 } else {
5510 ret = xmlStrndup(q, CUR_PTR - q);
5511 NEXT;
5512 }
5513 } else if (CUR == '\'') {
5514 NEXT;
5515 q = CUR_PTR;
5516 while ((IS_CHAR(CUR)) && (CUR != '\''))
5517 NEXT;
5518 if (!IS_CHAR(CUR)) {
5519 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5520 } else {
5521 ret = xmlStrndup(q, CUR_PTR - q);
5522 NEXT;
5523 }
5524 } else {
5525 XP_ERROR(XPATH_START_LITERAL_ERROR);
5526 }
5527 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005528 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5529 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005530 xmlFree(ret);
5531}
5532
5533/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005534 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005535 * @ctxt: the XPath Parser context
5536 *
5537 * Parse a VariableReference, evaluate it and push it on the stack.
5538 *
5539 * The variable bindings consist of a mapping from variable names
5540 * to variable values. The value of a variable is an object, which
5541 * of any of the types that are possible for the value of an expression,
5542 * and may also be of additional types not specified here.
5543 *
5544 * Early evaluation is possible since:
5545 * The variable bindings [...] used to evaluate a subexpression are
5546 * always the same as those used to evaluate the containing expression.
5547 *
5548 * [36] VariableReference ::= '$' QName
5549 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005550static void
5551xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005552 xmlChar *name;
5553 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005554
5555 SKIP_BLANKS;
5556 if (CUR != '$') {
5557 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5558 }
5559 NEXT;
5560 name = xmlXPathParseQName(ctxt, &prefix);
5561 if (name == NULL) {
5562 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5563 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005564 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005565 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5566 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005567 SKIP_BLANKS;
5568}
5569
5570/**
5571 * xmlXPathIsNodeType:
5572 * @ctxt: the XPath Parser context
5573 * @name: a name string
5574 *
5575 * Is the name given a NodeType one.
5576 *
5577 * [38] NodeType ::= 'comment'
5578 * | 'text'
5579 * | 'processing-instruction'
5580 * | 'node'
5581 *
5582 * Returns 1 if true 0 otherwise
5583 */
5584int
5585xmlXPathIsNodeType(const xmlChar *name) {
5586 if (name == NULL)
5587 return(0);
5588
5589 if (xmlStrEqual(name, BAD_CAST "comment"))
5590 return(1);
5591 if (xmlStrEqual(name, BAD_CAST "text"))
5592 return(1);
5593 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5594 return(1);
5595 if (xmlStrEqual(name, BAD_CAST "node"))
5596 return(1);
5597 return(0);
5598}
5599
5600/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005601 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005602 * @ctxt: the XPath Parser context
5603 *
5604 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5605 * [17] Argument ::= Expr
5606 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005607 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00005608 * pushed on the stack
5609 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005610static void
5611xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005612 xmlChar *name;
5613 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005614 int nbargs = 0;
5615
5616 name = xmlXPathParseQName(ctxt, &prefix);
5617 if (name == NULL) {
5618 XP_ERROR(XPATH_EXPR_ERROR);
5619 }
5620 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005621#ifdef DEBUG_EXPR
5622 if (prefix == NULL)
5623 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5624 name);
5625 else
5626 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5627 prefix, name);
5628#endif
5629
Owen Taylor3473f882001-02-23 17:55:21 +00005630 if (CUR != '(') {
5631 XP_ERROR(XPATH_EXPR_ERROR);
5632 }
5633 NEXT;
5634 SKIP_BLANKS;
5635
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005636 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005637 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005638 int op1 = ctxt->comp->last;
5639 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005640 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005641 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005642 nbargs++;
5643 if (CUR == ')') break;
5644 if (CUR != ',') {
5645 XP_ERROR(XPATH_EXPR_ERROR);
5646 }
5647 NEXT;
5648 SKIP_BLANKS;
5649 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005650 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
5651 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005652 NEXT;
5653 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005654}
5655
5656/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005657 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005658 * @ctxt: the XPath Parser context
5659 *
5660 * [15] PrimaryExpr ::= VariableReference
5661 * | '(' Expr ')'
5662 * | Literal
5663 * | Number
5664 * | FunctionCall
5665 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005666 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005667 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005668static void
5669xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005670 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005671 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005672 else if (CUR == '(') {
5673 NEXT;
5674 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005675 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005676 if (CUR != ')') {
5677 XP_ERROR(XPATH_EXPR_ERROR);
5678 }
5679 NEXT;
5680 SKIP_BLANKS;
5681 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005682 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005683 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005684 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005685 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005686 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005687 }
5688 SKIP_BLANKS;
5689}
5690
5691/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005692 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005693 * @ctxt: the XPath Parser context
5694 *
5695 * [20] FilterExpr ::= PrimaryExpr
5696 * | FilterExpr Predicate
5697 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005698 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005699 * Square brackets are used to filter expressions in the same way that
5700 * they are used in location paths. It is an error if the expression to
5701 * be filtered does not evaluate to a node-set. The context node list
5702 * used for evaluating the expression in square brackets is the node-set
5703 * to be filtered listed in document order.
5704 */
5705
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005706static void
5707xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
5708 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005709 CHECK_ERROR;
5710 SKIP_BLANKS;
5711
5712 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005713 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00005714 SKIP_BLANKS;
5715 }
5716
5717
5718}
5719
5720/**
5721 * xmlXPathScanName:
5722 * @ctxt: the XPath Parser context
5723 *
5724 * Trickery: parse an XML name but without consuming the input flow
5725 * Needed to avoid insanity in the parser state.
5726 *
5727 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5728 * CombiningChar | Extender
5729 *
5730 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5731 *
5732 * [6] Names ::= Name (S Name)*
5733 *
5734 * Returns the Name parsed or NULL
5735 */
5736
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005737static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005738xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
5739 xmlChar buf[XML_MAX_NAMELEN];
5740 int len = 0;
5741
5742 SKIP_BLANKS;
5743 if (!IS_LETTER(CUR) && (CUR != '_') &&
5744 (CUR != ':')) {
5745 return(NULL);
5746 }
5747
5748 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5749 (NXT(len) == '.') || (NXT(len) == '-') ||
5750 (NXT(len) == '_') || (NXT(len) == ':') ||
5751 (IS_COMBINING(NXT(len))) ||
5752 (IS_EXTENDER(NXT(len)))) {
5753 buf[len] = NXT(len);
5754 len++;
5755 if (len >= XML_MAX_NAMELEN) {
5756 xmlGenericError(xmlGenericErrorContext,
5757 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5758 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5759 (NXT(len) == '.') || (NXT(len) == '-') ||
5760 (NXT(len) == '_') || (NXT(len) == ':') ||
5761 (IS_COMBINING(NXT(len))) ||
5762 (IS_EXTENDER(NXT(len))))
5763 len++;
5764 break;
5765 }
5766 }
5767 return(xmlStrndup(buf, len));
5768}
5769
5770/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005771 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005772 * @ctxt: the XPath Parser context
5773 *
5774 * [19] PathExpr ::= LocationPath
5775 * | FilterExpr
5776 * | FilterExpr '/' RelativeLocationPath
5777 * | FilterExpr '//' RelativeLocationPath
5778 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005779 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005780 * The / operator and // operators combine an arbitrary expression
5781 * and a relative location path. It is an error if the expression
5782 * does not evaluate to a node-set.
5783 * The / operator does composition in the same way as when / is
5784 * used in a location path. As in location paths, // is short for
5785 * /descendant-or-self::node()/.
5786 */
5787
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005788static void
5789xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005790 int lc = 1; /* Should we branch to LocationPath ? */
5791 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5792
5793 SKIP_BLANKS;
5794 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5795 (CUR == '\'') || (CUR == '"')) {
5796 lc = 0;
5797 } else if (CUR == '*') {
5798 /* relative or absolute location path */
5799 lc = 1;
5800 } else if (CUR == '/') {
5801 /* relative or absolute location path */
5802 lc = 1;
5803 } else if (CUR == '@') {
5804 /* relative abbreviated attribute location path */
5805 lc = 1;
5806 } else if (CUR == '.') {
5807 /* relative abbreviated attribute location path */
5808 lc = 1;
5809 } else {
5810 /*
5811 * Problem is finding if we have a name here whether it's:
5812 * - a nodetype
5813 * - a function call in which case it's followed by '('
5814 * - an axis in which case it's followed by ':'
5815 * - a element name
5816 * We do an a priori analysis here rather than having to
5817 * maintain parsed token content through the recursive function
5818 * calls. This looks uglier but makes the code quite easier to
5819 * read/write/debug.
5820 */
5821 SKIP_BLANKS;
5822 name = xmlXPathScanName(ctxt);
5823 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
5824#ifdef DEBUG_STEP
5825 xmlGenericError(xmlGenericErrorContext,
5826 "PathExpr: Axis\n");
5827#endif
5828 lc = 1;
5829 xmlFree(name);
5830 } else if (name != NULL) {
5831 int len =xmlStrlen(name);
5832 int blank = 0;
5833
5834
5835 while (NXT(len) != 0) {
5836 if (NXT(len) == '/') {
5837 /* element name */
5838#ifdef DEBUG_STEP
5839 xmlGenericError(xmlGenericErrorContext,
5840 "PathExpr: AbbrRelLocation\n");
5841#endif
5842 lc = 1;
5843 break;
5844 } else if (IS_BLANK(NXT(len))) {
5845 /* skip to next */
5846 blank = 1;
5847 } else if (NXT(len) == ':') {
5848#ifdef DEBUG_STEP
5849 xmlGenericError(xmlGenericErrorContext,
5850 "PathExpr: AbbrRelLocation\n");
5851#endif
5852 lc = 1;
5853 break;
5854 } else if ((NXT(len) == '(')) {
5855 /* Note Type or Function */
5856 if (xmlXPathIsNodeType(name)) {
5857#ifdef DEBUG_STEP
5858 xmlGenericError(xmlGenericErrorContext,
5859 "PathExpr: Type search\n");
5860#endif
5861 lc = 1;
5862 } else {
5863#ifdef DEBUG_STEP
5864 xmlGenericError(xmlGenericErrorContext,
5865 "PathExpr: function call\n");
5866#endif
5867 lc = 0;
5868 }
5869 break;
5870 } else if ((NXT(len) == '[')) {
5871 /* element name */
5872#ifdef DEBUG_STEP
5873 xmlGenericError(xmlGenericErrorContext,
5874 "PathExpr: AbbrRelLocation\n");
5875#endif
5876 lc = 1;
5877 break;
5878 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5879 (NXT(len) == '=')) {
5880 lc = 1;
5881 break;
5882 } else {
5883 lc = 1;
5884 break;
5885 }
5886 len++;
5887 }
5888 if (NXT(len) == 0) {
5889#ifdef DEBUG_STEP
5890 xmlGenericError(xmlGenericErrorContext,
5891 "PathExpr: AbbrRelLocation\n");
5892#endif
5893 /* element name */
5894 lc = 1;
5895 }
5896 xmlFree(name);
5897 } else {
5898 /* make sure all cases are covered explicitely */
5899 XP_ERROR(XPATH_EXPR_ERROR);
5900 }
5901 }
5902
5903 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005904 if (CUR == '/') {
5905 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
5906 } else {
5907 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005908 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005909 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005910 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005911 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005912 CHECK_ERROR;
5913 if ((CUR == '/') && (NXT(1) == '/')) {
5914 SKIP(2);
5915 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005916
5917 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
5918 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5919 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
5920
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005921 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005922 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005923 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005924 }
5925 }
5926 SKIP_BLANKS;
5927}
5928
5929/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005930 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005931 * @ctxt: the XPath Parser context
5932 *
5933 * [18] UnionExpr ::= PathExpr
5934 * | UnionExpr '|' PathExpr
5935 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005936 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005937 */
5938
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005939static void
5940xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
5941 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005942 CHECK_ERROR;
5943 SKIP_BLANKS;
5944 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005945 int op1 = ctxt->comp->last;
5946 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005947
5948 NEXT;
5949 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005950 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005951
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005952 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
5953
Owen Taylor3473f882001-02-23 17:55:21 +00005954 SKIP_BLANKS;
5955 }
Owen Taylor3473f882001-02-23 17:55:21 +00005956}
5957
5958/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005959 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005960 * @ctxt: the XPath Parser context
5961 *
5962 * [27] UnaryExpr ::= UnionExpr
5963 * | '-' UnaryExpr
5964 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005965 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005966 */
5967
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005968static void
5969xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005970 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005971 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005972
5973 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00005974 while (CUR == '-') {
5975 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005976 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005977 NEXT;
5978 SKIP_BLANKS;
5979 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005980
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005981 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005982 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005983 if (found) {
5984 if (minus)
5985 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
5986 else
5987 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005988 }
5989}
5990
5991/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005992 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005993 * @ctxt: the XPath Parser context
5994 *
5995 * [26] MultiplicativeExpr ::= UnaryExpr
5996 * | MultiplicativeExpr MultiplyOperator UnaryExpr
5997 * | MultiplicativeExpr 'div' UnaryExpr
5998 * | MultiplicativeExpr 'mod' UnaryExpr
5999 * [34] MultiplyOperator ::= '*'
6000 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006001 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006002 */
6003
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006004static void
6005xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6006 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006007 CHECK_ERROR;
6008 SKIP_BLANKS;
6009 while ((CUR == '*') ||
6010 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6011 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6012 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006013 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006014
6015 if (CUR == '*') {
6016 op = 0;
6017 NEXT;
6018 } else if (CUR == 'd') {
6019 op = 1;
6020 SKIP(3);
6021 } else if (CUR == 'm') {
6022 op = 2;
6023 SKIP(3);
6024 }
6025 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006026 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006027 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006028 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006029 SKIP_BLANKS;
6030 }
6031}
6032
6033/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006034 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006035 * @ctxt: the XPath Parser context
6036 *
6037 * [25] AdditiveExpr ::= MultiplicativeExpr
6038 * | AdditiveExpr '+' MultiplicativeExpr
6039 * | AdditiveExpr '-' MultiplicativeExpr
6040 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006041 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006042 */
6043
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006044static void
6045xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006046
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006047 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006048 CHECK_ERROR;
6049 SKIP_BLANKS;
6050 while ((CUR == '+') || (CUR == '-')) {
6051 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006052 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006053
6054 if (CUR == '+') plus = 1;
6055 else plus = 0;
6056 NEXT;
6057 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006058 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006059 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006060 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006061 SKIP_BLANKS;
6062 }
6063}
6064
6065/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006066 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006067 * @ctxt: the XPath Parser context
6068 *
6069 * [24] RelationalExpr ::= AdditiveExpr
6070 * | RelationalExpr '<' AdditiveExpr
6071 * | RelationalExpr '>' AdditiveExpr
6072 * | RelationalExpr '<=' AdditiveExpr
6073 * | RelationalExpr '>=' AdditiveExpr
6074 *
6075 * A <= B > C is allowed ? Answer from James, yes with
6076 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6077 * which is basically what got implemented.
6078 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006079 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006080 * on the stack
6081 */
6082
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006083static void
6084xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6085 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006086 CHECK_ERROR;
6087 SKIP_BLANKS;
6088 while ((CUR == '<') ||
6089 (CUR == '>') ||
6090 ((CUR == '<') && (NXT(1) == '=')) ||
6091 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006092 int inf, strict;
6093 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006094
6095 if (CUR == '<') inf = 1;
6096 else inf = 0;
6097 if (NXT(1) == '=') strict = 0;
6098 else strict = 1;
6099 NEXT;
6100 if (!strict) NEXT;
6101 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006102 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006103 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006104 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006105 SKIP_BLANKS;
6106 }
6107}
6108
6109/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006110 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006111 * @ctxt: the XPath Parser context
6112 *
6113 * [23] EqualityExpr ::= RelationalExpr
6114 * | EqualityExpr '=' RelationalExpr
6115 * | EqualityExpr '!=' RelationalExpr
6116 *
6117 * A != B != C is allowed ? Answer from James, yes with
6118 * (RelationalExpr = RelationalExpr) = RelationalExpr
6119 * (RelationalExpr != RelationalExpr) != RelationalExpr
6120 * which is basically what got implemented.
6121 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006122 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006123 *
6124 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006125static void
6126xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6127 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006128 CHECK_ERROR;
6129 SKIP_BLANKS;
6130 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006131 int eq;
6132 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006133
6134 if (CUR == '=') eq = 1;
6135 else eq = 0;
6136 NEXT;
6137 if (!eq) NEXT;
6138 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006139 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006140 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006141 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006142 SKIP_BLANKS;
6143 }
6144}
6145
6146/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006147 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006148 * @ctxt: the XPath Parser context
6149 *
6150 * [22] AndExpr ::= EqualityExpr
6151 * | AndExpr 'and' EqualityExpr
6152 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006153 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006154 *
6155 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006156static void
6157xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6158 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006159 CHECK_ERROR;
6160 SKIP_BLANKS;
6161 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006162 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006163 SKIP(3);
6164 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006165 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006166 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006167 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006168 SKIP_BLANKS;
6169 }
6170}
6171
6172/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006173 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006174 * @ctxt: the XPath Parser context
6175 *
6176 * [14] Expr ::= OrExpr
6177 * [21] OrExpr ::= AndExpr
6178 * | OrExpr 'or' AndExpr
6179 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006180 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006181 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006182static void
6183xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6184 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006185 CHECK_ERROR;
6186 SKIP_BLANKS;
6187 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006188 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006189 SKIP(2);
6190 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006191 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006192 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006193 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6194 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006195 SKIP_BLANKS;
6196 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006197 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6198 /* more ops could be optimized too */
6199 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6200 }
Owen Taylor3473f882001-02-23 17:55:21 +00006201}
6202
6203/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006204 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006205 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006206 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006207 *
6208 * [8] Predicate ::= '[' PredicateExpr ']'
6209 * [9] PredicateExpr ::= Expr
6210 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006211 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006212 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006213static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006214xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006215 int op1 = ctxt->comp->last;
6216
6217 SKIP_BLANKS;
6218 if (CUR != '[') {
6219 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6220 }
6221 NEXT;
6222 SKIP_BLANKS;
6223
6224 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006225 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006226 CHECK_ERROR;
6227
6228 if (CUR != ']') {
6229 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6230 }
6231
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006232 if (filter)
6233 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6234 else
6235 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006236
6237 NEXT;
6238 SKIP_BLANKS;
6239}
6240
6241/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006242 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006243 * @ctxt: the XPath Parser context
6244 * @test: pointer to a xmlXPathTestVal
6245 * @type: pointer to a xmlXPathTypeVal
6246 * @prefix: placeholder for a possible name prefix
6247 *
6248 * [7] NodeTest ::= NameTest
6249 * | NodeType '(' ')'
6250 * | 'processing-instruction' '(' Literal ')'
6251 *
6252 * [37] NameTest ::= '*'
6253 * | NCName ':' '*'
6254 * | QName
6255 * [38] NodeType ::= 'comment'
6256 * | 'text'
6257 * | 'processing-instruction'
6258 * | 'node'
6259 *
6260 * Returns the name found and update @test, @type and @prefix appropriately
6261 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006262static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006263xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6264 xmlXPathTypeVal *type, const xmlChar **prefix,
6265 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006266 int blanks;
6267
6268 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6269 STRANGE;
6270 return(NULL);
6271 }
6272 *type = 0;
6273 *test = 0;
6274 *prefix = NULL;
6275 SKIP_BLANKS;
6276
6277 if ((name == NULL) && (CUR == '*')) {
6278 /*
6279 * All elements
6280 */
6281 NEXT;
6282 *test = NODE_TEST_ALL;
6283 return(NULL);
6284 }
6285
6286 if (name == NULL)
6287 name = xmlXPathParseNCName(ctxt);
6288 if (name == NULL) {
6289 XP_ERROR0(XPATH_EXPR_ERROR);
6290 }
6291
6292 blanks = IS_BLANK(CUR);
6293 SKIP_BLANKS;
6294 if (CUR == '(') {
6295 NEXT;
6296 /*
6297 * NodeType or PI search
6298 */
6299 if (xmlStrEqual(name, BAD_CAST "comment"))
6300 *type = NODE_TYPE_COMMENT;
6301 else if (xmlStrEqual(name, BAD_CAST "node"))
6302 *type = NODE_TYPE_NODE;
6303 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6304 *type = NODE_TYPE_PI;
6305 else if (xmlStrEqual(name, BAD_CAST "text"))
6306 *type = NODE_TYPE_TEXT;
6307 else {
6308 if (name != NULL)
6309 xmlFree(name);
6310 XP_ERROR0(XPATH_EXPR_ERROR);
6311 }
6312
6313 *test = NODE_TEST_TYPE;
6314
6315 SKIP_BLANKS;
6316 if (*type == NODE_TYPE_PI) {
6317 /*
6318 * Specific case: search a PI by name.
6319 */
Owen Taylor3473f882001-02-23 17:55:21 +00006320 if (name != NULL)
6321 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006322 name = NULL;
6323 if (CUR != ')') {
6324 name = xmlXPathParseLiteral(ctxt);
6325 CHECK_ERROR 0;
6326 SKIP_BLANKS;
6327 }
Owen Taylor3473f882001-02-23 17:55:21 +00006328 }
6329 if (CUR != ')') {
6330 if (name != NULL)
6331 xmlFree(name);
6332 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6333 }
6334 NEXT;
6335 return(name);
6336 }
6337 *test = NODE_TEST_NAME;
6338 if ((!blanks) && (CUR == ':')) {
6339 NEXT;
6340
6341 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006342 * Since currently the parser context don't have a
6343 * namespace list associated:
6344 * The namespace name for this prefix can be computed
6345 * only at evaluation time. The compilation is done
6346 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006347 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006348#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006349 *prefix = xmlXPathNsLookup(ctxt->context, name);
6350 if (name != NULL)
6351 xmlFree(name);
6352 if (*prefix == NULL) {
6353 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6354 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006355#else
6356 *prefix = name;
6357#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006358
6359 if (CUR == '*') {
6360 /*
6361 * All elements
6362 */
6363 NEXT;
6364 *test = NODE_TEST_ALL;
6365 return(NULL);
6366 }
6367
6368 name = xmlXPathParseNCName(ctxt);
6369 if (name == NULL) {
6370 XP_ERROR0(XPATH_EXPR_ERROR);
6371 }
6372 }
6373 return(name);
6374}
6375
6376/**
6377 * xmlXPathIsAxisName:
6378 * @name: a preparsed name token
6379 *
6380 * [6] AxisName ::= 'ancestor'
6381 * | 'ancestor-or-self'
6382 * | 'attribute'
6383 * | 'child'
6384 * | 'descendant'
6385 * | 'descendant-or-self'
6386 * | 'following'
6387 * | 'following-sibling'
6388 * | 'namespace'
6389 * | 'parent'
6390 * | 'preceding'
6391 * | 'preceding-sibling'
6392 * | 'self'
6393 *
6394 * Returns the axis or 0
6395 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006396static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006397xmlXPathIsAxisName(const xmlChar *name) {
6398 xmlXPathAxisVal ret = 0;
6399 switch (name[0]) {
6400 case 'a':
6401 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6402 ret = AXIS_ANCESTOR;
6403 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6404 ret = AXIS_ANCESTOR_OR_SELF;
6405 if (xmlStrEqual(name, BAD_CAST "attribute"))
6406 ret = AXIS_ATTRIBUTE;
6407 break;
6408 case 'c':
6409 if (xmlStrEqual(name, BAD_CAST "child"))
6410 ret = AXIS_CHILD;
6411 break;
6412 case 'd':
6413 if (xmlStrEqual(name, BAD_CAST "descendant"))
6414 ret = AXIS_DESCENDANT;
6415 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6416 ret = AXIS_DESCENDANT_OR_SELF;
6417 break;
6418 case 'f':
6419 if (xmlStrEqual(name, BAD_CAST "following"))
6420 ret = AXIS_FOLLOWING;
6421 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6422 ret = AXIS_FOLLOWING_SIBLING;
6423 break;
6424 case 'n':
6425 if (xmlStrEqual(name, BAD_CAST "namespace"))
6426 ret = AXIS_NAMESPACE;
6427 break;
6428 case 'p':
6429 if (xmlStrEqual(name, BAD_CAST "parent"))
6430 ret = AXIS_PARENT;
6431 if (xmlStrEqual(name, BAD_CAST "preceding"))
6432 ret = AXIS_PRECEDING;
6433 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6434 ret = AXIS_PRECEDING_SIBLING;
6435 break;
6436 case 's':
6437 if (xmlStrEqual(name, BAD_CAST "self"))
6438 ret = AXIS_SELF;
6439 break;
6440 }
6441 return(ret);
6442}
6443
6444/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006445 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006446 * @ctxt: the XPath Parser context
6447 *
6448 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6449 * | AbbreviatedStep
6450 *
6451 * [12] AbbreviatedStep ::= '.' | '..'
6452 *
6453 * [5] AxisSpecifier ::= AxisName '::'
6454 * | AbbreviatedAxisSpecifier
6455 *
6456 * [13] AbbreviatedAxisSpecifier ::= '@'?
6457 *
6458 * Modified for XPtr range support as:
6459 *
6460 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6461 * | AbbreviatedStep
6462 * | 'range-to' '(' Expr ')' Predicate*
6463 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006464 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006465 * A location step of . is short for self::node(). This is
6466 * particularly useful in conjunction with //. For example, the
6467 * location path .//para is short for
6468 * self::node()/descendant-or-self::node()/child::para
6469 * and so will select all para descendant elements of the context
6470 * node.
6471 * Similarly, a location step of .. is short for parent::node().
6472 * For example, ../title is short for parent::node()/child::title
6473 * and so will select the title children of the parent of the context
6474 * node.
6475 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006476static void
6477xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006478#ifdef LIBXML_XPTR_ENABLED
6479 int rangeto = 0;
6480 int op2 = -1;
6481#endif
6482
Owen Taylor3473f882001-02-23 17:55:21 +00006483 SKIP_BLANKS;
6484 if ((CUR == '.') && (NXT(1) == '.')) {
6485 SKIP(2);
6486 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006487 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6488 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006489 } else if (CUR == '.') {
6490 NEXT;
6491 SKIP_BLANKS;
6492 } else {
6493 xmlChar *name = NULL;
6494 const xmlChar *prefix = NULL;
6495 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006496 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006497 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006498 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006499
6500 /*
6501 * The modification needed for XPointer change to the production
6502 */
6503#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006504 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006505 name = xmlXPathParseNCName(ctxt);
6506 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006507 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006508 xmlFree(name);
6509 SKIP_BLANKS;
6510 if (CUR != '(') {
6511 XP_ERROR(XPATH_EXPR_ERROR);
6512 }
6513 NEXT;
6514 SKIP_BLANKS;
6515
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006516 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006517 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006518 CHECK_ERROR;
6519
6520 SKIP_BLANKS;
6521 if (CUR != ')') {
6522 XP_ERROR(XPATH_EXPR_ERROR);
6523 }
6524 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006525 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006526 goto eval_predicates;
6527 }
6528 }
6529#endif
6530 if (name == NULL)
6531 name = xmlXPathParseNCName(ctxt);
6532 if (name != NULL) {
6533 axis = xmlXPathIsAxisName(name);
6534 if (axis != 0) {
6535 SKIP_BLANKS;
6536 if ((CUR == ':') && (NXT(1) == ':')) {
6537 SKIP(2);
6538 xmlFree(name);
6539 name = NULL;
6540 } else {
6541 /* an element name can conflict with an axis one :-\ */
6542 axis = AXIS_CHILD;
6543 }
6544 } else {
6545 axis = AXIS_CHILD;
6546 }
6547 } else if (CUR == '@') {
6548 NEXT;
6549 axis = AXIS_ATTRIBUTE;
6550 } else {
6551 axis = AXIS_CHILD;
6552 }
6553
6554 CHECK_ERROR;
6555
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006556 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006557 if (test == 0)
6558 return;
6559
6560#ifdef DEBUG_STEP
6561 xmlGenericError(xmlGenericErrorContext,
6562 "Basis : computing new set\n");
6563#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006564
Owen Taylor3473f882001-02-23 17:55:21 +00006565#ifdef DEBUG_STEP
6566 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006567 if (ctxt->value == NULL)
6568 xmlGenericError(xmlGenericErrorContext, "no value\n");
6569 else if (ctxt->value->nodesetval == NULL)
6570 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6571 else
6572 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006573#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006574
6575eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006576 op1 = ctxt->comp->last;
6577 ctxt->comp->last = -1;
6578
Owen Taylor3473f882001-02-23 17:55:21 +00006579 SKIP_BLANKS;
6580 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006581 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006582 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006583
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006584#ifdef LIBXML_XPTR_ENABLED
6585 if (rangeto) {
6586 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
6587 } else
6588#endif
6589 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
6590 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006591
Owen Taylor3473f882001-02-23 17:55:21 +00006592 }
6593#ifdef DEBUG_STEP
6594 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006595 if (ctxt->value == NULL)
6596 xmlGenericError(xmlGenericErrorContext, "no value\n");
6597 else if (ctxt->value->nodesetval == NULL)
6598 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6599 else
6600 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6601 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006602#endif
6603}
6604
6605/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006606 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006607 * @ctxt: the XPath Parser context
6608 *
6609 * [3] RelativeLocationPath ::= Step
6610 * | RelativeLocationPath '/' Step
6611 * | AbbreviatedRelativeLocationPath
6612 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6613 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006614 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00006615 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006616static void
Owen Taylor3473f882001-02-23 17:55:21 +00006617#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006618xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006619#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006620xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006621#endif
6622(xmlXPathParserContextPtr ctxt) {
6623 SKIP_BLANKS;
6624 if ((CUR == '/') && (NXT(1) == '/')) {
6625 SKIP(2);
6626 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006627 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6628 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006629 } else if (CUR == '/') {
6630 NEXT;
6631 SKIP_BLANKS;
6632 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006633 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006634 SKIP_BLANKS;
6635 while (CUR == '/') {
6636 if ((CUR == '/') && (NXT(1) == '/')) {
6637 SKIP(2);
6638 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006639 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00006640 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006641 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006642 } else if (CUR == '/') {
6643 NEXT;
6644 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006645 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006646 }
6647 SKIP_BLANKS;
6648 }
6649}
6650
6651/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006652 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006653 * @ctxt: the XPath Parser context
6654 *
6655 * [1] LocationPath ::= RelativeLocationPath
6656 * | AbsoluteLocationPath
6657 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6658 * | AbbreviatedAbsoluteLocationPath
6659 * [10] AbbreviatedAbsoluteLocationPath ::=
6660 * '//' RelativeLocationPath
6661 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006662 * Compile a location path
6663 *
Owen Taylor3473f882001-02-23 17:55:21 +00006664 * // is short for /descendant-or-self::node()/. For example,
6665 * //para is short for /descendant-or-self::node()/child::para and
6666 * so will select any para element in the document (even a para element
6667 * that is a document element will be selected by //para since the
6668 * document element node is a child of the root node); div//para is
6669 * short for div/descendant-or-self::node()/child::para and so will
6670 * select all para descendants of div children.
6671 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006672static void
6673xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006674 SKIP_BLANKS;
6675 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006676 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006677 } else {
6678 while (CUR == '/') {
6679 if ((CUR == '/') && (NXT(1) == '/')) {
6680 SKIP(2);
6681 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006682 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6683 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006684 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006685 } else if (CUR == '/') {
6686 NEXT;
6687 SKIP_BLANKS;
6688 if (CUR != 0)
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006689 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006690 }
6691 }
6692 }
6693}
6694
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006695/************************************************************************
6696 * *
6697 * XPath precompiled expression evaluation *
6698 * *
6699 ************************************************************************/
6700
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006701static void
6702xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
6703
6704/**
6705 * xmlXPathNodeCollectAndTest:
6706 * @ctxt: the XPath Parser context
6707 * @op: the XPath precompiled step operation
6708 *
6709 * This is the function implementing a step: based on the current list
6710 * of nodes, it builds up a new list, looking at all nodes under that
6711 * axis and selecting them it also do the predicate filtering
6712 *
6713 * Pushes the new NodeSet resulting from the search.
6714 */
6715static void
6716xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
6717 xmlXPathStepOpPtr op) {
6718 xmlXPathAxisVal axis = op->value;
6719 xmlXPathTestVal test = op->value2;
6720 xmlXPathTypeVal type = op->value3;
6721 const xmlChar *prefix = op->value4;
6722 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006723 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006724
6725#ifdef DEBUG_STEP
6726 int n = 0, t = 0;
6727#endif
6728 int i;
6729 xmlNodeSetPtr ret, list;
6730 xmlXPathTraversalFunction next = NULL;
6731 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
6732 xmlNodePtr cur = NULL;
6733 xmlXPathObjectPtr obj;
6734 xmlNodeSetPtr nodelist;
6735 xmlNodePtr tmp;
6736
6737 CHECK_TYPE(XPATH_NODESET);
6738 obj = valuePop(ctxt);
6739 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006740 if (prefix != NULL) {
6741 URI = xmlXPathNsLookup(ctxt->context, prefix);
6742 if (URI == NULL)
6743 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
6744 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006745
6746#ifdef DEBUG_STEP
6747 xmlGenericError(xmlGenericErrorContext,
6748 "new step : ");
6749#endif
6750 switch (axis) {
6751 case AXIS_ANCESTOR:
6752#ifdef DEBUG_STEP
6753 xmlGenericError(xmlGenericErrorContext,
6754 "axis 'ancestors' ");
6755#endif
6756 next = xmlXPathNextAncestor; break;
6757 case AXIS_ANCESTOR_OR_SELF:
6758#ifdef DEBUG_STEP
6759 xmlGenericError(xmlGenericErrorContext,
6760 "axis 'ancestors-or-self' ");
6761#endif
6762 next = xmlXPathNextAncestorOrSelf; break;
6763 case AXIS_ATTRIBUTE:
6764#ifdef DEBUG_STEP
6765 xmlGenericError(xmlGenericErrorContext,
6766 "axis 'attributes' ");
6767#endif
6768 next = xmlXPathNextAttribute; break;
6769 break;
6770 case AXIS_CHILD:
6771#ifdef DEBUG_STEP
6772 xmlGenericError(xmlGenericErrorContext,
6773 "axis 'child' ");
6774#endif
6775 next = xmlXPathNextChild; break;
6776 case AXIS_DESCENDANT:
6777#ifdef DEBUG_STEP
6778 xmlGenericError(xmlGenericErrorContext,
6779 "axis 'descendant' ");
6780#endif
6781 next = xmlXPathNextDescendant; break;
6782 case AXIS_DESCENDANT_OR_SELF:
6783#ifdef DEBUG_STEP
6784 xmlGenericError(xmlGenericErrorContext,
6785 "axis 'descendant-or-self' ");
6786#endif
6787 next = xmlXPathNextDescendantOrSelf; break;
6788 case AXIS_FOLLOWING:
6789#ifdef DEBUG_STEP
6790 xmlGenericError(xmlGenericErrorContext,
6791 "axis 'following' ");
6792#endif
6793 next = xmlXPathNextFollowing; break;
6794 case AXIS_FOLLOWING_SIBLING:
6795#ifdef DEBUG_STEP
6796 xmlGenericError(xmlGenericErrorContext,
6797 "axis 'following-siblings' ");
6798#endif
6799 next = xmlXPathNextFollowingSibling; break;
6800 case AXIS_NAMESPACE:
6801#ifdef DEBUG_STEP
6802 xmlGenericError(xmlGenericErrorContext,
6803 "axis 'namespace' ");
6804#endif
6805 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
6806 break;
6807 case AXIS_PARENT:
6808#ifdef DEBUG_STEP
6809 xmlGenericError(xmlGenericErrorContext,
6810 "axis 'parent' ");
6811#endif
6812 next = xmlXPathNextParent; break;
6813 case AXIS_PRECEDING:
6814#ifdef DEBUG_STEP
6815 xmlGenericError(xmlGenericErrorContext,
6816 "axis 'preceding' ");
6817#endif
6818 next = xmlXPathNextPreceding; break;
6819 case AXIS_PRECEDING_SIBLING:
6820#ifdef DEBUG_STEP
6821 xmlGenericError(xmlGenericErrorContext,
6822 "axis 'preceding-sibling' ");
6823#endif
6824 next = xmlXPathNextPrecedingSibling; break;
6825 case AXIS_SELF:
6826#ifdef DEBUG_STEP
6827 xmlGenericError(xmlGenericErrorContext,
6828 "axis 'self' ");
6829#endif
6830 next = xmlXPathNextSelf; break;
6831 }
6832 if (next == NULL)
6833 return;
6834
6835 nodelist = obj->nodesetval;
6836 if (nodelist == NULL) {
6837 xmlXPathFreeObject(obj);
6838 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
6839 return;
6840 }
6841 addNode = xmlXPathNodeSetAddUnique;
6842 ret = NULL;
6843#ifdef DEBUG_STEP
6844 xmlGenericError(xmlGenericErrorContext,
6845 " context contains %d nodes\n",
6846 nodelist->nodeNr);
6847 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006848 case NODE_TEST_NONE:
6849 xmlGenericError(xmlGenericErrorContext,
6850 " searching for none !!!\n");
6851 break;
6852 case NODE_TEST_TYPE:
6853 xmlGenericError(xmlGenericErrorContext,
6854 " searching for type %d\n", type);
6855 break;
6856 case NODE_TEST_PI:
6857 xmlGenericError(xmlGenericErrorContext,
6858 " searching for PI !!!\n");
6859 break;
6860 case NODE_TEST_ALL:
6861 xmlGenericError(xmlGenericErrorContext,
6862 " searching for *\n");
6863 break;
6864 case NODE_TEST_NS:
6865 xmlGenericError(xmlGenericErrorContext,
6866 " searching for namespace %s\n",
6867 prefix);
6868 break;
6869 case NODE_TEST_NAME:
6870 xmlGenericError(xmlGenericErrorContext,
6871 " searching for name %s\n", name);
6872 if (prefix != NULL)
6873 xmlGenericError(xmlGenericErrorContext,
6874 " with namespace %s\n",
6875 prefix);
6876 break;
6877 }
6878 xmlGenericError(xmlGenericErrorContext, "Testing : ");
6879#endif
6880 /*
6881 * 2.3 Node Tests
6882 * - For the attribute axis, the principal node type is attribute.
6883 * - For the namespace axis, the principal node type is namespace.
6884 * - For other axes, the principal node type is element.
6885 *
6886 * A node test * is true for any node of the
6887 * principal node type. For example, child::* willi
6888 * select all element children of the context node
6889 */
6890 tmp = ctxt->context->node;
6891 for (i = 0;i < nodelist->nodeNr; i++) {
6892 ctxt->context->node = nodelist->nodeTab[i];
6893
6894 cur = NULL;
6895 list = xmlXPathNodeSetCreate(NULL);
6896 do {
6897 cur = next(ctxt, cur);
6898 if (cur == NULL) break;
6899#ifdef DEBUG_STEP
6900 t++;
6901 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
6902#endif
6903 switch (test) {
6904 case NODE_TEST_NONE:
6905 ctxt->context->node = tmp;
6906 STRANGE
6907 return;
6908 case NODE_TEST_TYPE:
6909 if ((cur->type == type) ||
6910 ((type == NODE_TYPE_NODE) &&
6911 ((cur->type == XML_DOCUMENT_NODE) ||
6912 (cur->type == XML_HTML_DOCUMENT_NODE) ||
6913 (cur->type == XML_ELEMENT_NODE) ||
6914 (cur->type == XML_PI_NODE) ||
6915 (cur->type == XML_COMMENT_NODE) ||
6916 (cur->type == XML_CDATA_SECTION_NODE) ||
6917 (cur->type == XML_TEXT_NODE)))) {
6918#ifdef DEBUG_STEP
6919 n++;
6920#endif
6921 addNode(list, cur);
6922 }
6923 break;
6924 case NODE_TEST_PI:
6925 if (cur->type == XML_PI_NODE) {
6926 if ((name != NULL) &&
6927 (!xmlStrEqual(name, cur->name)))
6928 break;
6929#ifdef DEBUG_STEP
6930 n++;
6931#endif
6932 addNode(list, cur);
6933 }
6934 break;
6935 case NODE_TEST_ALL:
6936 if (axis == AXIS_ATTRIBUTE) {
6937 if (cur->type == XML_ATTRIBUTE_NODE) {
6938#ifdef DEBUG_STEP
6939 n++;
6940#endif
6941 addNode(list, cur);
6942 }
6943 } else if (axis == AXIS_NAMESPACE) {
6944 if (cur->type == XML_NAMESPACE_DECL) {
6945#ifdef DEBUG_STEP
6946 n++;
6947#endif
6948 addNode(list, cur);
6949 }
6950 } else {
6951 if ((cur->type == XML_ELEMENT_NODE) ||
6952 (cur->type == XML_DOCUMENT_NODE) ||
6953 (cur->type == XML_HTML_DOCUMENT_NODE)) {
6954 if (prefix == NULL) {
6955#ifdef DEBUG_STEP
6956 n++;
6957#endif
6958 addNode(list, cur);
6959 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00006960 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006961 cur->ns->href))) {
6962#ifdef DEBUG_STEP
6963 n++;
6964#endif
6965 addNode(list, cur);
6966 }
6967 }
6968 }
6969 break;
6970 case NODE_TEST_NS: {
6971 TODO;
6972 break;
6973 }
6974 case NODE_TEST_NAME:
6975 switch (cur->type) {
6976 case XML_ELEMENT_NODE:
6977 if (xmlStrEqual(name, cur->name)) {
6978 if (prefix == NULL) {
6979 if ((cur->ns == NULL) ||
6980 (cur->ns->prefix == NULL)) {
6981#ifdef DEBUG_STEP
6982 n++;
6983#endif
6984 addNode(list, cur);
6985 }
6986 } else {
6987 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00006988 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006989 cur->ns->href))) {
6990#ifdef DEBUG_STEP
6991 n++;
6992#endif
6993 addNode(list, cur);
6994 }
6995 }
6996 }
6997 break;
6998 case XML_ATTRIBUTE_NODE: {
6999 xmlAttrPtr attr = (xmlAttrPtr) cur;
7000 if (xmlStrEqual(name, attr->name)) {
7001 if (prefix == NULL) {
7002 if ((attr->ns == NULL) ||
7003 (attr->ns->prefix == NULL)) {
7004#ifdef DEBUG_STEP
7005 n++;
7006#endif
7007 addNode(list, (xmlNodePtr) attr);
7008 }
7009 } else {
7010 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007011 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007012 attr->ns->href))) {
7013#ifdef DEBUG_STEP
7014 n++;
7015#endif
7016 addNode(list, (xmlNodePtr) attr);
7017 }
7018 }
7019 }
7020 break;
7021 }
7022 case XML_NAMESPACE_DECL: {
7023 TODO;
7024 break;
7025 }
7026 default:
7027 break;
7028 }
7029 break;
7030 }
7031 } while (cur != NULL);
7032
7033 /*
7034 * If there is some predicate filtering do it now
7035 */
7036 if (op->ch2 != -1) {
7037 xmlXPathObjectPtr obj2;
7038
7039 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7040 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7041 CHECK_TYPE(XPATH_NODESET);
7042 obj2 = valuePop(ctxt);
7043 list = obj2->nodesetval;
7044 obj2->nodesetval = NULL;
7045 xmlXPathFreeObject(obj2);
7046 }
7047 if (ret == NULL) {
7048 ret = list;
7049 } else {
7050 ret = xmlXPathNodeSetMerge(ret, list);
7051 xmlXPathFreeNodeSet(list);
7052 }
7053 }
7054 ctxt->context->node = tmp;
7055#ifdef DEBUG_STEP
7056 xmlGenericError(xmlGenericErrorContext,
7057 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7058#endif
7059 xmlXPathFreeObject(obj);
7060 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7061}
7062
Owen Taylor3473f882001-02-23 17:55:21 +00007063/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007064 * xmlXPathCompOpEval:
7065 * @ctxt: the XPath parser context with the compiled expression
7066 * @op: an XPath compiled operation
7067 *
7068 * Evaluate the Precompiled XPath operation
7069 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007070static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007071xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7072 int equal, ret;
7073 xmlXPathCompExprPtr comp;
7074 xmlXPathObjectPtr arg1, arg2;
7075
7076 comp = ctxt->comp;
7077 switch (op->op) {
7078 case XPATH_OP_END:
7079 return;
7080 case XPATH_OP_AND:
7081 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7082 xmlXPathBooleanFunction(ctxt, 1);
7083 if (ctxt->value->boolval == 0)
7084 return;
7085 arg2 = valuePop(ctxt);
7086 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7087 xmlXPathBooleanFunction(ctxt, 1);
7088 arg1 = valuePop(ctxt);
7089 arg1->boolval &= arg2->boolval;
7090 valuePush(ctxt, arg1);
7091 xmlXPathFreeObject(arg2);
7092 return;
7093 case XPATH_OP_OR:
7094 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7095 xmlXPathBooleanFunction(ctxt, 1);
7096 if (ctxt->value->boolval == 1)
7097 return;
7098 arg2 = valuePop(ctxt);
7099 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7100 xmlXPathBooleanFunction(ctxt, 1);
7101 arg1 = valuePop(ctxt);
7102 arg1->boolval |= arg2->boolval;
7103 valuePush(ctxt, arg1);
7104 xmlXPathFreeObject(arg2);
7105 return;
7106 case XPATH_OP_EQUAL:
7107 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7108 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7109 equal = xmlXPathEqualValues(ctxt);
7110 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7111 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7112 return;
7113 case XPATH_OP_CMP:
7114 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7115 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7116 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7117 valuePush(ctxt, xmlXPathNewBoolean(ret));
7118 return;
7119 case XPATH_OP_PLUS:
7120 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7121 if (op->ch2 != -1)
7122 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7123 if (op->value == 0) xmlXPathSubValues(ctxt);
7124 else if (op->value == 1) xmlXPathAddValues(ctxt);
7125 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7126 else if (op->value == 3) {
7127 xmlXPathObjectPtr arg;
7128
7129 POP_FLOAT
7130 valuePush(ctxt, arg);
7131 }
7132 return;
7133 case XPATH_OP_MULT:
7134 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7135 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7136 if (op->value == 0) xmlXPathMultValues(ctxt);
7137 else if (op->value == 1) xmlXPathDivValues(ctxt);
7138 else if (op->value == 2) xmlXPathModValues(ctxt);
7139 return;
7140 case XPATH_OP_UNION:
7141 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7142 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7143 CHECK_TYPE(XPATH_NODESET);
7144 arg2 = valuePop(ctxt);
7145
7146 CHECK_TYPE(XPATH_NODESET);
7147 arg1 = valuePop(ctxt);
7148
7149 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7150 arg2->nodesetval);
7151 valuePush(ctxt, arg1);
7152 xmlXPathFreeObject(arg2);
7153 return;
7154 case XPATH_OP_ROOT:
7155 xmlXPathRoot(ctxt);
7156 return;
7157 case XPATH_OP_NODE:
7158 if (op->ch1 != -1)
7159 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7160 if (op->ch2 != -1)
7161 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7162 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7163 return;
7164 case XPATH_OP_RESET:
7165 if (op->ch1 != -1)
7166 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7167 if (op->ch2 != -1)
7168 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7169 ctxt->context->node = NULL;
7170 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007171 case XPATH_OP_COLLECT: {
7172 if (op->ch1 == -1)
7173 return;
7174
7175 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7176 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007177 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007178 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007179 case XPATH_OP_VALUE:
7180 valuePush(ctxt,
7181 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7182 return;
7183 case XPATH_OP_VARIABLE: {
7184 if (op->ch1 != -1)
7185 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7186 if (op->value5 == NULL)
7187 valuePush(ctxt,
7188 xmlXPathVariableLookup(ctxt->context, op->value4));
7189 else {
7190 const xmlChar *URI;
7191 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7192 if (URI == NULL) {
7193 xmlGenericError(xmlGenericErrorContext,
7194 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7195 op->value4, op->value5);
7196 return;
7197 }
7198 valuePush(ctxt,
7199 xmlXPathVariableLookupNS(ctxt->context,
7200 op->value4, URI));
7201 }
7202 return;
7203 }
7204 case XPATH_OP_FUNCTION: {
7205 xmlXPathFunction func;
7206
7207 if (op->ch1 != -1)
7208 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7209 if (op->value5 == NULL)
7210 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7211 else {
7212 const xmlChar *URI;
7213 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7214 if (URI == NULL) {
7215 xmlGenericError(xmlGenericErrorContext,
7216 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7217 op->value4, op->value5);
7218 return;
7219 }
7220 func = xmlXPathFunctionLookupNS(ctxt->context,
7221 op->value4, URI);
7222 }
7223 if (func == NULL) {
7224 xmlGenericError(xmlGenericErrorContext,
7225 "xmlXPathRunEval: function %s not found\n",
7226 op->value4);
7227 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
7228 return;
7229 }
7230 func(ctxt, op->value);
7231 return;
7232 }
7233 case XPATH_OP_ARG:
7234 if (op->ch1 != -1)
7235 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7236 if (op->ch2 != -1)
7237 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7238 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007239 case XPATH_OP_PREDICATE:
7240 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007241 xmlXPathObjectPtr res;
7242 xmlXPathObjectPtr obj, tmp;
7243 xmlNodeSetPtr newset = NULL;
7244 xmlNodeSetPtr oldset;
7245 xmlNodePtr oldnode;
7246 int i;
7247
7248 if (op->ch1 != -1)
7249 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7250 if (op->ch2 == -1)
7251 return;
7252
7253 oldnode = ctxt->context->node;
7254
7255#ifdef LIBXML_XPTR_ENABLED
7256 /*
7257 * Hum are we filtering the result of an XPointer expression
7258 */
7259 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007260 xmlLocationSetPtr newlocset = NULL;
7261 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007262
7263 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007264 * Extract the old locset, and then evaluate the result of the
7265 * expression for all the element in the locset. use it to grow
7266 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007267 */
7268 CHECK_TYPE(XPATH_LOCATIONSET);
7269 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007270 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007271 ctxt->context->node = NULL;
7272
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007273 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007274 ctxt->context->contextSize = 0;
7275 ctxt->context->proximityPosition = 0;
7276 if (op->ch2 != -1)
7277 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7278 res = valuePop(ctxt);
7279 if (res != NULL)
7280 xmlXPathFreeObject(res);
7281 valuePush(ctxt, obj);
7282 CHECK_ERROR;
7283 return;
7284 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007285 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007286
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007287 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007288 /*
7289 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007290 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007291 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007292 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007293 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7294 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007295 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007296 ctxt->context->proximityPosition = i + 1;
7297
7298 if (op->ch2 != -1)
7299 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7300 CHECK_ERROR;
7301
7302 /*
7303 * The result of the evaluation need to be tested to
7304 * decided whether the filter succeeded or not
7305 */
7306 res = valuePop(ctxt);
7307 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007308 xmlXPtrLocationSetAdd(newlocset,
7309 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007310 }
7311
7312 /*
7313 * Cleanup
7314 */
7315 if (res != NULL)
7316 xmlXPathFreeObject(res);
7317 if (ctxt->value == tmp) {
7318 res = valuePop(ctxt);
7319 xmlXPathFreeObject(res);
7320 }
7321
7322 ctxt->context->node = NULL;
7323 }
7324
7325 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007326 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007327 */
7328 xmlXPathFreeObject(obj);
7329 ctxt->context->node = NULL;
7330 ctxt->context->contextSize = -1;
7331 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007332 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007333 ctxt->context->node = oldnode;
7334 return;
7335 }
7336#endif /* LIBXML_XPTR_ENABLED */
7337
7338 /*
7339 * Extract the old set, and then evaluate the result of the
7340 * expression for all the element in the set. use it to grow
7341 * up a new set.
7342 */
7343 CHECK_TYPE(XPATH_NODESET);
7344 obj = valuePop(ctxt);
7345 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007346
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007347 oldnode = ctxt->context->node;
7348 ctxt->context->node = NULL;
7349
7350 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7351 ctxt->context->contextSize = 0;
7352 ctxt->context->proximityPosition = 0;
7353 if (op->ch2 != -1)
7354 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7355 res = valuePop(ctxt);
7356 if (res != NULL)
7357 xmlXPathFreeObject(res);
7358 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007359 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007360 CHECK_ERROR;
7361 } else {
7362 /*
7363 * Initialize the new set.
7364 */
7365 newset = xmlXPathNodeSetCreate(NULL);
7366
7367 for (i = 0; i < oldset->nodeNr; i++) {
7368 /*
7369 * Run the evaluation with a node list made of
7370 * a single item in the nodeset.
7371 */
7372 ctxt->context->node = oldset->nodeTab[i];
7373 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7374 valuePush(ctxt, tmp);
7375 ctxt->context->contextSize = oldset->nodeNr;
7376 ctxt->context->proximityPosition = i + 1;
7377
7378 if (op->ch2 != -1)
7379 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7380 CHECK_ERROR;
7381
7382 /*
7383 * The result of the evaluation need to be tested to
7384 * decided whether the filter succeeded or not
7385 */
7386 res = valuePop(ctxt);
7387 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7388 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7389 }
7390
7391 /*
7392 * Cleanup
7393 */
7394 if (res != NULL)
7395 xmlXPathFreeObject(res);
7396 if (ctxt->value == tmp) {
7397 res = valuePop(ctxt);
7398 xmlXPathFreeObject(res);
7399 }
7400
7401 ctxt->context->node = NULL;
7402 }
7403
7404 /*
7405 * The result is used as the new evaluation set.
7406 */
7407 xmlXPathFreeObject(obj);
7408 ctxt->context->node = NULL;
7409 ctxt->context->contextSize = -1;
7410 ctxt->context->proximityPosition = -1;
7411 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7412 }
7413 ctxt->context->node = oldnode;
7414 return;
7415 }
7416 case XPATH_OP_SORT:
7417 if (op->ch1 != -1)
7418 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7419 if ((ctxt->value != NULL) &&
7420 (ctxt->value->type == XPATH_NODESET) &&
7421 (ctxt->value->nodesetval != NULL))
7422 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7423 return;
7424#ifdef LIBXML_XPTR_ENABLED
7425 case XPATH_OP_RANGETO: {
7426 xmlXPathObjectPtr range;
7427 xmlXPathObjectPtr res, obj;
7428 xmlXPathObjectPtr tmp;
7429 xmlLocationSetPtr newset = NULL;
7430 xmlNodeSetPtr oldset;
7431 int i;
7432
7433 if (op->ch1 != -1)
7434 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7435 if (op->ch2 == -1)
7436 return;
7437
7438 CHECK_TYPE(XPATH_NODESET);
7439 obj = valuePop(ctxt);
7440 oldset = obj->nodesetval;
7441 ctxt->context->node = NULL;
7442
7443 newset = xmlXPtrLocationSetCreate(NULL);
7444
Daniel Veillard911f49a2001-04-07 15:39:35 +00007445 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007446 for (i = 0; i < oldset->nodeNr; i++) {
7447 /*
7448 * Run the evaluation with a node list made of a single item
7449 * in the nodeset.
7450 */
7451 ctxt->context->node = oldset->nodeTab[i];
7452 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7453 valuePush(ctxt, tmp);
7454
7455 if (op->ch2 != -1)
7456 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7457 CHECK_ERROR;
7458
7459 /*
7460 * The result of the evaluation need to be tested to
7461 * decided whether the filter succeeded or not
7462 */
7463 res = valuePop(ctxt);
7464 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7465 if (range != NULL) {
7466 xmlXPtrLocationSetAdd(newset, range);
7467 }
7468
7469 /*
7470 * Cleanup
7471 */
7472 if (res != NULL)
7473 xmlXPathFreeObject(res);
7474 if (ctxt->value == tmp) {
7475 res = valuePop(ctxt);
7476 xmlXPathFreeObject(res);
7477 }
7478
7479 ctxt->context->node = NULL;
7480 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007481 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007482
7483 /*
7484 * The result is used as the new evaluation set.
7485 */
7486 xmlXPathFreeObject(obj);
7487 ctxt->context->node = NULL;
7488 ctxt->context->contextSize = -1;
7489 ctxt->context->proximityPosition = -1;
7490 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7491 return;
7492 }
7493#endif /* LIBXML_XPTR_ENABLED */
7494 }
7495 xmlGenericError(xmlGenericErrorContext,
7496 "XPath: unknown precompiled operation %d\n",
7497 op->op);
7498 return;
7499}
7500
7501/**
7502 * xmlXPathRunEval:
7503 * @ctxt: the XPath parser context with the compiled expression
7504 *
7505 * Evaluate the Precompiled XPath expression in the given context.
7506 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007507static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007508xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7509 xmlXPathCompExprPtr comp;
7510
7511 if ((ctxt == NULL) || (ctxt->comp == NULL))
7512 return;
7513
7514 if (ctxt->valueTab == NULL) {
7515 /* Allocate the value stack */
7516 ctxt->valueTab = (xmlXPathObjectPtr *)
7517 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7518 if (ctxt->valueTab == NULL) {
7519 xmlFree(ctxt);
7520 xmlGenericError(xmlGenericErrorContext,
7521 "xmlXPathRunEval: out of memory\n");
7522 return;
7523 }
7524 ctxt->valueNr = 0;
7525 ctxt->valueMax = 10;
7526 ctxt->value = NULL;
7527 }
7528 comp = ctxt->comp;
7529 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7530}
7531
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007532/************************************************************************
7533 * *
7534 * Public interfaces *
7535 * *
7536 ************************************************************************/
7537
7538/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007539 * xmlXPathEvalPredicate:
7540 * @ctxt: the XPath context
7541 * @res: the Predicate Expression evaluation result
7542 *
7543 * Evaluate a predicate result for the current node.
7544 * A PredicateExpr is evaluated by evaluating the Expr and converting
7545 * the result to a boolean. If the result is a number, the result will
7546 * be converted to true if the number is equal to the position of the
7547 * context node in the context node list (as returned by the position
7548 * function) and will be converted to false otherwise; if the result
7549 * is not a number, then the result will be converted as if by a call
7550 * to the boolean function.
7551 *
7552 * Return 1 if predicate is true, 0 otherwise
7553 */
7554int
7555xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7556 if (res == NULL) return(0);
7557 switch (res->type) {
7558 case XPATH_BOOLEAN:
7559 return(res->boolval);
7560 case XPATH_NUMBER:
7561 return(res->floatval == ctxt->proximityPosition);
7562 case XPATH_NODESET:
7563 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007564 if (res->nodesetval == NULL)
7565 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007566 return(res->nodesetval->nodeNr != 0);
7567 case XPATH_STRING:
7568 return((res->stringval != NULL) &&
7569 (xmlStrlen(res->stringval) != 0));
7570 default:
7571 STRANGE
7572 }
7573 return(0);
7574}
7575
7576/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007577 * xmlXPathEvaluatePredicateResult:
7578 * @ctxt: the XPath Parser context
7579 * @res: the Predicate Expression evaluation result
7580 *
7581 * Evaluate a predicate result for the current node.
7582 * A PredicateExpr is evaluated by evaluating the Expr and converting
7583 * the result to a boolean. If the result is a number, the result will
7584 * be converted to true if the number is equal to the position of the
7585 * context node in the context node list (as returned by the position
7586 * function) and will be converted to false otherwise; if the result
7587 * is not a number, then the result will be converted as if by a call
7588 * to the boolean function.
7589 *
7590 * Return 1 if predicate is true, 0 otherwise
7591 */
7592int
7593xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
7594 xmlXPathObjectPtr res) {
7595 if (res == NULL) return(0);
7596 switch (res->type) {
7597 case XPATH_BOOLEAN:
7598 return(res->boolval);
7599 case XPATH_NUMBER:
7600 return(res->floatval == ctxt->context->proximityPosition);
7601 case XPATH_NODESET:
7602 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00007603 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00007604 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007605 return(res->nodesetval->nodeNr != 0);
7606 case XPATH_STRING:
7607 return((res->stringval != NULL) &&
7608 (xmlStrlen(res->stringval) != 0));
7609 default:
7610 STRANGE
7611 }
7612 return(0);
7613}
7614
7615/**
7616 * xmlXPathCompile:
7617 * @str: the XPath expression
7618 *
7619 * Compile an XPath expression
7620 *
7621 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7622 * the caller has to free the object.
7623 */
7624xmlXPathCompExprPtr
7625xmlXPathCompile(const xmlChar *str) {
7626 xmlXPathParserContextPtr ctxt;
7627 xmlXPathCompExprPtr comp;
7628
7629 xmlXPathInit();
7630
7631 ctxt = xmlXPathNewParserContext(str, NULL);
7632 xmlXPathCompileExpr(ctxt);
7633
Daniel Veillard40af6492001-04-22 08:50:55 +00007634 if (*ctxt->cur != 0) {
7635 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7636 comp = NULL;
7637 } else {
7638 comp = ctxt->comp;
7639 ctxt->comp = NULL;
7640 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007641 xmlXPathFreeParserContext(ctxt);
7642 return(comp);
7643}
7644
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007645/**
7646 * xmlXPathCompiledEval:
7647 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00007648 * @ctx: the XPath context
7649 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007650 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00007651 *
7652 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7653 * the caller has to free the object.
7654 */
7655xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007656xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00007657 xmlXPathParserContextPtr ctxt;
7658 xmlXPathObjectPtr res, tmp, init = NULL;
7659 int stack = 0;
7660
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007661 if ((comp == NULL) || (ctx == NULL))
7662 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007663 xmlXPathInit();
7664
7665 CHECK_CONTEXT(ctx)
7666
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007667 ctxt = xmlXPathCompParserContext(comp, ctx);
7668 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007669
7670 if (ctxt->value == NULL) {
7671 xmlGenericError(xmlGenericErrorContext,
7672 "xmlXPathEval: evaluation failed\n");
7673 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007674 } else {
7675 res = valuePop(ctxt);
7676 }
7677
7678 do {
7679 tmp = valuePop(ctxt);
7680 if (tmp != NULL) {
7681 if (tmp != init)
7682 stack++;
7683 xmlXPathFreeObject(tmp);
7684 }
7685 } while (tmp != NULL);
7686 if ((stack != 0) && (res != NULL)) {
7687 xmlGenericError(xmlGenericErrorContext,
7688 "xmlXPathEval: %d object left on the stack\n",
7689 stack);
7690 }
7691 if (ctxt->error != XPATH_EXPRESSION_OK) {
7692 xmlXPathFreeObject(res);
7693 res = NULL;
7694 }
7695
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007696
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007697 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007698 xmlXPathFreeParserContext(ctxt);
7699 return(res);
7700}
7701
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007702/**
7703 * xmlXPathEvalExpr:
7704 * @ctxt: the XPath Parser context
7705 *
7706 * Parse and evaluate an XPath expression in the given context,
7707 * then push the result on the context stack
7708 */
7709void
7710xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
7711 xmlXPathCompileExpr(ctxt);
7712 xmlXPathRunEval(ctxt);
7713}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007714
7715/**
7716 * xmlXPathEval:
7717 * @str: the XPath expression
7718 * @ctx: the XPath context
7719 *
7720 * Evaluate the XPath Location Path in the given context.
7721 *
7722 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7723 * the caller has to free the object.
7724 */
7725xmlXPathObjectPtr
7726xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
7727 xmlXPathParserContextPtr ctxt;
7728 xmlXPathObjectPtr res, tmp, init = NULL;
7729 int stack = 0;
7730
7731 xmlXPathInit();
7732
7733 CHECK_CONTEXT(ctx)
7734
7735 ctxt = xmlXPathNewParserContext(str, ctx);
7736 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007737
7738 if (ctxt->value == NULL) {
7739 xmlGenericError(xmlGenericErrorContext,
7740 "xmlXPathEval: evaluation failed\n");
7741 res = NULL;
7742 } else if (*ctxt->cur != 0) {
7743 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7744 res = NULL;
7745 } else {
7746 res = valuePop(ctxt);
7747 }
7748
7749 do {
7750 tmp = valuePop(ctxt);
7751 if (tmp != NULL) {
7752 if (tmp != init)
7753 stack++;
7754 xmlXPathFreeObject(tmp);
7755 }
7756 } while (tmp != NULL);
7757 if ((stack != 0) && (res != NULL)) {
7758 xmlGenericError(xmlGenericErrorContext,
7759 "xmlXPathEval: %d object left on the stack\n",
7760 stack);
7761 }
7762 if (ctxt->error != XPATH_EXPRESSION_OK) {
7763 xmlXPathFreeObject(res);
7764 res = NULL;
7765 }
7766
Owen Taylor3473f882001-02-23 17:55:21 +00007767 xmlXPathFreeParserContext(ctxt);
7768 return(res);
7769}
7770
7771/**
7772 * xmlXPathEvalExpression:
7773 * @str: the XPath expression
7774 * @ctxt: the XPath context
7775 *
7776 * Evaluate the XPath expression in the given context.
7777 *
7778 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
7779 * the caller has to free the object.
7780 */
7781xmlXPathObjectPtr
7782xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
7783 xmlXPathParserContextPtr pctxt;
7784 xmlXPathObjectPtr res, tmp;
7785 int stack = 0;
7786
7787 xmlXPathInit();
7788
7789 CHECK_CONTEXT(ctxt)
7790
7791 pctxt = xmlXPathNewParserContext(str, ctxt);
7792 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007793
7794 if (*pctxt->cur != 0) {
7795 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7796 res = NULL;
7797 } else {
7798 res = valuePop(pctxt);
7799 }
7800 do {
7801 tmp = valuePop(pctxt);
7802 if (tmp != NULL) {
7803 xmlXPathFreeObject(tmp);
7804 stack++;
7805 }
7806 } while (tmp != NULL);
7807 if ((stack != 0) && (res != NULL)) {
7808 xmlGenericError(xmlGenericErrorContext,
7809 "xmlXPathEvalExpression: %d object left on the stack\n",
7810 stack);
7811 }
7812 xmlXPathFreeParserContext(pctxt);
7813 return(res);
7814}
7815
7816/**
7817 * xmlXPathRegisterAllFunctions:
7818 * @ctxt: the XPath context
7819 *
7820 * Registers all default XPath functions in this context
7821 */
7822void
7823xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
7824{
7825 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
7826 xmlXPathBooleanFunction);
7827 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
7828 xmlXPathCeilingFunction);
7829 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
7830 xmlXPathCountFunction);
7831 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
7832 xmlXPathConcatFunction);
7833 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
7834 xmlXPathContainsFunction);
7835 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
7836 xmlXPathIdFunction);
7837 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
7838 xmlXPathFalseFunction);
7839 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
7840 xmlXPathFloorFunction);
7841 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
7842 xmlXPathLastFunction);
7843 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
7844 xmlXPathLangFunction);
7845 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
7846 xmlXPathLocalNameFunction);
7847 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
7848 xmlXPathNotFunction);
7849 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
7850 xmlXPathNameFunction);
7851 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
7852 xmlXPathNamespaceURIFunction);
7853 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
7854 xmlXPathNormalizeFunction);
7855 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
7856 xmlXPathNumberFunction);
7857 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
7858 xmlXPathPositionFunction);
7859 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
7860 xmlXPathRoundFunction);
7861 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
7862 xmlXPathStringFunction);
7863 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
7864 xmlXPathStringLengthFunction);
7865 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
7866 xmlXPathStartsWithFunction);
7867 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
7868 xmlXPathSubstringFunction);
7869 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
7870 xmlXPathSubstringBeforeFunction);
7871 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
7872 xmlXPathSubstringAfterFunction);
7873 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
7874 xmlXPathSumFunction);
7875 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
7876 xmlXPathTrueFunction);
7877 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
7878 xmlXPathTranslateFunction);
7879}
7880
7881#endif /* LIBXML_XPATH_ENABLED */