blob: 89b139f8443f2ab2cf3f0ce2afc27577d0eee4e5 [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
19#ifdef WIN32
20#include "win32config.h"
21#else
22#include "config.h"
23#endif
24
25#include <libxml/xmlversion.h>
26#ifdef LIBXML_XPATH_ENABLED
27
28#include <stdio.h>
29#include <string.h>
30
31#ifdef HAVE_SYS_TYPES_H
32#include <sys/types.h>
33#endif
34#ifdef HAVE_MATH_H
35#include <math.h>
36#endif
37#ifdef HAVE_FLOAT_H
38#include <float.h>
39#endif
40#ifdef HAVE_IEEEFP_H
41#include <ieeefp.h>
42#endif
43#ifdef HAVE_NAN_H
44#include <nan.h>
45#endif
46#ifdef HAVE_CTYPE_H
47#include <ctype.h>
48#endif
49
50#include <libxml/xmlmemory.h>
51#include <libxml/tree.h>
52#include <libxml/valid.h>
53#include <libxml/xpath.h>
54#include <libxml/xpathInternals.h>
55#include <libxml/parserInternals.h>
56#include <libxml/hash.h>
57#ifdef LIBXML_XPTR_ENABLED
58#include <libxml/xpointer.h>
59#endif
60#ifdef LIBXML_DEBUG_ENABLED
61#include <libxml/debugXML.h>
62#endif
63#include <libxml/xmlerror.h>
64
65/* #define DEBUG */
66/* #define DEBUG_STEP */
67/* #define DEBUG_EXPR */
68
69void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
70double xmlXPathStringEvalNumber(const xmlChar *str);
71
Daniel Veillard9e7160d2001-03-18 23:17:47 +000072/************************************************************************
73 * *
74 * Floating point stuff *
75 * *
76 ************************************************************************/
77
Owen Taylor3473f882001-02-23 17:55:21 +000078/*
Owen Taylor3473f882001-02-23 17:55:21 +000079 * The lack of portability of this section of the libc is annoying !
80 */
81double xmlXPathNAN = 0;
82double xmlXPathPINF = 1;
83double xmlXPathNINF = -1;
84
85#ifndef isinf
86#ifndef HAVE_ISINF
87
88#if HAVE_FPCLASS
89
90int isinf(double d) {
91 fpclass_t type = fpclass(d);
92 switch (type) {
93 case FP_NINF:
94 return(-1);
95 case FP_PINF:
96 return(1);
97 }
98 return(0);
99}
100
101#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
102
103#if HAVE_FP_CLASS_H
104#include <fp_class.h>
105#endif
106
107int isinf(double d) {
108#if HAVE_FP_CLASS
109 int fpclass = fp_class(d);
110#else
111 int fpclass = fp_class_d(d);
112#endif
113 if (fpclass == FP_POS_INF)
114 return(1);
115 if (fpclass == FP_NEG_INF)
116 return(-1);
117 return(0);
118}
119
120#elif defined(HAVE_CLASS)
121
122int isinf(double d) {
123 int fpclass = class(d);
124 if (fpclass == FP_PLUS_INF)
125 return(1);
126 if (fpclass == FP_MINUS_INF)
127 return(-1);
128 return(0);
129}
130#elif defined(finite) || defined(HAVE_FINITE)
131int isinf(double x) { return !finite(x) && x==x; }
132#elif defined(HUGE_VAL)
133int isinf(double x)
134{
135 if (x == HUGE_VAL)
136 return(1);
137 if (x == -HUGE_VAL)
138 return(-1);
139 return(0);
140}
141#endif
142
143#endif /* ! HAVE_ISINF */
144#endif /* ! defined(isinf) */
145
146#ifndef isnan
147#ifndef HAVE_ISNAN
148
149#ifdef HAVE_ISNAND
150#define isnan(f) isnand(f)
151#endif /* HAVE_iSNAND */
152
153#endif /* ! HAVE_iSNAN */
154#endif /* ! defined(isnan) */
155
156/**
157 * xmlXPathInit:
158 *
159 * Initialize the XPath environment
160 */
161void
162xmlXPathInit(void) {
163 static int initialized = 0;
164
165 if (initialized) return;
166
167 xmlXPathNAN = 0;
168 xmlXPathNAN /= 0;
169
170 xmlXPathPINF = 1;
171 xmlXPathPINF /= 0;
172
173 xmlXPathNINF = -1;
174 xmlXPathNINF /= 0;
175
176 initialized = 1;
177}
178
179/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000180 * *
181 * Parser Types *
182 * *
183 ************************************************************************/
184
185/*
186 * Types are private:
187 */
188
189typedef enum {
190 XPATH_OP_END=0,
191 XPATH_OP_AND,
192 XPATH_OP_OR,
193 XPATH_OP_EQUAL,
194 XPATH_OP_CMP,
195 XPATH_OP_PLUS,
196 XPATH_OP_MULT,
197 XPATH_OP_UNION,
198 XPATH_OP_ROOT,
199 XPATH_OP_NODE,
200 XPATH_OP_RESET,
201 XPATH_OP_COLLECT,
202 XPATH_OP_VALUE,
203 XPATH_OP_VARIABLE,
204 XPATH_OP_FUNCTION,
205 XPATH_OP_ARG,
206 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000207 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000208 XPATH_OP_SORT
209#ifdef LIBXML_XPTR_ENABLED
210 ,XPATH_OP_RANGETO
211#endif
212} xmlXPathOp;
213
214typedef enum {
215 AXIS_ANCESTOR = 1,
216 AXIS_ANCESTOR_OR_SELF,
217 AXIS_ATTRIBUTE,
218 AXIS_CHILD,
219 AXIS_DESCENDANT,
220 AXIS_DESCENDANT_OR_SELF,
221 AXIS_FOLLOWING,
222 AXIS_FOLLOWING_SIBLING,
223 AXIS_NAMESPACE,
224 AXIS_PARENT,
225 AXIS_PRECEDING,
226 AXIS_PRECEDING_SIBLING,
227 AXIS_SELF
228} xmlXPathAxisVal;
229
230typedef enum {
231 NODE_TEST_NONE = 0,
232 NODE_TEST_TYPE = 1,
233 NODE_TEST_PI = 2,
234 NODE_TEST_ALL = 3,
235 NODE_TEST_NS = 4,
236 NODE_TEST_NAME = 5
237} xmlXPathTestVal;
238
239typedef enum {
240 NODE_TYPE_NODE = 0,
241 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
242 NODE_TYPE_TEXT = XML_TEXT_NODE,
243 NODE_TYPE_PI = XML_PI_NODE
244} xmlXPathTypeVal;
245
246
247typedef struct _xmlXPathStepOp xmlXPathStepOp;
248typedef xmlXPathStepOp *xmlXPathStepOpPtr;
249struct _xmlXPathStepOp {
250 xmlXPathOp op;
251 int ch1;
252 int ch2;
253 int value;
254 int value2;
255 int value3;
256 void *value4;
257 void *value5;
258};
259
260struct _xmlXPathCompExpr {
261 int nbStep;
262 int maxStep;
263 xmlXPathStepOp *steps; /* ops for computation */
264 int last;
265};
266
267/************************************************************************
268 * *
269 * Parser Type functions *
270 * *
271 ************************************************************************/
272
273/**
274 * xmlXPathNewCompExpr:
275 *
276 * Create a new Xpath component
277 *
278 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
279 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000280static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000281xmlXPathNewCompExpr(void) {
282 xmlXPathCompExprPtr cur;
283
284 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
285 if (cur == NULL) {
286 xmlGenericError(xmlGenericErrorContext,
287 "xmlXPathNewCompExpr : malloc failed\n");
288 return(NULL);
289 }
290 memset(cur, 0, sizeof(xmlXPathCompExpr));
291 cur->maxStep = 10;
292 cur->nbStep = 0;
293 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
294 sizeof(xmlXPathStepOp));
295 if (cur->steps == NULL) {
296 xmlGenericError(xmlGenericErrorContext,
297 "xmlXPathNewCompExpr : malloc failed\n");
298 xmlFree(cur);
299 return(NULL);
300 }
301 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
302 cur->last = -1;
303 return(cur);
304}
305
306/**
307 * xmlXPathFreeCompExpr:
308 * @comp: an XPATH comp
309 *
310 * Free up the memory allocated by @comp
311 */
312void
313xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) {
314 xmlXPathStepOpPtr op;
315 int i;
316
317 if (comp == NULL)
318 return;
319 for (i = 0;i < comp->nbStep;i++) {
320 op = &comp->steps[i];
321 if (op->value4 != NULL) {
322 if (op->op == XPATH_OP_VALUE)
323 xmlXPathFreeObject(op->value4);
324 else
325 xmlFree(op->value4);
326 }
327 if (op->value5 != NULL)
328 xmlFree(op->value5);
329 }
330 if (comp->steps != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000331 xmlFree(comp->steps);
332 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000333 xmlFree(comp);
334}
335
336/**
337 * xmlXPathCompExprAdd:
338 * @comp: the compiled expression
339 * @ch1: first child index
340 * @ch2: second child index
341 * @op: an op
342 * @value: the first int value
343 * @value2: the second int value
344 * @value3: the third int value
345 * @value4: the first string value
346 * @value5: the second string value
347 *
348 * Add an step to an XPath Compiled Expression
349 *
350 * Returns -1 in case of failure, the index otherwise
351 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000352static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000353xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
354 xmlXPathOp op, int value,
355 int value2, int value3, void *value4, void *value5) {
356 if (comp->nbStep >= comp->maxStep) {
357 xmlXPathStepOp *real;
358
359 comp->maxStep *= 2;
360 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
361 comp->maxStep * sizeof(xmlXPathStepOp));
362 if (real == NULL) {
363 comp->maxStep /= 2;
364 xmlGenericError(xmlGenericErrorContext,
365 "xmlXPathCompExprAdd : realloc failed\n");
366 return(-1);
367 }
368 comp->steps = real;
369 }
370 comp->last = comp->nbStep;
371 comp->steps[comp->nbStep].ch1 = ch1;
372 comp->steps[comp->nbStep].ch2 = ch2;
373 comp->steps[comp->nbStep].op = op;
374 comp->steps[comp->nbStep].value = value;
375 comp->steps[comp->nbStep].value2 = value2;
376 comp->steps[comp->nbStep].value3 = value3;
377 comp->steps[comp->nbStep].value4 = value4;
378 comp->steps[comp->nbStep].value5 = value5;
379 return(comp->nbStep++);
380}
381
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000382#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
383 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
384 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000385#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
386 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
387 (op), (val), (val2), (val3), (val4), (val5))
388
389#define PUSH_LEAVE_EXPR(op, val, val2) \
390xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
391
392#define PUSH_UNARY_EXPR(op, ch, val, val2) \
393xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
394
395#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
396xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
397
398/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000399 * *
400 * Debugging related functions *
401 * *
402 ************************************************************************/
403
404#define TODO \
405 xmlGenericError(xmlGenericErrorContext, \
406 "Unimplemented block at %s:%d\n", \
407 __FILE__, __LINE__);
408
409#define STRANGE \
410 xmlGenericError(xmlGenericErrorContext, \
411 "Internal error at %s:%d\n", \
412 __FILE__, __LINE__);
413
414#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000415static void
416xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000417 int i;
418 char shift[100];
419
420 for (i = 0;((i < depth) && (i < 25));i++)
421 shift[2 * i] = shift[2 * i + 1] = ' ';
422 shift[2 * i] = shift[2 * i + 1] = 0;
423 if (cur == NULL) {
424 fprintf(output, shift);
425 fprintf(output, "Node is NULL !\n");
426 return;
427
428 }
429
430 if ((cur->type == XML_DOCUMENT_NODE) ||
431 (cur->type == XML_HTML_DOCUMENT_NODE)) {
432 fprintf(output, shift);
433 fprintf(output, " /\n");
434 } else if (cur->type == XML_ATTRIBUTE_NODE)
435 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
436 else
437 xmlDebugDumpOneNode(output, cur, depth);
438}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000439static void
440xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000441 xmlNodePtr tmp;
442 int i;
443 char shift[100];
444
445 for (i = 0;((i < depth) && (i < 25));i++)
446 shift[2 * i] = shift[2 * i + 1] = ' ';
447 shift[2 * i] = shift[2 * i + 1] = 0;
448 if (cur == NULL) {
449 fprintf(output, shift);
450 fprintf(output, "Node is NULL !\n");
451 return;
452
453 }
454
455 while (cur != NULL) {
456 tmp = cur;
457 cur = cur->next;
458 xmlDebugDumpOneNode(output, tmp, depth);
459 }
460}
Owen Taylor3473f882001-02-23 17:55:21 +0000461
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000462static void
463xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000464 int i;
465 char shift[100];
466
467 for (i = 0;((i < depth) && (i < 25));i++)
468 shift[2 * i] = shift[2 * i + 1] = ' ';
469 shift[2 * i] = shift[2 * i + 1] = 0;
470
471 if (cur == NULL) {
472 fprintf(output, shift);
473 fprintf(output, "NodeSet is NULL !\n");
474 return;
475
476 }
477
478 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
479 for (i = 0;i < cur->nodeNr;i++) {
480 fprintf(output, shift);
481 fprintf(output, "%d", i + 1);
482 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
483 }
484}
485
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000486static void
487xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000488 int i;
489 char shift[100];
490
491 for (i = 0;((i < depth) && (i < 25));i++)
492 shift[2 * i] = shift[2 * i + 1] = ' ';
493 shift[2 * i] = shift[2 * i + 1] = 0;
494
495 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
496 fprintf(output, shift);
497 fprintf(output, "Value Tree is NULL !\n");
498 return;
499
500 }
501
502 fprintf(output, shift);
503 fprintf(output, "%d", i + 1);
504 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
505}
Owen Taylor3473f882001-02-23 17:55:21 +0000506#if defined(LIBXML_XPTR_ENABLED)
507void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000508static void
509xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000510 int i;
511 char shift[100];
512
513 for (i = 0;((i < depth) && (i < 25));i++)
514 shift[2 * i] = shift[2 * i + 1] = ' ';
515 shift[2 * i] = shift[2 * i + 1] = 0;
516
517 if (cur == NULL) {
518 fprintf(output, shift);
519 fprintf(output, "LocationSet is NULL !\n");
520 return;
521
522 }
523
524 for (i = 0;i < cur->locNr;i++) {
525 fprintf(output, shift);
526 fprintf(output, "%d : ", i + 1);
527 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
528 }
529}
530#endif
531
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000532/**
533 * xmlXPathDebugDumpObject:
534 * @output: the FILE * to dump the output
535 * @cur: the object to inspect
536 * @depth: indentation level
537 *
538 * Dump the content of the object for debugging purposes
539 */
540void
541xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000542 int i;
543 char shift[100];
544
545 for (i = 0;((i < depth) && (i < 25));i++)
546 shift[2 * i] = shift[2 * i + 1] = ' ';
547 shift[2 * i] = shift[2 * i + 1] = 0;
548
549 fprintf(output, shift);
550
551 if (cur == NULL) {
552 fprintf(output, "Object is empty (NULL)\n");
553 return;
554 }
555 switch(cur->type) {
556 case XPATH_UNDEFINED:
557 fprintf(output, "Object is uninitialized\n");
558 break;
559 case XPATH_NODESET:
560 fprintf(output, "Object is a Node Set :\n");
561 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
562 break;
563 case XPATH_XSLT_TREE:
564 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000565 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000566 break;
567 case XPATH_BOOLEAN:
568 fprintf(output, "Object is a Boolean : ");
569 if (cur->boolval) fprintf(output, "true\n");
570 else fprintf(output, "false\n");
571 break;
572 case XPATH_NUMBER:
573 fprintf(output, "Object is a number : %0g\n", cur->floatval);
574 break;
575 case XPATH_STRING:
576 fprintf(output, "Object is a string : ");
577 xmlDebugDumpString(output, cur->stringval);
578 fprintf(output, "\n");
579 break;
580 case XPATH_POINT:
581 fprintf(output, "Object is a point : index %d in node", cur->index);
582 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
583 fprintf(output, "\n");
584 break;
585 case XPATH_RANGE:
586 if ((cur->user2 == NULL) ||
587 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
588 fprintf(output, "Object is a collapsed range :\n");
589 fprintf(output, shift);
590 if (cur->index >= 0)
591 fprintf(output, "index %d in ", cur->index);
592 fprintf(output, "node\n");
593 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
594 depth + 1);
595 } else {
596 fprintf(output, "Object is a range :\n");
597 fprintf(output, shift);
598 fprintf(output, "From ");
599 if (cur->index >= 0)
600 fprintf(output, "index %d in ", cur->index);
601 fprintf(output, "node\n");
602 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
603 depth + 1);
604 fprintf(output, shift);
605 fprintf(output, "To ");
606 if (cur->index2 >= 0)
607 fprintf(output, "index %d in ", cur->index2);
608 fprintf(output, "node\n");
609 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
610 depth + 1);
611 fprintf(output, "\n");
612 }
613 break;
614 case XPATH_LOCATIONSET:
615#if defined(LIBXML_XPTR_ENABLED)
616 fprintf(output, "Object is a Location Set:\n");
617 xmlXPathDebugDumpLocationSet(output,
618 (xmlLocationSetPtr) cur->user, depth);
619#endif
620 break;
621 case XPATH_USERS:
622 fprintf(output, "Object is user defined\n");
623 break;
624 }
625}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000626
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000627static void
628xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000629 xmlXPathStepOpPtr op, int depth) {
630 int i;
631 char shift[100];
632
633 for (i = 0;((i < depth) && (i < 25));i++)
634 shift[2 * i] = shift[2 * i + 1] = ' ';
635 shift[2 * i] = shift[2 * i + 1] = 0;
636
637 fprintf(output, shift);
638 if (op == NULL) {
639 fprintf(output, "Step is NULL\n");
640 return;
641 }
642 switch (op->op) {
643 case XPATH_OP_END:
644 fprintf(output, "END"); break;
645 case XPATH_OP_AND:
646 fprintf(output, "AND"); break;
647 case XPATH_OP_OR:
648 fprintf(output, "OR"); break;
649 case XPATH_OP_EQUAL:
650 if (op->value)
651 fprintf(output, "EQUAL =");
652 else
653 fprintf(output, "EQUAL !=");
654 break;
655 case XPATH_OP_CMP:
656 if (op->value)
657 fprintf(output, "CMP <");
658 else
659 fprintf(output, "CMP >");
660 if (!op->value2)
661 fprintf(output, "=");
662 break;
663 case XPATH_OP_PLUS:
664 if (op->value == 0)
665 fprintf(output, "PLUS -");
666 else if (op->value == 1)
667 fprintf(output, "PLUS +");
668 else if (op->value == 2)
669 fprintf(output, "PLUS unary -");
670 else if (op->value == 3)
671 fprintf(output, "PLUS unary - -");
672 break;
673 case XPATH_OP_MULT:
674 if (op->value == 0)
675 fprintf(output, "MULT *");
676 else if (op->value == 1)
677 fprintf(output, "MULT div");
678 else
679 fprintf(output, "MULT mod");
680 break;
681 case XPATH_OP_UNION:
682 fprintf(output, "UNION"); break;
683 case XPATH_OP_ROOT:
684 fprintf(output, "ROOT"); break;
685 case XPATH_OP_NODE:
686 fprintf(output, "NODE"); break;
687 case XPATH_OP_RESET:
688 fprintf(output, "RESET"); break;
689 case XPATH_OP_SORT:
690 fprintf(output, "SORT"); break;
691 case XPATH_OP_COLLECT: {
692 xmlXPathAxisVal axis = op->value;
693 xmlXPathTestVal test = op->value2;
694 xmlXPathTypeVal type = op->value3;
695 const xmlChar *prefix = op->value4;
696 const xmlChar *name = op->value5;
697
698 fprintf(output, "COLLECT ");
699 switch (axis) {
700 case AXIS_ANCESTOR:
701 fprintf(output, " 'ancestors' "); break;
702 case AXIS_ANCESTOR_OR_SELF:
703 fprintf(output, " 'ancestors-or-self' "); break;
704 case AXIS_ATTRIBUTE:
705 fprintf(output, " 'attributes' "); break;
706 case AXIS_CHILD:
707 fprintf(output, " 'child' "); break;
708 case AXIS_DESCENDANT:
709 fprintf(output, " 'descendant' "); break;
710 case AXIS_DESCENDANT_OR_SELF:
711 fprintf(output, " 'descendant-or-self' "); break;
712 case AXIS_FOLLOWING:
713 fprintf(output, " 'following' "); break;
714 case AXIS_FOLLOWING_SIBLING:
715 fprintf(output, " 'following-siblings' "); break;
716 case AXIS_NAMESPACE:
717 fprintf(output, " 'namespace' "); break;
718 case AXIS_PARENT:
719 fprintf(output, " 'parent' "); break;
720 case AXIS_PRECEDING:
721 fprintf(output, " 'preceding' "); break;
722 case AXIS_PRECEDING_SIBLING:
723 fprintf(output, " 'preceding-sibling' "); break;
724 case AXIS_SELF:
725 fprintf(output, " 'self' "); break;
726 }
727 switch (test) {
728 case NODE_TEST_NONE:
729 fprintf(output, "'none' "); break;
730 case NODE_TEST_TYPE:
731 fprintf(output, "'type' "); break;
732 case NODE_TEST_PI:
733 fprintf(output, "'PI' "); break;
734 case NODE_TEST_ALL:
735 fprintf(output, "'all' "); break;
736 case NODE_TEST_NS:
737 fprintf(output, "'namespace' "); break;
738 case NODE_TEST_NAME:
739 fprintf(output, "'name' "); break;
740 }
741 switch (type) {
742 case NODE_TYPE_NODE:
743 fprintf(output, "'node' "); break;
744 case NODE_TYPE_COMMENT:
745 fprintf(output, "'comment' "); break;
746 case NODE_TYPE_TEXT:
747 fprintf(output, "'text' "); break;
748 case NODE_TYPE_PI:
749 fprintf(output, "'PI' "); break;
750 }
751 if (prefix != NULL)
752 fprintf(output, "%s:", prefix);
753 if (name != NULL)
754 fprintf(output, "%s", name);
755 break;
756
757 }
758 case XPATH_OP_VALUE: {
759 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
760
761 fprintf(output, "ELEM ");
762 xmlXPathDebugDumpObject(output, object, 0);
763 goto finish;
764 }
765 case XPATH_OP_VARIABLE: {
766 const xmlChar *prefix = op->value5;
767 const xmlChar *name = op->value4;
768
769 if (prefix != NULL)
770 fprintf(output, "VARIABLE %s:%s", prefix, name);
771 else
772 fprintf(output, "VARIABLE %s", name);
773 break;
774 }
775 case XPATH_OP_FUNCTION: {
776 int nbargs = op->value;
777 const xmlChar *prefix = op->value5;
778 const xmlChar *name = op->value4;
779
780 if (prefix != NULL)
781 fprintf(output, "FUNCTION %s:%s(%d args)",
782 prefix, name, nbargs);
783 else
784 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
785 break;
786 }
787 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
788 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000789 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000790 default:
791 fprintf(output, "UNKNOWN %d\n", op->op); return;
792 }
793 fprintf(output, "\n");
794finish:
795 if (op->ch1 >= 0)
796 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
797 if (op->ch2 >= 0)
798 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
799}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000800
801void
802xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
803 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000804 int i;
805 char shift[100];
806
807 for (i = 0;((i < depth) && (i < 25));i++)
808 shift[2 * i] = shift[2 * i + 1] = ' ';
809 shift[2 * i] = shift[2 * i + 1] = 0;
810
811 fprintf(output, shift);
812
813 if (comp == NULL) {
814 fprintf(output, "Compiled Expression is NULL\n");
815 return;
816 }
817 fprintf(output, "Compiled Expression : %d elements\n",
818 comp->nbStep);
819 i = comp->last;
820 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
821}
Owen Taylor3473f882001-02-23 17:55:21 +0000822#endif
823
824/************************************************************************
825 * *
826 * Parser stacks related functions and macros *
827 * *
828 ************************************************************************/
829
830/*
831 * Generic function for accessing stacks in the Parser Context
832 */
833
834#define PUSH_AND_POP(type, name) \
835extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
836 if (ctxt->name##Nr >= ctxt->name##Max) { \
837 ctxt->name##Max *= 2; \
838 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
839 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
840 if (ctxt->name##Tab == NULL) { \
841 xmlGenericError(xmlGenericErrorContext, \
842 "realloc failed !\n"); \
843 return(0); \
844 } \
845 } \
846 ctxt->name##Tab[ctxt->name##Nr] = value; \
847 ctxt->name = value; \
848 return(ctxt->name##Nr++); \
849} \
850extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
851 type ret; \
852 if (ctxt->name##Nr <= 0) return(0); \
853 ctxt->name##Nr--; \
854 if (ctxt->name##Nr > 0) \
855 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
856 else \
857 ctxt->name = NULL; \
858 ret = ctxt->name##Tab[ctxt->name##Nr]; \
859 ctxt->name##Tab[ctxt->name##Nr] = 0; \
860 return(ret); \
861} \
862
863PUSH_AND_POP(xmlXPathObjectPtr, value)
864
865/*
866 * Macros for accessing the content. Those should be used only by the parser,
867 * and not exported.
868 *
869 * Dirty macros, i.e. one need to make assumption on the context to use them
870 *
871 * CUR_PTR return the current pointer to the xmlChar to be parsed.
872 * CUR returns the current xmlChar value, i.e. a 8 bit value
873 * in ISO-Latin or UTF-8.
874 * This should be used internally by the parser
875 * only to compare to ASCII values otherwise it would break when
876 * running with UTF-8 encoding.
877 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
878 * to compare on ASCII based substring.
879 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
880 * strings within the parser.
881 * CURRENT Returns the current char value, with the full decoding of
882 * UTF-8 if we are using this mode. It returns an int.
883 * NEXT Skip to the next character, this does the proper decoding
884 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
885 * It returns the pointer to the current xmlChar.
886 */
887
888#define CUR (*ctxt->cur)
889#define SKIP(val) ctxt->cur += (val)
890#define NXT(val) ctxt->cur[(val)]
891#define CUR_PTR ctxt->cur
892
893#define SKIP_BLANKS \
894 while (IS_BLANK(*(ctxt->cur))) NEXT
895
896#define CURRENT (*ctxt->cur)
897#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
898
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000899
900#ifndef DBL_DIG
901#define DBL_DIG 16
902#endif
903#ifndef DBL_EPSILON
904#define DBL_EPSILON 1E-9
905#endif
906
907#define UPPER_DOUBLE 1E9
908#define LOWER_DOUBLE 1E-5
909
910#define INTEGER_DIGITS DBL_DIG
911#define FRACTION_DIGITS (DBL_DIG + 1)
912#define EXPONENT_DIGITS (3 + 2)
913
914/**
915 * xmlXPathFormatNumber:
916 * @number: number to format
917 * @buffer: output buffer
918 * @buffersize: size of output buffer
919 *
920 * Convert the number into a string representation.
921 */
922static void
923xmlXPathFormatNumber(double number, char buffer[], int buffersize)
924{
925 switch (isinf(number)) {
926 case 1:
927 if (buffersize > (int)sizeof("+Infinity"))
928 sprintf(buffer, "+Infinity");
929 break;
930 case -1:
931 if (buffersize > (int)sizeof("-Infinity"))
932 sprintf(buffer, "-Infinity");
933 break;
934 default:
935 if (isnan(number)) {
936 if (buffersize > (int)sizeof("NaN"))
937 sprintf(buffer, "NaN");
938 } else {
939 char work[INTEGER_DIGITS + FRACTION_DIGITS + EXPONENT_DIGITS + 1];
940 char *pointer;
941 char *start;
942 int i;
943 int digits;
944 int is_negative;
945 int use_scientific;
946 int exponent;
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000947 int indx;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000948 int count;
949 double n;
950
951 i = digits = 0;
952 is_negative = (number < 0.0);
953 if (is_negative)
954 number = -number;
955
956 /* Scale number */
957 n = log10(number);
958 exponent = (isinf(n) == -1) ? 0 : (int)n;
959 use_scientific = (((number <= LOWER_DOUBLE) ||
960 (number > UPPER_DOUBLE)) &&
961 (number != 0));
962 if (use_scientific) {
963 number /= pow(10.0, (double)exponent);
964 while (number < 1.0) {
965 number *= 10.0;
966 exponent--;
967 }
968 }
969
970 /* Integer part is build from back */
971 pointer = &work[INTEGER_DIGITS + 1];
972 if (number < 1.0) {
973 *(--pointer) = '0';
974 digits++;
975 } else {
976 n = number;
977 for (i = 1; i < INTEGER_DIGITS - 1; i++) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000978 indx = (int)n % 10;
979 *(--pointer) = "0123456789"[indx];
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000980 n /= 10.0;
981 if (n < 1.0)
982 break;
983 }
984 digits += i;
985 }
986 if (is_negative) {
987 *(--pointer) = '-';
988 digits++;
989 }
990 start = pointer;
991
992 /* Fraction part is build from front */
993 i = 0;
994 pointer = &work[INTEGER_DIGITS + 1];
995 if (number - floor(number) > DBL_EPSILON) {
996 *(pointer++) = '.';
997 i++;
998 n = number;
999 count = 0;
1000 while (i < FRACTION_DIGITS) {
1001 n -= floor(n);
1002 n *= 10.0;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001003 indx = (int)n % 10;
1004 *(pointer++) = "0123456789"[indx];
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001005 i++;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001006 if ((indx != 0) || (count > 0))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001007 count++;
1008 if ((n > 10.0) || (count > FRACTION_DIGITS / 2))
1009 break;
1010 }
1011 }
1012 /* Remove trailing zeroes */
1013 while ((pointer[-1] == '0') && (i > 0)) {
1014 pointer--;
1015 i--;
1016 }
1017 digits += i;
1018
1019 if (use_scientific) {
1020 *(pointer++) = 'e';
1021 digits++;
1022 if (exponent < 0) {
1023 *(pointer++) = '-';
1024 exponent = -exponent;
1025 } else {
1026 *(pointer++) = '+';
1027 }
1028 digits++;
1029 if (exponent >= 100)
1030 pointer += 2;
1031 else if (exponent >= 10)
1032 pointer += 1;
1033 while (exponent >= 1) {
1034 *(pointer--) = "0123456789"[exponent % 10];
1035 exponent /= 10;
1036 digits++;
1037 }
1038 }
1039
1040 if (digits >= buffersize)
1041 digits = buffersize - 1;
1042
1043 memcpy(buffer, start, digits);
1044 buffer[digits] = 0;
1045 }
1046 break;
1047 }
1048}
1049
Owen Taylor3473f882001-02-23 17:55:21 +00001050/************************************************************************
1051 * *
1052 * Error handling routines *
1053 * *
1054 ************************************************************************/
1055
1056
1057const char *xmlXPathErrorMessages[] = {
1058 "Ok",
1059 "Number encoding",
1060 "Unfinished litteral",
1061 "Start of litteral",
1062 "Expected $ for variable reference",
1063 "Undefined variable",
1064 "Invalid predicate",
1065 "Invalid expression",
1066 "Missing closing curly brace",
1067 "Unregistered function",
1068 "Invalid operand",
1069 "Invalid type",
1070 "Invalid number of arguments",
1071 "Invalid context size",
1072 "Invalid context position",
1073 "Memory allocation error",
1074 "Syntax error",
1075 "Resource error",
1076 "Sub resource error",
1077 "Undefined namespace prefix"
1078};
1079
1080/**
1081 * xmlXPathError:
1082 * @ctxt: the XPath Parser context
1083 * @file: the file name
1084 * @line: the line number
1085 * @no: the error number
1086 *
1087 * Create a new xmlNodeSetPtr of type double and of value @val
1088 *
1089 * Returns the newly created object.
1090 */
1091void
1092xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1093 int line, int no) {
1094 int n;
1095 const xmlChar *cur;
1096 const xmlChar *base;
1097
1098 xmlGenericError(xmlGenericErrorContext,
1099 "Error %s:%d: %s\n", file, line,
1100 xmlXPathErrorMessages[no]);
1101
1102 cur = ctxt->cur;
1103 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001104 if ((cur == NULL) || (base == NULL))
1105 return;
1106
Owen Taylor3473f882001-02-23 17:55:21 +00001107 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1108 cur--;
1109 }
1110 n = 0;
1111 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1112 cur--;
1113 if ((*cur == '\n') || (*cur == '\r')) cur++;
1114 base = cur;
1115 n = 0;
1116 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1117 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1118 n++;
1119 }
1120 xmlGenericError(xmlGenericErrorContext, "\n");
1121 cur = ctxt->cur;
1122 while ((*cur == '\n') || (*cur == '\r'))
1123 cur--;
1124 n = 0;
1125 while ((cur != base) && (n++ < 80)) {
1126 xmlGenericError(xmlGenericErrorContext, " ");
1127 base++;
1128 }
1129 xmlGenericError(xmlGenericErrorContext,"^\n");
1130}
1131
1132
1133/************************************************************************
1134 * *
1135 * Routines to handle NodeSets *
1136 * *
1137 ************************************************************************/
1138
1139/**
1140 * xmlXPathCmpNodes:
1141 * @node1: the first node
1142 * @node2: the second node
1143 *
1144 * Compare two nodes w.r.t document order
1145 *
1146 * Returns -2 in case of error 1 if first point < second point, 0 if
1147 * that's the same node, -1 otherwise
1148 */
1149int
1150xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1151 int depth1, depth2;
1152 xmlNodePtr cur, root;
1153
1154 if ((node1 == NULL) || (node2 == NULL))
1155 return(-2);
1156 /*
1157 * a couple of optimizations which will avoid computations in most cases
1158 */
1159 if (node1 == node2)
1160 return(0);
1161 if (node1 == node2->prev)
1162 return(1);
1163 if (node1 == node2->next)
1164 return(-1);
1165
1166 /*
1167 * compute depth to root
1168 */
1169 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1170 if (cur == node1)
1171 return(1);
1172 depth2++;
1173 }
1174 root = cur;
1175 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1176 if (cur == node2)
1177 return(-1);
1178 depth1++;
1179 }
1180 /*
1181 * Distinct document (or distinct entities :-( ) case.
1182 */
1183 if (root != cur) {
1184 return(-2);
1185 }
1186 /*
1187 * get the nearest common ancestor.
1188 */
1189 while (depth1 > depth2) {
1190 depth1--;
1191 node1 = node1->parent;
1192 }
1193 while (depth2 > depth1) {
1194 depth2--;
1195 node2 = node2->parent;
1196 }
1197 while (node1->parent != node2->parent) {
1198 node1 = node1->parent;
1199 node2 = node2->parent;
1200 /* should not happen but just in case ... */
1201 if ((node1 == NULL) || (node2 == NULL))
1202 return(-2);
1203 }
1204 /*
1205 * Find who's first.
1206 */
1207 if (node1 == node2->next)
1208 return(-1);
1209 for (cur = node1->next;cur != NULL;cur = cur->next)
1210 if (cur == node2)
1211 return(1);
1212 return(-1); /* assume there is no sibling list corruption */
1213}
1214
1215/**
1216 * xmlXPathNodeSetSort:
1217 * @set: the node set
1218 *
1219 * Sort the node set in document order
1220 */
1221void
1222xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001223 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001224 xmlNodePtr tmp;
1225
1226 if (set == NULL)
1227 return;
1228
1229 /* Use Shell's sort to sort the node-set */
1230 len = set->nodeNr;
1231 for (incr = len / 2; incr > 0; incr /= 2) {
1232 for (i = incr; i < len; i++) {
1233 j = i - incr;
1234 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001235 if (xmlXPathCmpNodes(set->nodeTab[j],
1236 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001237 tmp = set->nodeTab[j];
1238 set->nodeTab[j] = set->nodeTab[j + incr];
1239 set->nodeTab[j + incr] = tmp;
1240 j -= incr;
1241 } else
1242 break;
1243 }
1244 }
1245 }
1246}
1247
1248#define XML_NODESET_DEFAULT 10
1249/**
1250 * xmlXPathNodeSetCreate:
1251 * @val: an initial xmlNodePtr, or NULL
1252 *
1253 * Create a new xmlNodeSetPtr of type double and of value @val
1254 *
1255 * Returns the newly created object.
1256 */
1257xmlNodeSetPtr
1258xmlXPathNodeSetCreate(xmlNodePtr val) {
1259 xmlNodeSetPtr ret;
1260
1261 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1262 if (ret == NULL) {
1263 xmlGenericError(xmlGenericErrorContext,
1264 "xmlXPathNewNodeSet: out of memory\n");
1265 return(NULL);
1266 }
1267 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1268 if (val != NULL) {
1269 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1270 sizeof(xmlNodePtr));
1271 if (ret->nodeTab == NULL) {
1272 xmlGenericError(xmlGenericErrorContext,
1273 "xmlXPathNewNodeSet: out of memory\n");
1274 return(NULL);
1275 }
1276 memset(ret->nodeTab, 0 ,
1277 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1278 ret->nodeMax = XML_NODESET_DEFAULT;
1279 ret->nodeTab[ret->nodeNr++] = val;
1280 }
1281 return(ret);
1282}
1283
1284/**
1285 * xmlXPathNodeSetAdd:
1286 * @cur: the initial node set
1287 * @val: a new xmlNodePtr
1288 *
1289 * add a new xmlNodePtr ot an existing NodeSet
1290 */
1291void
1292xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1293 int i;
1294
1295 if (val == NULL) return;
1296
1297 /*
1298 * check against doublons
1299 */
1300 for (i = 0;i < cur->nodeNr;i++)
1301 if (cur->nodeTab[i] == val) return;
1302
1303 /*
1304 * grow the nodeTab if needed
1305 */
1306 if (cur->nodeMax == 0) {
1307 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1308 sizeof(xmlNodePtr));
1309 if (cur->nodeTab == NULL) {
1310 xmlGenericError(xmlGenericErrorContext,
1311 "xmlXPathNodeSetAdd: out of memory\n");
1312 return;
1313 }
1314 memset(cur->nodeTab, 0 ,
1315 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1316 cur->nodeMax = XML_NODESET_DEFAULT;
1317 } else if (cur->nodeNr == cur->nodeMax) {
1318 xmlNodePtr *temp;
1319
1320 cur->nodeMax *= 2;
1321 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1322 sizeof(xmlNodePtr));
1323 if (temp == NULL) {
1324 xmlGenericError(xmlGenericErrorContext,
1325 "xmlXPathNodeSetAdd: out of memory\n");
1326 return;
1327 }
1328 cur->nodeTab = temp;
1329 }
1330 cur->nodeTab[cur->nodeNr++] = val;
1331}
1332
1333/**
1334 * xmlXPathNodeSetAddUnique:
1335 * @cur: the initial node set
1336 * @val: a new xmlNodePtr
1337 *
1338 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1339 * when we are sure the node is not already in the set.
1340 */
1341void
1342xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1343 if (val == NULL) return;
1344
1345 /*
1346 * grow the nodeTab if needed
1347 */
1348 if (cur->nodeMax == 0) {
1349 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1350 sizeof(xmlNodePtr));
1351 if (cur->nodeTab == NULL) {
1352 xmlGenericError(xmlGenericErrorContext,
1353 "xmlXPathNodeSetAddUnique: out of memory\n");
1354 return;
1355 }
1356 memset(cur->nodeTab, 0 ,
1357 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1358 cur->nodeMax = XML_NODESET_DEFAULT;
1359 } else if (cur->nodeNr == cur->nodeMax) {
1360 xmlNodePtr *temp;
1361
1362 cur->nodeMax *= 2;
1363 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1364 sizeof(xmlNodePtr));
1365 if (temp == NULL) {
1366 xmlGenericError(xmlGenericErrorContext,
1367 "xmlXPathNodeSetAddUnique: out of memory\n");
1368 return;
1369 }
1370 cur->nodeTab = temp;
1371 }
1372 cur->nodeTab[cur->nodeNr++] = val;
1373}
1374
1375/**
1376 * xmlXPathNodeSetMerge:
1377 * @val1: the first NodeSet or NULL
1378 * @val2: the second NodeSet
1379 *
1380 * Merges two nodesets, all nodes from @val2 are added to @val1
1381 * if @val1 is NULL, a new set is created and copied from @val2
1382 *
1383 * Returns val1 once extended or NULL in case of error.
1384 */
1385xmlNodeSetPtr
1386xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001387 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001388
1389 if (val2 == NULL) return(val1);
1390 if (val1 == NULL) {
1391 val1 = xmlXPathNodeSetCreate(NULL);
1392 }
1393
1394 initNr = val1->nodeNr;
1395
1396 for (i = 0;i < val2->nodeNr;i++) {
1397 /*
1398 * check against doublons
1399 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001400 skip = 0;
1401 for (j = 0; j < initNr; j++) {
1402 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1403 skip = 1;
1404 break;
1405 }
1406 }
1407 if (skip)
1408 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001409
1410 /*
1411 * grow the nodeTab if needed
1412 */
1413 if (val1->nodeMax == 0) {
1414 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1415 sizeof(xmlNodePtr));
1416 if (val1->nodeTab == NULL) {
1417 xmlGenericError(xmlGenericErrorContext,
1418 "xmlXPathNodeSetMerge: out of memory\n");
1419 return(NULL);
1420 }
1421 memset(val1->nodeTab, 0 ,
1422 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1423 val1->nodeMax = XML_NODESET_DEFAULT;
1424 } else if (val1->nodeNr == val1->nodeMax) {
1425 xmlNodePtr *temp;
1426
1427 val1->nodeMax *= 2;
1428 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1429 sizeof(xmlNodePtr));
1430 if (temp == NULL) {
1431 xmlGenericError(xmlGenericErrorContext,
1432 "xmlXPathNodeSetMerge: out of memory\n");
1433 return(NULL);
1434 }
1435 val1->nodeTab = temp;
1436 }
1437 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1438 }
1439
1440 return(val1);
1441}
1442
1443/**
1444 * xmlXPathNodeSetDel:
1445 * @cur: the initial node set
1446 * @val: an xmlNodePtr
1447 *
1448 * Removes an xmlNodePtr from an existing NodeSet
1449 */
1450void
1451xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1452 int i;
1453
1454 if (cur == NULL) return;
1455 if (val == NULL) return;
1456
1457 /*
1458 * check against doublons
1459 */
1460 for (i = 0;i < cur->nodeNr;i++)
1461 if (cur->nodeTab[i] == val) break;
1462
1463 if (i >= cur->nodeNr) {
1464#ifdef DEBUG
1465 xmlGenericError(xmlGenericErrorContext,
1466 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1467 val->name);
1468#endif
1469 return;
1470 }
1471 cur->nodeNr--;
1472 for (;i < cur->nodeNr;i++)
1473 cur->nodeTab[i] = cur->nodeTab[i + 1];
1474 cur->nodeTab[cur->nodeNr] = NULL;
1475}
1476
1477/**
1478 * xmlXPathNodeSetRemove:
1479 * @cur: the initial node set
1480 * @val: the index to remove
1481 *
1482 * Removes an entry from an existing NodeSet list.
1483 */
1484void
1485xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1486 if (cur == NULL) return;
1487 if (val >= cur->nodeNr) return;
1488 cur->nodeNr--;
1489 for (;val < cur->nodeNr;val++)
1490 cur->nodeTab[val] = cur->nodeTab[val + 1];
1491 cur->nodeTab[cur->nodeNr] = NULL;
1492}
1493
1494/**
1495 * xmlXPathFreeNodeSet:
1496 * @obj: the xmlNodeSetPtr to free
1497 *
1498 * Free the NodeSet compound (not the actual nodes !).
1499 */
1500void
1501xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1502 if (obj == NULL) return;
1503 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001504 xmlFree(obj->nodeTab);
1505 }
Owen Taylor3473f882001-02-23 17:55:21 +00001506 xmlFree(obj);
1507}
1508
1509/**
1510 * xmlXPathFreeValueTree:
1511 * @obj: the xmlNodeSetPtr to free
1512 *
1513 * Free the NodeSet compound and the actual tree, this is different
1514 * from xmlXPathFreeNodeSet()
1515 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001516static void
Owen Taylor3473f882001-02-23 17:55:21 +00001517xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1518 int i;
1519
1520 if (obj == NULL) return;
1521 for (i = 0;i < obj->nodeNr;i++)
1522 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001523 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001524
1525 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001526 xmlFree(obj->nodeTab);
1527 }
Owen Taylor3473f882001-02-23 17:55:21 +00001528 xmlFree(obj);
1529}
1530
1531#if defined(DEBUG) || defined(DEBUG_STEP)
1532/**
1533 * xmlGenericErrorContextNodeSet:
1534 * @output: a FILE * for the output
1535 * @obj: the xmlNodeSetPtr to free
1536 *
1537 * Quick display of a NodeSet
1538 */
1539void
1540xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1541 int i;
1542
1543 if (output == NULL) output = xmlGenericErrorContext;
1544 if (obj == NULL) {
1545 fprintf(output, "NodeSet == NULL !\n");
1546 return;
1547 }
1548 if (obj->nodeNr == 0) {
1549 fprintf(output, "NodeSet is empty\n");
1550 return;
1551 }
1552 if (obj->nodeTab == NULL) {
1553 fprintf(output, " nodeTab == NULL !\n");
1554 return;
1555 }
1556 for (i = 0; i < obj->nodeNr; i++) {
1557 if (obj->nodeTab[i] == NULL) {
1558 fprintf(output, " NULL !\n");
1559 return;
1560 }
1561 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1562 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1563 fprintf(output, " /");
1564 else if (obj->nodeTab[i]->name == NULL)
1565 fprintf(output, " noname!");
1566 else fprintf(output, " %s", obj->nodeTab[i]->name);
1567 }
1568 fprintf(output, "\n");
1569}
1570#endif
1571
1572/**
1573 * xmlXPathNewNodeSet:
1574 * @val: the NodePtr value
1575 *
1576 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1577 * it with the single Node @val
1578 *
1579 * Returns the newly created object.
1580 */
1581xmlXPathObjectPtr
1582xmlXPathNewNodeSet(xmlNodePtr val) {
1583 xmlXPathObjectPtr ret;
1584
1585 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1586 if (ret == NULL) {
1587 xmlGenericError(xmlGenericErrorContext,
1588 "xmlXPathNewNodeSet: out of memory\n");
1589 return(NULL);
1590 }
1591 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1592 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001593 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001594 ret->nodesetval = xmlXPathNodeSetCreate(val);
1595 return(ret);
1596}
1597
1598/**
1599 * xmlXPathNewValueTree:
1600 * @val: the NodePtr value
1601 *
1602 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1603 * it with the tree root @val
1604 *
1605 * Returns the newly created object.
1606 */
1607xmlXPathObjectPtr
1608xmlXPathNewValueTree(xmlNodePtr val) {
1609 xmlXPathObjectPtr ret;
1610
1611 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1612 if (ret == NULL) {
1613 xmlGenericError(xmlGenericErrorContext,
1614 "xmlXPathNewNodeSet: out of memory\n");
1615 return(NULL);
1616 }
1617 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1618 ret->type = XPATH_XSLT_TREE;
1619 ret->nodesetval = xmlXPathNodeSetCreate(val);
1620 return(ret);
1621}
1622
1623/**
1624 * xmlXPathNewNodeSetList:
1625 * @val: an existing NodeSet
1626 *
1627 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1628 * it with the Nodeset @val
1629 *
1630 * Returns the newly created object.
1631 */
1632xmlXPathObjectPtr
1633xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1634 xmlXPathObjectPtr ret;
1635 int i;
1636
1637 if (val == NULL)
1638 ret = NULL;
1639 else if (val->nodeTab == NULL)
1640 ret = xmlXPathNewNodeSet(NULL);
1641 else
1642 {
1643 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1644 for (i = 1; i < val->nodeNr; ++i)
1645 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1646 }
1647
1648 return(ret);
1649}
1650
1651/**
1652 * xmlXPathWrapNodeSet:
1653 * @val: the NodePtr value
1654 *
1655 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1656 *
1657 * Returns the newly created object.
1658 */
1659xmlXPathObjectPtr
1660xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1661 xmlXPathObjectPtr ret;
1662
1663 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1664 if (ret == NULL) {
1665 xmlGenericError(xmlGenericErrorContext,
1666 "xmlXPathWrapNodeSet: out of memory\n");
1667 return(NULL);
1668 }
1669 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1670 ret->type = XPATH_NODESET;
1671 ret->nodesetval = val;
1672 return(ret);
1673}
1674
1675/**
1676 * xmlXPathFreeNodeSetList:
1677 * @obj: an existing NodeSetList object
1678 *
1679 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1680 * the list contrary to xmlXPathFreeObject().
1681 */
1682void
1683xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1684 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001685 xmlFree(obj);
1686}
1687
1688/************************************************************************
1689 * *
1690 * Routines to handle extra functions *
1691 * *
1692 ************************************************************************/
1693
1694/**
1695 * xmlXPathRegisterFunc:
1696 * @ctxt: the XPath context
1697 * @name: the function name
1698 * @f: the function implementation or NULL
1699 *
1700 * Register a new function. If @f is NULL it unregisters the function
1701 *
1702 * Returns 0 in case of success, -1 in case of error
1703 */
1704int
1705xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1706 xmlXPathFunction f) {
1707 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1708}
1709
1710/**
1711 * xmlXPathRegisterFuncNS:
1712 * @ctxt: the XPath context
1713 * @name: the function name
1714 * @ns_uri: the function namespace URI
1715 * @f: the function implementation or NULL
1716 *
1717 * Register a new function. If @f is NULL it unregisters the function
1718 *
1719 * Returns 0 in case of success, -1 in case of error
1720 */
1721int
1722xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1723 const xmlChar *ns_uri, xmlXPathFunction f) {
1724 if (ctxt == NULL)
1725 return(-1);
1726 if (name == NULL)
1727 return(-1);
1728
1729 if (ctxt->funcHash == NULL)
1730 ctxt->funcHash = xmlHashCreate(0);
1731 if (ctxt->funcHash == NULL)
1732 return(-1);
1733 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1734}
1735
1736/**
1737 * xmlXPathFunctionLookup:
1738 * @ctxt: the XPath context
1739 * @name: the function name
1740 *
1741 * Search in the Function array of the context for the given
1742 * function.
1743 *
1744 * Returns the xmlXPathFunction or NULL if not found
1745 */
1746xmlXPathFunction
1747xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1748 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1749}
1750
1751/**
1752 * xmlXPathFunctionLookupNS:
1753 * @ctxt: the XPath context
1754 * @name: the function name
1755 * @ns_uri: the function namespace URI
1756 *
1757 * Search in the Function array of the context for the given
1758 * function.
1759 *
1760 * Returns the xmlXPathFunction or NULL if not found
1761 */
1762xmlXPathFunction
1763xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1764 const xmlChar *ns_uri) {
1765 if (ctxt == NULL)
1766 return(NULL);
1767 if (ctxt->funcHash == NULL)
1768 return(NULL);
1769 if (name == NULL)
1770 return(NULL);
1771
1772 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1773}
1774
1775/**
1776 * xmlXPathRegisteredFuncsCleanup:
1777 * @ctxt: the XPath context
1778 *
1779 * Cleanup the XPath context data associated to registered functions
1780 */
1781void
1782xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1783 if (ctxt == NULL)
1784 return;
1785
1786 xmlHashFree(ctxt->funcHash, NULL);
1787 ctxt->funcHash = NULL;
1788}
1789
1790/************************************************************************
1791 * *
1792 * Routines to handle Variable *
1793 * *
1794 ************************************************************************/
1795
1796/**
1797 * xmlXPathRegisterVariable:
1798 * @ctxt: the XPath context
1799 * @name: the variable name
1800 * @value: the variable value or NULL
1801 *
1802 * Register a new variable value. If @value is NULL it unregisters
1803 * the variable
1804 *
1805 * Returns 0 in case of success, -1 in case of error
1806 */
1807int
1808xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1809 xmlXPathObjectPtr value) {
1810 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1811}
1812
1813/**
1814 * xmlXPathRegisterVariableNS:
1815 * @ctxt: the XPath context
1816 * @name: the variable name
1817 * @ns_uri: the variable namespace URI
1818 * @value: the variable value or NULL
1819 *
1820 * Register a new variable value. If @value is NULL it unregisters
1821 * the variable
1822 *
1823 * Returns 0 in case of success, -1 in case of error
1824 */
1825int
1826xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1827 const xmlChar *ns_uri,
1828 xmlXPathObjectPtr value) {
1829 if (ctxt == NULL)
1830 return(-1);
1831 if (name == NULL)
1832 return(-1);
1833
1834 if (ctxt->varHash == NULL)
1835 ctxt->varHash = xmlHashCreate(0);
1836 if (ctxt->varHash == NULL)
1837 return(-1);
1838 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1839 (void *) value,
1840 (xmlHashDeallocator)xmlXPathFreeObject));
1841}
1842
1843/**
1844 * xmlXPathRegisterVariableLookup:
1845 * @ctxt: the XPath context
1846 * @f: the lookup function
1847 * @data: the lookup data
1848 *
1849 * register an external mechanism to do variable lookup
1850 */
1851void
1852xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1853 xmlXPathVariableLookupFunc f, void *data) {
1854 if (ctxt == NULL)
1855 return;
1856 ctxt->varLookupFunc = (void *) f;
1857 ctxt->varLookupData = data;
1858}
1859
1860/**
1861 * xmlXPathVariableLookup:
1862 * @ctxt: the XPath context
1863 * @name: the variable name
1864 *
1865 * Search in the Variable array of the context for the given
1866 * variable value.
1867 *
1868 * Returns the value or NULL if not found
1869 */
1870xmlXPathObjectPtr
1871xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1872 if (ctxt == NULL)
1873 return(NULL);
1874
1875 if (ctxt->varLookupFunc != NULL) {
1876 xmlXPathObjectPtr ret;
1877
1878 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1879 (ctxt->varLookupData, name, NULL);
1880 if (ret != NULL) return(ret);
1881 }
1882 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1883}
1884
1885/**
1886 * xmlXPathVariableLookupNS:
1887 * @ctxt: the XPath context
1888 * @name: the variable name
1889 * @ns_uri: the variable namespace URI
1890 *
1891 * Search in the Variable array of the context for the given
1892 * variable value.
1893 *
1894 * Returns the value or NULL if not found
1895 */
1896xmlXPathObjectPtr
1897xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1898 const xmlChar *ns_uri) {
1899 if (ctxt == NULL)
1900 return(NULL);
1901
1902 if (ctxt->varLookupFunc != NULL) {
1903 xmlXPathObjectPtr ret;
1904
1905 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1906 (ctxt->varLookupData, name, ns_uri);
1907 if (ret != NULL) return(ret);
1908 }
1909
1910 if (ctxt->varHash == NULL)
1911 return(NULL);
1912 if (name == NULL)
1913 return(NULL);
1914
1915 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1916}
1917
1918/**
1919 * xmlXPathRegisteredVariablesCleanup:
1920 * @ctxt: the XPath context
1921 *
1922 * Cleanup the XPath context data associated to registered variables
1923 */
1924void
1925xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1926 if (ctxt == NULL)
1927 return;
1928
1929 xmlHashFree(ctxt->varHash, NULL);
1930 ctxt->varHash = NULL;
1931}
1932
1933/**
1934 * xmlXPathRegisterNs:
1935 * @ctxt: the XPath context
1936 * @prefix: the namespace prefix
1937 * @ns_uri: the namespace name
1938 *
1939 * Register a new namespace. If @ns_uri is NULL it unregisters
1940 * the namespace
1941 *
1942 * Returns 0 in case of success, -1 in case of error
1943 */
1944int
1945xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1946 const xmlChar *ns_uri) {
1947 if (ctxt == NULL)
1948 return(-1);
1949 if (prefix == NULL)
1950 return(-1);
1951
1952 if (ctxt->nsHash == NULL)
1953 ctxt->nsHash = xmlHashCreate(10);
1954 if (ctxt->nsHash == NULL)
1955 return(-1);
1956 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1957 (xmlHashDeallocator)xmlFree));
1958}
1959
1960/**
1961 * xmlXPathNsLookup:
1962 * @ctxt: the XPath context
1963 * @prefix: the namespace prefix value
1964 *
1965 * Search in the namespace declaration array of the context for the given
1966 * namespace name associated to the given prefix
1967 *
1968 * Returns the value or NULL if not found
1969 */
1970const xmlChar *
1971xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1972 if (ctxt == NULL)
1973 return(NULL);
1974 if (prefix == NULL)
1975 return(NULL);
1976
1977#ifdef XML_XML_NAMESPACE
1978 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1979 return(XML_XML_NAMESPACE);
1980#endif
1981
1982 if (ctxt->nsHash == NULL)
1983 return(NULL);
1984
1985 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1986}
1987
1988/**
1989 * xmlXPathRegisteredVariablesCleanup:
1990 * @ctxt: the XPath context
1991 *
1992 * Cleanup the XPath context data associated to registered variables
1993 */
1994void
1995xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
1996 if (ctxt == NULL)
1997 return;
1998
1999 xmlHashFree(ctxt->nsHash, NULL);
2000 ctxt->nsHash = NULL;
2001}
2002
2003/************************************************************************
2004 * *
2005 * Routines to handle Values *
2006 * *
2007 ************************************************************************/
2008
2009/* Allocations are terrible, one need to optimize all this !!! */
2010
2011/**
2012 * xmlXPathNewFloat:
2013 * @val: the double value
2014 *
2015 * Create a new xmlXPathObjectPtr of type double and of value @val
2016 *
2017 * Returns the newly created object.
2018 */
2019xmlXPathObjectPtr
2020xmlXPathNewFloat(double val) {
2021 xmlXPathObjectPtr ret;
2022
2023 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2024 if (ret == NULL) {
2025 xmlGenericError(xmlGenericErrorContext,
2026 "xmlXPathNewFloat: out of memory\n");
2027 return(NULL);
2028 }
2029 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2030 ret->type = XPATH_NUMBER;
2031 ret->floatval = val;
2032 return(ret);
2033}
2034
2035/**
2036 * xmlXPathNewBoolean:
2037 * @val: the boolean value
2038 *
2039 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2040 *
2041 * Returns the newly created object.
2042 */
2043xmlXPathObjectPtr
2044xmlXPathNewBoolean(int val) {
2045 xmlXPathObjectPtr ret;
2046
2047 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2048 if (ret == NULL) {
2049 xmlGenericError(xmlGenericErrorContext,
2050 "xmlXPathNewBoolean: out of memory\n");
2051 return(NULL);
2052 }
2053 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2054 ret->type = XPATH_BOOLEAN;
2055 ret->boolval = (val != 0);
2056 return(ret);
2057}
2058
2059/**
2060 * xmlXPathNewString:
2061 * @val: the xmlChar * value
2062 *
2063 * Create a new xmlXPathObjectPtr of type string and of value @val
2064 *
2065 * Returns the newly created object.
2066 */
2067xmlXPathObjectPtr
2068xmlXPathNewString(const xmlChar *val) {
2069 xmlXPathObjectPtr ret;
2070
2071 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2072 if (ret == NULL) {
2073 xmlGenericError(xmlGenericErrorContext,
2074 "xmlXPathNewString: out of memory\n");
2075 return(NULL);
2076 }
2077 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2078 ret->type = XPATH_STRING;
2079 if (val != NULL)
2080 ret->stringval = xmlStrdup(val);
2081 else
2082 ret->stringval = xmlStrdup((const xmlChar *)"");
2083 return(ret);
2084}
2085
2086/**
2087 * xmlXPathNewCString:
2088 * @val: the char * value
2089 *
2090 * Create a new xmlXPathObjectPtr of type string and of value @val
2091 *
2092 * Returns the newly created object.
2093 */
2094xmlXPathObjectPtr
2095xmlXPathNewCString(const char *val) {
2096 xmlXPathObjectPtr ret;
2097
2098 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2099 if (ret == NULL) {
2100 xmlGenericError(xmlGenericErrorContext,
2101 "xmlXPathNewCString: out of memory\n");
2102 return(NULL);
2103 }
2104 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2105 ret->type = XPATH_STRING;
2106 ret->stringval = xmlStrdup(BAD_CAST val);
2107 return(ret);
2108}
2109
2110/**
2111 * xmlXPathObjectCopy:
2112 * @val: the original object
2113 *
2114 * allocate a new copy of a given object
2115 *
2116 * Returns the newly created object.
2117 */
2118xmlXPathObjectPtr
2119xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2120 xmlXPathObjectPtr ret;
2121
2122 if (val == NULL)
2123 return(NULL);
2124
2125 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2126 if (ret == NULL) {
2127 xmlGenericError(xmlGenericErrorContext,
2128 "xmlXPathObjectCopy: out of memory\n");
2129 return(NULL);
2130 }
2131 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2132 switch (val->type) {
2133 case XPATH_BOOLEAN:
2134 case XPATH_NUMBER:
2135 case XPATH_POINT:
2136 case XPATH_RANGE:
2137 break;
2138 case XPATH_STRING:
2139 ret->stringval = xmlStrdup(val->stringval);
2140 break;
2141 case XPATH_XSLT_TREE:
2142 if ((val->nodesetval != NULL) &&
2143 (val->nodesetval->nodeTab != NULL))
2144 ret->nodesetval = xmlXPathNodeSetCreate(
2145 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2146 else
2147 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2148 break;
2149 case XPATH_NODESET:
2150 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2151 break;
2152 case XPATH_LOCATIONSET:
2153#ifdef LIBXML_XPTR_ENABLED
2154 {
2155 xmlLocationSetPtr loc = val->user;
2156 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2157 break;
2158 }
2159#endif
2160 case XPATH_UNDEFINED:
2161 case XPATH_USERS:
2162 xmlGenericError(xmlGenericErrorContext,
2163 "xmlXPathObjectCopy: unsupported type %d\n",
2164 val->type);
2165 break;
2166 }
2167 return(ret);
2168}
2169
2170/**
2171 * xmlXPathFreeObject:
2172 * @obj: the object to free
2173 *
2174 * Free up an xmlXPathObjectPtr object.
2175 */
2176void
2177xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2178 if (obj == NULL) return;
2179 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002180 if (obj->boolval) {
2181 obj->type = XPATH_XSLT_TREE;
2182 if (obj->nodesetval != NULL)
2183 xmlXPathFreeValueTree(obj->nodesetval);
2184 } else {
2185 if (obj->nodesetval != NULL)
2186 xmlXPathFreeNodeSet(obj->nodesetval);
2187 }
Owen Taylor3473f882001-02-23 17:55:21 +00002188#ifdef LIBXML_XPTR_ENABLED
2189 } else if (obj->type == XPATH_LOCATIONSET) {
2190 if (obj->user != NULL)
2191 xmlXPtrFreeLocationSet(obj->user);
2192#endif
2193 } else if (obj->type == XPATH_STRING) {
2194 if (obj->stringval != NULL)
2195 xmlFree(obj->stringval);
2196 } else if (obj->type == XPATH_XSLT_TREE) {
2197 if (obj->nodesetval != NULL)
2198 xmlXPathFreeValueTree(obj->nodesetval);
2199 }
2200
Owen Taylor3473f882001-02-23 17:55:21 +00002201 xmlFree(obj);
2202}
2203
2204/************************************************************************
2205 * *
2206 * Routines to handle XPath contexts *
2207 * *
2208 ************************************************************************/
2209
2210/**
2211 * xmlXPathNewContext:
2212 * @doc: the XML document
2213 *
2214 * Create a new xmlXPathContext
2215 *
2216 * Returns the xmlXPathContext just allocated.
2217 */
2218xmlXPathContextPtr
2219xmlXPathNewContext(xmlDocPtr doc) {
2220 xmlXPathContextPtr ret;
2221
2222 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2223 if (ret == NULL) {
2224 xmlGenericError(xmlGenericErrorContext,
2225 "xmlXPathNewContext: out of memory\n");
2226 return(NULL);
2227 }
2228 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2229 ret->doc = doc;
2230 ret->node = NULL;
2231
2232 ret->varHash = NULL;
2233
2234 ret->nb_types = 0;
2235 ret->max_types = 0;
2236 ret->types = NULL;
2237
2238 ret->funcHash = xmlHashCreate(0);
2239
2240 ret->nb_axis = 0;
2241 ret->max_axis = 0;
2242 ret->axis = NULL;
2243
2244 ret->nsHash = NULL;
2245 ret->user = NULL;
2246
2247 ret->contextSize = -1;
2248 ret->proximityPosition = -1;
2249
2250 xmlXPathRegisterAllFunctions(ret);
2251
2252 return(ret);
2253}
2254
2255/**
2256 * xmlXPathFreeContext:
2257 * @ctxt: the context to free
2258 *
2259 * Free up an xmlXPathContext
2260 */
2261void
2262xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2263 xmlXPathRegisteredNsCleanup(ctxt);
2264 xmlXPathRegisteredFuncsCleanup(ctxt);
2265 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002266 xmlFree(ctxt);
2267}
2268
2269/************************************************************************
2270 * *
2271 * Routines to handle XPath parser contexts *
2272 * *
2273 ************************************************************************/
2274
2275#define CHECK_CTXT(ctxt) \
2276 if (ctxt == NULL) { \
2277 xmlGenericError(xmlGenericErrorContext, \
2278 "%s:%d Internal error: ctxt == NULL\n", \
2279 __FILE__, __LINE__); \
2280 } \
2281
2282
2283#define CHECK_CONTEXT(ctxt) \
2284 if (ctxt == NULL) { \
2285 xmlGenericError(xmlGenericErrorContext, \
2286 "%s:%d Internal error: no context\n", \
2287 __FILE__, __LINE__); \
2288 } \
2289 else if (ctxt->doc == NULL) { \
2290 xmlGenericError(xmlGenericErrorContext, \
2291 "%s:%d Internal error: no document\n", \
2292 __FILE__, __LINE__); \
2293 } \
2294 else if (ctxt->doc->children == NULL) { \
2295 xmlGenericError(xmlGenericErrorContext, \
2296 "%s:%d Internal error: document without root\n", \
2297 __FILE__, __LINE__); \
2298 } \
2299
2300
2301/**
2302 * xmlXPathNewParserContext:
2303 * @str: the XPath expression
2304 * @ctxt: the XPath context
2305 *
2306 * Create a new xmlXPathParserContext
2307 *
2308 * Returns the xmlXPathParserContext just allocated.
2309 */
2310xmlXPathParserContextPtr
2311xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2312 xmlXPathParserContextPtr ret;
2313
2314 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2315 if (ret == NULL) {
2316 xmlGenericError(xmlGenericErrorContext,
2317 "xmlXPathNewParserContext: out of memory\n");
2318 return(NULL);
2319 }
2320 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2321 ret->cur = ret->base = str;
2322 ret->context = ctxt;
2323
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002324 ret->comp = xmlXPathNewCompExpr();
2325 if (ret->comp == NULL) {
2326 xmlFree(ret->valueTab);
2327 xmlFree(ret);
2328 return(NULL);
2329 }
2330
2331 return(ret);
2332}
2333
2334/**
2335 * xmlXPathCompParserContext:
2336 * @comp: the XPath compiled expression
2337 * @ctxt: the XPath context
2338 *
2339 * Create a new xmlXPathParserContext when processing a compiled expression
2340 *
2341 * Returns the xmlXPathParserContext just allocated.
2342 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002343static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002344xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2345 xmlXPathParserContextPtr ret;
2346
2347 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2348 if (ret == NULL) {
2349 xmlGenericError(xmlGenericErrorContext,
2350 "xmlXPathNewParserContext: out of memory\n");
2351 return(NULL);
2352 }
2353 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2354
Owen Taylor3473f882001-02-23 17:55:21 +00002355 /* Allocate the value stack */
2356 ret->valueTab = (xmlXPathObjectPtr *)
2357 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002358 if (ret->valueTab == NULL) {
2359 xmlFree(ret);
2360 xmlGenericError(xmlGenericErrorContext,
2361 "xmlXPathNewParserContext: out of memory\n");
2362 return(NULL);
2363 }
Owen Taylor3473f882001-02-23 17:55:21 +00002364 ret->valueNr = 0;
2365 ret->valueMax = 10;
2366 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002367
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002368 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002369 ret->comp = comp;
2370
Owen Taylor3473f882001-02-23 17:55:21 +00002371 return(ret);
2372}
2373
2374/**
2375 * xmlXPathFreeParserContext:
2376 * @ctxt: the context to free
2377 *
2378 * Free up an xmlXPathParserContext
2379 */
2380void
2381xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2382 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002383 xmlFree(ctxt->valueTab);
2384 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002385 if (ctxt->comp)
2386 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002387 xmlFree(ctxt);
2388}
2389
2390/************************************************************************
2391 * *
2392 * The implicit core function library *
2393 * *
2394 ************************************************************************/
2395
2396/*
2397 * Auto-pop and cast to a number
2398 */
2399void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
2400
2401
2402#define POP_FLOAT \
2403 arg = valuePop(ctxt); \
2404 if (arg == NULL) { \
2405 XP_ERROR(XPATH_INVALID_OPERAND); \
2406 } \
2407 if (arg->type != XPATH_NUMBER) { \
2408 valuePush(ctxt, arg); \
2409 xmlXPathNumberFunction(ctxt, 1); \
2410 arg = valuePop(ctxt); \
2411 }
2412
2413/**
2414 * xmlXPathCompareNodeSetFloat:
2415 * @ctxt: the XPath Parser context
2416 * @inf: less than (1) or greater than (0)
2417 * @strict: is the comparison strict
2418 * @arg: the node set
2419 * @f: the value
2420 *
2421 * Implement the compare operation between a nodeset and a number
2422 * @ns < @val (1, 1, ...
2423 * @ns <= @val (1, 0, ...
2424 * @ns > @val (0, 1, ...
2425 * @ns >= @val (0, 0, ...
2426 *
2427 * If one object to be compared is a node-set and the other is a number,
2428 * then the comparison will be true if and only if there is a node in the
2429 * node-set such that the result of performing the comparison on the number
2430 * to be compared and on the result of converting the string-value of that
2431 * node to a number using the number function is true.
2432 *
2433 * Returns 0 or 1 depending on the results of the test.
2434 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002435static int
Owen Taylor3473f882001-02-23 17:55:21 +00002436xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2437 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2438 int i, ret = 0;
2439 xmlNodeSetPtr ns;
2440 xmlChar *str2;
2441
2442 if ((f == NULL) || (arg == NULL) ||
2443 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2444 xmlXPathFreeObject(arg);
2445 xmlXPathFreeObject(f);
2446 return(0);
2447 }
2448 ns = arg->nodesetval;
2449 for (i = 0;i < ns->nodeNr;i++) {
2450 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2451 if (str2 != NULL) {
2452 valuePush(ctxt,
2453 xmlXPathNewString(str2));
2454 xmlFree(str2);
2455 xmlXPathNumberFunction(ctxt, 1);
2456 valuePush(ctxt, xmlXPathObjectCopy(f));
2457 ret = xmlXPathCompareValues(ctxt, inf, strict);
2458 if (ret)
2459 break;
2460 }
2461 }
2462 xmlXPathFreeObject(arg);
2463 xmlXPathFreeObject(f);
2464 return(ret);
2465}
2466
2467/**
2468 * xmlXPathCompareNodeSetString:
2469 * @ctxt: the XPath Parser context
2470 * @inf: less than (1) or greater than (0)
2471 * @strict: is the comparison strict
2472 * @arg: the node set
2473 * @s: the value
2474 *
2475 * Implement the compare operation between a nodeset and a string
2476 * @ns < @val (1, 1, ...
2477 * @ns <= @val (1, 0, ...
2478 * @ns > @val (0, 1, ...
2479 * @ns >= @val (0, 0, ...
2480 *
2481 * If one object to be compared is a node-set and the other is a string,
2482 * then the comparison will be true if and only if there is a node in
2483 * the node-set such that the result of performing the comparison on the
2484 * string-value of the node and the other string is true.
2485 *
2486 * Returns 0 or 1 depending on the results of the test.
2487 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002488static int
Owen Taylor3473f882001-02-23 17:55:21 +00002489xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2490 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2491 int i, ret = 0;
2492 xmlNodeSetPtr ns;
2493 xmlChar *str2;
2494
2495 if ((s == NULL) || (arg == NULL) ||
2496 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2497 xmlXPathFreeObject(arg);
2498 xmlXPathFreeObject(s);
2499 return(0);
2500 }
2501 ns = arg->nodesetval;
2502 for (i = 0;i < ns->nodeNr;i++) {
2503 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2504 if (str2 != NULL) {
2505 valuePush(ctxt,
2506 xmlXPathNewString(str2));
2507 xmlFree(str2);
2508 valuePush(ctxt, xmlXPathObjectCopy(s));
2509 ret = xmlXPathCompareValues(ctxt, inf, strict);
2510 if (ret)
2511 break;
2512 }
2513 }
2514 xmlXPathFreeObject(arg);
2515 xmlXPathFreeObject(s);
2516 return(ret);
2517}
2518
2519/**
2520 * xmlXPathCompareNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00002521 * @op: less than (-1), equal (0) or greater than (1)
2522 * @strict: is the comparison strict
2523 * @arg1: the fist node set object
2524 * @arg2: the second node set object
2525 *
2526 * Implement the compare operation on nodesets:
2527 *
2528 * If both objects to be compared are node-sets, then the comparison
2529 * will be true if and only if there is a node in the first node-set
2530 * and a node in the second node-set such that the result of performing
2531 * the comparison on the string-values of the two nodes is true.
2532 * ....
2533 * When neither object to be compared is a node-set and the operator
2534 * is <=, <, >= or >, then the objects are compared by converting both
2535 * objects to numbers and comparing the numbers according to IEEE 754.
2536 * ....
2537 * The number function converts its argument to a number as follows:
2538 * - a string that consists of optional whitespace followed by an
2539 * optional minus sign followed by a Number followed by whitespace
2540 * is converted to the IEEE 754 number that is nearest (according
2541 * to the IEEE 754 round-to-nearest rule) to the mathematical value
2542 * represented by the string; any other string is converted to NaN
2543 *
2544 * Conclusion all nodes need to be converted first to their string value
2545 * and then the comparison must be done when possible
2546 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002547static int
2548xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00002549 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2550 int i, j, init = 0;
2551 double val1;
2552 double *values2;
2553 int ret = 0;
2554 xmlChar *str;
2555 xmlNodeSetPtr ns1;
2556 xmlNodeSetPtr ns2;
2557
2558 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002559 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
2560 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002561 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002562 }
Owen Taylor3473f882001-02-23 17:55:21 +00002563 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002564 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
2565 xmlXPathFreeObject(arg1);
2566 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002567 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002568 }
Owen Taylor3473f882001-02-23 17:55:21 +00002569
2570 ns1 = arg1->nodesetval;
2571 ns2 = arg2->nodesetval;
2572
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002573 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002574 xmlXPathFreeObject(arg1);
2575 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002576 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002577 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002578 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002579 xmlXPathFreeObject(arg1);
2580 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002581 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002582 }
Owen Taylor3473f882001-02-23 17:55:21 +00002583
2584 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
2585 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002586 xmlXPathFreeObject(arg1);
2587 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002588 return(0);
2589 }
2590 for (i = 0;i < ns1->nodeNr;i++) {
2591 str = xmlNodeGetContent(ns1->nodeTab[i]);
2592 if (str == NULL)
2593 continue;
2594 val1 = xmlXPathStringEvalNumber(str);
2595 xmlFree(str);
2596 if (isnan(val1))
2597 continue;
2598 for (j = 0;j < ns2->nodeNr;j++) {
2599 if (init == 0) {
2600 str = xmlNodeGetContent(ns2->nodeTab[j]);
2601 if (str == NULL) {
2602 values2[j] = xmlXPathNAN;
2603 } else {
2604 values2[j] = xmlXPathStringEvalNumber(str);
2605 xmlFree(str);
2606 }
2607 }
2608 if (isnan(values2[j]))
2609 continue;
2610 if (inf && strict)
2611 ret = (val1 < values2[j]);
2612 else if (inf && !strict)
2613 ret = (val1 <= values2[j]);
2614 else if (!inf && strict)
2615 ret = (val1 > values2[j]);
2616 else if (!inf && !strict)
2617 ret = (val1 >= values2[j]);
2618 if (ret)
2619 break;
2620 }
2621 if (ret)
2622 break;
2623 init = 1;
2624 }
2625 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002626 xmlXPathFreeObject(arg1);
2627 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002628 return(ret);
2629 return(0);
2630}
2631
2632/**
2633 * xmlXPathCompareNodeSetValue:
2634 * @ctxt: the XPath Parser context
2635 * @inf: less than (1) or greater than (0)
2636 * @strict: is the comparison strict
2637 * @arg: the node set
2638 * @val: the value
2639 *
2640 * Implement the compare operation between a nodeset and a value
2641 * @ns < @val (1, 1, ...
2642 * @ns <= @val (1, 0, ...
2643 * @ns > @val (0, 1, ...
2644 * @ns >= @val (0, 0, ...
2645 *
2646 * If one object to be compared is a node-set and the other is a boolean,
2647 * then the comparison will be true if and only if the result of performing
2648 * the comparison on the boolean and on the result of converting
2649 * the node-set to a boolean using the boolean function is true.
2650 *
2651 * Returns 0 or 1 depending on the results of the test.
2652 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002653static int
Owen Taylor3473f882001-02-23 17:55:21 +00002654xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
2655 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
2656 if ((val == NULL) || (arg == NULL) ||
2657 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2658 return(0);
2659
2660 switch(val->type) {
2661 case XPATH_NUMBER:
2662 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
2663 case XPATH_NODESET:
2664 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002665 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00002666 case XPATH_STRING:
2667 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
2668 case XPATH_BOOLEAN:
2669 valuePush(ctxt, arg);
2670 xmlXPathBooleanFunction(ctxt, 1);
2671 valuePush(ctxt, val);
2672 return(xmlXPathCompareValues(ctxt, inf, strict));
2673 default:
2674 TODO
2675 return(0);
2676 }
2677 return(0);
2678}
2679
2680/**
2681 * xmlXPathEqualNodeSetString
2682 * @arg: the nodeset object argument
2683 * @str: the string to compare to.
2684 *
2685 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2686 * If one object to be compared is a node-set and the other is a string,
2687 * then the comparison will be true if and only if there is a node in
2688 * the node-set such that the result of performing the comparison on the
2689 * string-value of the node and the other string is true.
2690 *
2691 * Returns 0 or 1 depending on the results of the test.
2692 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002693static int
Owen Taylor3473f882001-02-23 17:55:21 +00002694xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
2695 int i;
2696 xmlNodeSetPtr ns;
2697 xmlChar *str2;
2698
2699 if ((str == NULL) || (arg == NULL) ||
2700 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2701 return(0);
2702 ns = arg->nodesetval;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002703 if (ns == NULL)
2704 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002705 if (ns->nodeNr <= 0)
2706 return(0);
2707 for (i = 0;i < ns->nodeNr;i++) {
2708 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2709 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
2710 xmlFree(str2);
2711 return(1);
2712 }
2713 if (str2 != NULL)
2714 xmlFree(str2);
2715 }
2716 return(0);
2717}
2718
2719/**
2720 * xmlXPathEqualNodeSetFloat
2721 * @arg: the nodeset object argument
2722 * @f: the float to compare to
2723 *
2724 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2725 * If one object to be compared is a node-set and the other is a number,
2726 * then the comparison will be true if and only if there is a node in
2727 * the node-set such that the result of performing the comparison on the
2728 * number to be compared and on the result of converting the string-value
2729 * of that node to a number using the number function is true.
2730 *
2731 * Returns 0 or 1 depending on the results of the test.
2732 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002733static int
Owen Taylor3473f882001-02-23 17:55:21 +00002734xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
2735 char buf[100] = "";
2736
2737 if ((arg == NULL) ||
2738 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2739 return(0);
2740
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002741 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00002742 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
2743}
2744
2745
2746/**
2747 * xmlXPathEqualNodeSets
2748 * @arg1: first nodeset object argument
2749 * @arg2: second nodeset object argument
2750 *
2751 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
2752 * If both objects to be compared are node-sets, then the comparison
2753 * will be true if and only if there is a node in the first node-set and
2754 * a node in the second node-set such that the result of performing the
2755 * comparison on the string-values of the two nodes is true.
2756 *
2757 * (needless to say, this is a costly operation)
2758 *
2759 * Returns 0 or 1 depending on the results of the test.
2760 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002761static int
Owen Taylor3473f882001-02-23 17:55:21 +00002762xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2763 int i, j;
2764 xmlChar **values1;
2765 xmlChar **values2;
2766 int ret = 0;
2767 xmlNodeSetPtr ns1;
2768 xmlNodeSetPtr ns2;
2769
2770 if ((arg1 == NULL) ||
2771 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
2772 return(0);
2773 if ((arg2 == NULL) ||
2774 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
2775 return(0);
2776
2777 ns1 = arg1->nodesetval;
2778 ns2 = arg2->nodesetval;
2779
2780 if (ns1->nodeNr <= 0)
2781 return(0);
2782 if (ns2->nodeNr <= 0)
2783 return(0);
2784
2785 /*
2786 * check if there is a node pertaining to both sets
2787 */
2788 for (i = 0;i < ns1->nodeNr;i++)
2789 for (j = 0;j < ns2->nodeNr;j++)
2790 if (ns1->nodeTab[i] == ns2->nodeTab[j])
2791 return(1);
2792
2793 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
2794 if (values1 == NULL)
2795 return(0);
2796 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
2797 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
2798 if (values2 == NULL) {
2799 xmlFree(values1);
2800 return(0);
2801 }
2802 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
2803 for (i = 0;i < ns1->nodeNr;i++) {
2804 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
2805 for (j = 0;j < ns2->nodeNr;j++) {
2806 if (i == 0)
2807 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
2808 ret = xmlStrEqual(values1[i], values2[j]);
2809 if (ret)
2810 break;
2811 }
2812 if (ret)
2813 break;
2814 }
2815 for (i = 0;i < ns1->nodeNr;i++)
2816 if (values1[i] != NULL)
2817 xmlFree(values1[i]);
2818 for (j = 0;j < ns2->nodeNr;j++)
2819 if (values2[j] != NULL)
2820 xmlFree(values2[j]);
2821 xmlFree(values1);
2822 xmlFree(values2);
2823 return(ret);
2824}
2825
2826/**
2827 * xmlXPathEqualValues:
2828 * @ctxt: the XPath Parser context
2829 *
2830 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2831 *
2832 * Returns 0 or 1 depending on the results of the test.
2833 */
2834int
2835xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
2836 xmlXPathObjectPtr arg1, arg2;
2837 int ret = 0;
2838
2839 arg1 = valuePop(ctxt);
2840 if (arg1 == NULL)
2841 XP_ERROR0(XPATH_INVALID_OPERAND);
2842
2843 arg2 = valuePop(ctxt);
2844 if (arg2 == NULL) {
2845 xmlXPathFreeObject(arg1);
2846 XP_ERROR0(XPATH_INVALID_OPERAND);
2847 }
2848
2849 if (arg1 == arg2) {
2850#ifdef DEBUG_EXPR
2851 xmlGenericError(xmlGenericErrorContext,
2852 "Equal: by pointer\n");
2853#endif
2854 return(1);
2855 }
2856
2857 switch (arg1->type) {
2858 case XPATH_UNDEFINED:
2859#ifdef DEBUG_EXPR
2860 xmlGenericError(xmlGenericErrorContext,
2861 "Equal: undefined\n");
2862#endif
2863 break;
2864 case XPATH_XSLT_TREE:
2865 case XPATH_NODESET:
2866 switch (arg2->type) {
2867 case XPATH_UNDEFINED:
2868#ifdef DEBUG_EXPR
2869 xmlGenericError(xmlGenericErrorContext,
2870 "Equal: undefined\n");
2871#endif
2872 break;
2873 case XPATH_XSLT_TREE:
2874 case XPATH_NODESET:
2875 ret = xmlXPathEqualNodeSets(arg1, arg2);
2876 break;
2877 case XPATH_BOOLEAN:
2878 if ((arg1->nodesetval == NULL) ||
2879 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2880 else
2881 ret = 1;
2882 ret = (ret == arg2->boolval);
2883 break;
2884 case XPATH_NUMBER:
2885 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2886 break;
2887 case XPATH_STRING:
2888 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2889 break;
2890 case XPATH_USERS:
2891 case XPATH_POINT:
2892 case XPATH_RANGE:
2893 case XPATH_LOCATIONSET:
2894 TODO
2895 break;
2896 }
2897 break;
2898 case XPATH_BOOLEAN:
2899 switch (arg2->type) {
2900 case XPATH_UNDEFINED:
2901#ifdef DEBUG_EXPR
2902 xmlGenericError(xmlGenericErrorContext,
2903 "Equal: undefined\n");
2904#endif
2905 break;
2906 case XPATH_NODESET:
2907 case XPATH_XSLT_TREE:
2908 if ((arg2->nodesetval == NULL) ||
2909 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2910 else
2911 ret = 1;
2912 break;
2913 case XPATH_BOOLEAN:
2914#ifdef DEBUG_EXPR
2915 xmlGenericError(xmlGenericErrorContext,
2916 "Equal: %d boolean %d \n",
2917 arg1->boolval, arg2->boolval);
2918#endif
2919 ret = (arg1->boolval == arg2->boolval);
2920 break;
2921 case XPATH_NUMBER:
2922 if (arg2->floatval) ret = 1;
2923 else ret = 0;
2924 ret = (arg1->boolval == ret);
2925 break;
2926 case XPATH_STRING:
2927 if ((arg2->stringval == NULL) ||
2928 (arg2->stringval[0] == 0)) ret = 0;
2929 else
2930 ret = 1;
2931 ret = (arg1->boolval == ret);
2932 break;
2933 case XPATH_USERS:
2934 case XPATH_POINT:
2935 case XPATH_RANGE:
2936 case XPATH_LOCATIONSET:
2937 TODO
2938 break;
2939 }
2940 break;
2941 case XPATH_NUMBER:
2942 switch (arg2->type) {
2943 case XPATH_UNDEFINED:
2944#ifdef DEBUG_EXPR
2945 xmlGenericError(xmlGenericErrorContext,
2946 "Equal: undefined\n");
2947#endif
2948 break;
2949 case XPATH_NODESET:
2950 case XPATH_XSLT_TREE:
2951 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2952 break;
2953 case XPATH_BOOLEAN:
2954 if (arg1->floatval) ret = 1;
2955 else ret = 0;
2956 ret = (arg2->boolval == ret);
2957 break;
2958 case XPATH_STRING:
2959 valuePush(ctxt, arg2);
2960 xmlXPathNumberFunction(ctxt, 1);
2961 arg2 = valuePop(ctxt);
2962 /* no break on purpose */
2963 case XPATH_NUMBER:
2964 ret = (arg1->floatval == arg2->floatval);
2965 break;
2966 case XPATH_USERS:
2967 case XPATH_POINT:
2968 case XPATH_RANGE:
2969 case XPATH_LOCATIONSET:
2970 TODO
2971 break;
2972 }
2973 break;
2974 case XPATH_STRING:
2975 switch (arg2->type) {
2976 case XPATH_UNDEFINED:
2977#ifdef DEBUG_EXPR
2978 xmlGenericError(xmlGenericErrorContext,
2979 "Equal: undefined\n");
2980#endif
2981 break;
2982 case XPATH_NODESET:
2983 case XPATH_XSLT_TREE:
2984 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2985 break;
2986 case XPATH_BOOLEAN:
2987 if ((arg1->stringval == NULL) ||
2988 (arg1->stringval[0] == 0)) ret = 0;
2989 else
2990 ret = 1;
2991 ret = (arg2->boolval == ret);
2992 break;
2993 case XPATH_STRING:
2994 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
2995 break;
2996 case XPATH_NUMBER:
2997 valuePush(ctxt, arg1);
2998 xmlXPathNumberFunction(ctxt, 1);
2999 arg1 = valuePop(ctxt);
3000 ret = (arg1->floatval == arg2->floatval);
3001 break;
3002 case XPATH_USERS:
3003 case XPATH_POINT:
3004 case XPATH_RANGE:
3005 case XPATH_LOCATIONSET:
3006 TODO
3007 break;
3008 }
3009 break;
3010 case XPATH_USERS:
3011 case XPATH_POINT:
3012 case XPATH_RANGE:
3013 case XPATH_LOCATIONSET:
3014 TODO
3015 break;
3016 }
3017 xmlXPathFreeObject(arg1);
3018 xmlXPathFreeObject(arg2);
3019 return(ret);
3020}
3021
3022
3023/**
3024 * xmlXPathCompareValues:
3025 * @ctxt: the XPath Parser context
3026 * @inf: less than (1) or greater than (0)
3027 * @strict: is the comparison strict
3028 *
3029 * Implement the compare operation on XPath objects:
3030 * @arg1 < @arg2 (1, 1, ...
3031 * @arg1 <= @arg2 (1, 0, ...
3032 * @arg1 > @arg2 (0, 1, ...
3033 * @arg1 >= @arg2 (0, 0, ...
3034 *
3035 * When neither object to be compared is a node-set and the operator is
3036 * <=, <, >=, >, then the objects are compared by converted both objects
3037 * to numbers and comparing the numbers according to IEEE 754. The <
3038 * comparison will be true if and only if the first number is less than the
3039 * second number. The <= comparison will be true if and only if the first
3040 * number is less than or equal to the second number. The > comparison
3041 * will be true if and only if the first number is greater than the second
3042 * number. The >= comparison will be true if and only if the first number
3043 * is greater than or equal to the second number.
3044 *
3045 * Returns 1 if the comparaison succeeded, 0 if it failed
3046 */
3047int
3048xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3049 int ret = 0;
3050 xmlXPathObjectPtr arg1, arg2;
3051
3052 arg2 = valuePop(ctxt);
3053 if (arg2 == NULL) {
3054 XP_ERROR0(XPATH_INVALID_OPERAND);
3055 }
3056
3057 arg1 = valuePop(ctxt);
3058 if (arg1 == NULL) {
3059 xmlXPathFreeObject(arg2);
3060 XP_ERROR0(XPATH_INVALID_OPERAND);
3061 }
3062
3063 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3064 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003065 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003066 } else {
3067 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003068 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3069 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003070 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003071 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3072 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003073 }
3074 }
3075 return(ret);
3076 }
3077
3078 if (arg1->type != XPATH_NUMBER) {
3079 valuePush(ctxt, arg1);
3080 xmlXPathNumberFunction(ctxt, 1);
3081 arg1 = valuePop(ctxt);
3082 }
3083 if (arg1->type != XPATH_NUMBER) {
3084 xmlXPathFreeObject(arg1);
3085 xmlXPathFreeObject(arg2);
3086 XP_ERROR0(XPATH_INVALID_OPERAND);
3087 }
3088 if (arg2->type != XPATH_NUMBER) {
3089 valuePush(ctxt, arg2);
3090 xmlXPathNumberFunction(ctxt, 1);
3091 arg2 = valuePop(ctxt);
3092 }
3093 if (arg2->type != XPATH_NUMBER) {
3094 xmlXPathFreeObject(arg1);
3095 xmlXPathFreeObject(arg2);
3096 XP_ERROR0(XPATH_INVALID_OPERAND);
3097 }
3098 /*
3099 * Add tests for infinity and nan
3100 * => feedback on 3.4 for Inf and NaN
3101 */
3102 if (inf && strict)
3103 ret = (arg1->floatval < arg2->floatval);
3104 else if (inf && !strict)
3105 ret = (arg1->floatval <= arg2->floatval);
3106 else if (!inf && strict)
3107 ret = (arg1->floatval > arg2->floatval);
3108 else if (!inf && !strict)
3109 ret = (arg1->floatval >= arg2->floatval);
3110 xmlXPathFreeObject(arg1);
3111 xmlXPathFreeObject(arg2);
3112 return(ret);
3113}
3114
3115/**
3116 * xmlXPathValueFlipSign:
3117 * @ctxt: the XPath Parser context
3118 *
3119 * Implement the unary - operation on an XPath object
3120 * The numeric operators convert their operands to numbers as if
3121 * by calling the number function.
3122 */
3123void
3124xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
3125 xmlXPathObjectPtr arg;
3126
3127 POP_FLOAT
3128 arg->floatval = -arg->floatval;
3129 valuePush(ctxt, arg);
3130}
3131
3132/**
3133 * xmlXPathAddValues:
3134 * @ctxt: the XPath Parser context
3135 *
3136 * Implement the add operation on XPath objects:
3137 * The numeric operators convert their operands to numbers as if
3138 * by calling the number function.
3139 */
3140void
3141xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3142 xmlXPathObjectPtr arg;
3143 double val;
3144
3145 POP_FLOAT
3146 val = arg->floatval;
3147 xmlXPathFreeObject(arg);
3148
3149 POP_FLOAT
3150 arg->floatval += val;
3151 valuePush(ctxt, arg);
3152}
3153
3154/**
3155 * xmlXPathSubValues:
3156 * @ctxt: the XPath Parser context
3157 *
3158 * Implement the substraction operation on XPath objects:
3159 * The numeric operators convert their operands to numbers as if
3160 * by calling the number function.
3161 */
3162void
3163xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3164 xmlXPathObjectPtr arg;
3165 double val;
3166
3167 POP_FLOAT
3168 val = arg->floatval;
3169 xmlXPathFreeObject(arg);
3170
3171 POP_FLOAT
3172 arg->floatval -= val;
3173 valuePush(ctxt, arg);
3174}
3175
3176/**
3177 * xmlXPathMultValues:
3178 * @ctxt: the XPath Parser context
3179 *
3180 * Implement the multiply operation on XPath objects:
3181 * The numeric operators convert their operands to numbers as if
3182 * by calling the number function.
3183 */
3184void
3185xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3186 xmlXPathObjectPtr arg;
3187 double val;
3188
3189 POP_FLOAT
3190 val = arg->floatval;
3191 xmlXPathFreeObject(arg);
3192
3193 POP_FLOAT
3194 arg->floatval *= val;
3195 valuePush(ctxt, arg);
3196}
3197
3198/**
3199 * xmlXPathDivValues:
3200 * @ctxt: the XPath Parser context
3201 *
3202 * Implement the div operation on XPath objects @arg1 / @arg2:
3203 * The numeric operators convert their operands to numbers as if
3204 * by calling the number function.
3205 */
3206void
3207xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3208 xmlXPathObjectPtr arg;
3209 double val;
3210
3211 POP_FLOAT
3212 val = arg->floatval;
3213 xmlXPathFreeObject(arg);
3214
3215 POP_FLOAT
3216 arg->floatval /= val;
3217 valuePush(ctxt, arg);
3218}
3219
3220/**
3221 * xmlXPathModValues:
3222 * @ctxt: the XPath Parser context
3223 *
3224 * Implement the mod operation on XPath objects: @arg1 / @arg2
3225 * The numeric operators convert their operands to numbers as if
3226 * by calling the number function.
3227 */
3228void
3229xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3230 xmlXPathObjectPtr arg;
3231 int arg1, arg2;
3232
3233 POP_FLOAT
3234 arg2 = (int) arg->floatval;
3235 xmlXPathFreeObject(arg);
3236
3237 POP_FLOAT
3238 arg1 = (int) arg->floatval;
3239 arg->floatval = arg1 % arg2;
3240 valuePush(ctxt, arg);
3241}
3242
3243/************************************************************************
3244 * *
3245 * The traversal functions *
3246 * *
3247 ************************************************************************/
3248
Owen Taylor3473f882001-02-23 17:55:21 +00003249/*
3250 * A traversal function enumerates nodes along an axis.
3251 * Initially it must be called with NULL, and it indicates
3252 * termination on the axis by returning NULL.
3253 */
3254typedef xmlNodePtr (*xmlXPathTraversalFunction)
3255 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3256
3257/**
3258 * xmlXPathNextSelf:
3259 * @ctxt: the XPath Parser context
3260 * @cur: the current node in the traversal
3261 *
3262 * Traversal function for the "self" direction
3263 * The self axis contains just the context node itself
3264 *
3265 * Returns the next element following that axis
3266 */
3267xmlNodePtr
3268xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3269 if (cur == NULL)
3270 return(ctxt->context->node);
3271 return(NULL);
3272}
3273
3274/**
3275 * xmlXPathNextChild:
3276 * @ctxt: the XPath Parser context
3277 * @cur: the current node in the traversal
3278 *
3279 * Traversal function for the "child" direction
3280 * The child axis contains the children of the context node in document order.
3281 *
3282 * Returns the next element following that axis
3283 */
3284xmlNodePtr
3285xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3286 if (cur == NULL) {
3287 if (ctxt->context->node == NULL) return(NULL);
3288 switch (ctxt->context->node->type) {
3289 case XML_ELEMENT_NODE:
3290 case XML_TEXT_NODE:
3291 case XML_CDATA_SECTION_NODE:
3292 case XML_ENTITY_REF_NODE:
3293 case XML_ENTITY_NODE:
3294 case XML_PI_NODE:
3295 case XML_COMMENT_NODE:
3296 case XML_NOTATION_NODE:
3297 case XML_DTD_NODE:
3298 return(ctxt->context->node->children);
3299 case XML_DOCUMENT_NODE:
3300 case XML_DOCUMENT_TYPE_NODE:
3301 case XML_DOCUMENT_FRAG_NODE:
3302 case XML_HTML_DOCUMENT_NODE:
3303#ifdef LIBXML_SGML_ENABLED
3304 case XML_SGML_DOCUMENT_NODE:
3305#endif
3306 return(((xmlDocPtr) ctxt->context->node)->children);
3307 case XML_ELEMENT_DECL:
3308 case XML_ATTRIBUTE_DECL:
3309 case XML_ENTITY_DECL:
3310 case XML_ATTRIBUTE_NODE:
3311 case XML_NAMESPACE_DECL:
3312 case XML_XINCLUDE_START:
3313 case XML_XINCLUDE_END:
3314 return(NULL);
3315 }
3316 return(NULL);
3317 }
3318 if ((cur->type == XML_DOCUMENT_NODE) ||
3319 (cur->type == XML_HTML_DOCUMENT_NODE))
3320 return(NULL);
3321 return(cur->next);
3322}
3323
3324/**
3325 * xmlXPathNextDescendant:
3326 * @ctxt: the XPath Parser context
3327 * @cur: the current node in the traversal
3328 *
3329 * Traversal function for the "descendant" direction
3330 * the descendant axis contains the descendants of the context node in document
3331 * order; a descendant is a child or a child of a child and so on.
3332 *
3333 * Returns the next element following that axis
3334 */
3335xmlNodePtr
3336xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3337 if (cur == NULL) {
3338 if (ctxt->context->node == NULL)
3339 return(NULL);
3340 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3341 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3342 return(NULL);
3343
3344 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3345 return(ctxt->context->doc->children);
3346 return(ctxt->context->node->children);
3347 }
3348
3349 if (cur->children != NULL)
3350 {
3351 if (cur->children->type != XML_ENTITY_DECL)
3352 return(cur->children);
3353 }
3354 if (cur->next != NULL) return(cur->next);
3355
3356 do {
3357 cur = cur->parent;
3358 if (cur == NULL) return(NULL);
3359 if (cur == ctxt->context->node) return(NULL);
3360 if (cur->next != NULL) {
3361 cur = cur->next;
3362 return(cur);
3363 }
3364 } while (cur != NULL);
3365 return(cur);
3366}
3367
3368/**
3369 * xmlXPathNextDescendantOrSelf:
3370 * @ctxt: the XPath Parser context
3371 * @cur: the current node in the traversal
3372 *
3373 * Traversal function for the "descendant-or-self" direction
3374 * the descendant-or-self axis contains the context node and the descendants
3375 * of the context node in document order; thus the context node is the first
3376 * node on the axis, and the first child of the context node is the second node
3377 * on the axis
3378 *
3379 * Returns the next element following that axis
3380 */
3381xmlNodePtr
3382xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3383 if (cur == NULL) {
3384 if (ctxt->context->node == NULL)
3385 return(NULL);
3386 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3387 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3388 return(NULL);
3389 return(ctxt->context->node);
3390 }
3391
3392 return(xmlXPathNextDescendant(ctxt, cur));
3393}
3394
3395/**
3396 * xmlXPathNextParent:
3397 * @ctxt: the XPath Parser context
3398 * @cur: the current node in the traversal
3399 *
3400 * Traversal function for the "parent" direction
3401 * The parent axis contains the parent of the context node, if there is one.
3402 *
3403 * Returns the next element following that axis
3404 */
3405xmlNodePtr
3406xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3407 /*
3408 * the parent of an attribute or namespace node is the element
3409 * to which the attribute or namespace node is attached
3410 * Namespace handling !!!
3411 */
3412 if (cur == NULL) {
3413 if (ctxt->context->node == NULL) return(NULL);
3414 switch (ctxt->context->node->type) {
3415 case XML_ELEMENT_NODE:
3416 case XML_TEXT_NODE:
3417 case XML_CDATA_SECTION_NODE:
3418 case XML_ENTITY_REF_NODE:
3419 case XML_ENTITY_NODE:
3420 case XML_PI_NODE:
3421 case XML_COMMENT_NODE:
3422 case XML_NOTATION_NODE:
3423 case XML_DTD_NODE:
3424 case XML_ELEMENT_DECL:
3425 case XML_ATTRIBUTE_DECL:
3426 case XML_XINCLUDE_START:
3427 case XML_XINCLUDE_END:
3428 case XML_ENTITY_DECL:
3429 if (ctxt->context->node->parent == NULL)
3430 return((xmlNodePtr) ctxt->context->doc);
3431 return(ctxt->context->node->parent);
3432 case XML_ATTRIBUTE_NODE: {
3433 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3434
3435 return(att->parent);
3436 }
3437 case XML_DOCUMENT_NODE:
3438 case XML_DOCUMENT_TYPE_NODE:
3439 case XML_DOCUMENT_FRAG_NODE:
3440 case XML_HTML_DOCUMENT_NODE:
3441#ifdef LIBXML_SGML_ENABLED
3442 case XML_SGML_DOCUMENT_NODE:
3443#endif
3444 return(NULL);
3445 case XML_NAMESPACE_DECL:
3446 /*
3447 * TODO !!! may require extending struct _xmlNs with
3448 * parent field
3449 * C.f. Infoset case...
3450 */
3451 return(NULL);
3452 }
3453 }
3454 return(NULL);
3455}
3456
3457/**
3458 * xmlXPathNextAncestor:
3459 * @ctxt: the XPath Parser context
3460 * @cur: the current node in the traversal
3461 *
3462 * Traversal function for the "ancestor" direction
3463 * the ancestor axis contains the ancestors of the context node; the ancestors
3464 * of the context node consist of the parent of context node and the parent's
3465 * parent and so on; the nodes are ordered in reverse document order; thus the
3466 * parent is the first node on the axis, and the parent's parent is the second
3467 * node on the axis
3468 *
3469 * Returns the next element following that axis
3470 */
3471xmlNodePtr
3472xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3473 /*
3474 * the parent of an attribute or namespace node is the element
3475 * to which the attribute or namespace node is attached
3476 * !!!!!!!!!!!!!
3477 */
3478 if (cur == NULL) {
3479 if (ctxt->context->node == NULL) return(NULL);
3480 switch (ctxt->context->node->type) {
3481 case XML_ELEMENT_NODE:
3482 case XML_TEXT_NODE:
3483 case XML_CDATA_SECTION_NODE:
3484 case XML_ENTITY_REF_NODE:
3485 case XML_ENTITY_NODE:
3486 case XML_PI_NODE:
3487 case XML_COMMENT_NODE:
3488 case XML_DTD_NODE:
3489 case XML_ELEMENT_DECL:
3490 case XML_ATTRIBUTE_DECL:
3491 case XML_ENTITY_DECL:
3492 case XML_NOTATION_NODE:
3493 case XML_XINCLUDE_START:
3494 case XML_XINCLUDE_END:
3495 if (ctxt->context->node->parent == NULL)
3496 return((xmlNodePtr) ctxt->context->doc);
3497 return(ctxt->context->node->parent);
3498 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003499 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00003500
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003501 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003502 }
3503 case XML_DOCUMENT_NODE:
3504 case XML_DOCUMENT_TYPE_NODE:
3505 case XML_DOCUMENT_FRAG_NODE:
3506 case XML_HTML_DOCUMENT_NODE:
3507#ifdef LIBXML_SGML_ENABLED
3508 case XML_SGML_DOCUMENT_NODE:
3509#endif
3510 return(NULL);
3511 case XML_NAMESPACE_DECL:
3512 /*
3513 * TODO !!! may require extending struct _xmlNs with
3514 * parent field
3515 * C.f. Infoset case...
3516 */
3517 return(NULL);
3518 }
3519 return(NULL);
3520 }
3521 if (cur == ctxt->context->doc->children)
3522 return((xmlNodePtr) ctxt->context->doc);
3523 if (cur == (xmlNodePtr) ctxt->context->doc)
3524 return(NULL);
3525 switch (cur->type) {
3526 case XML_ELEMENT_NODE:
3527 case XML_TEXT_NODE:
3528 case XML_CDATA_SECTION_NODE:
3529 case XML_ENTITY_REF_NODE:
3530 case XML_ENTITY_NODE:
3531 case XML_PI_NODE:
3532 case XML_COMMENT_NODE:
3533 case XML_NOTATION_NODE:
3534 case XML_DTD_NODE:
3535 case XML_ELEMENT_DECL:
3536 case XML_ATTRIBUTE_DECL:
3537 case XML_ENTITY_DECL:
3538 case XML_XINCLUDE_START:
3539 case XML_XINCLUDE_END:
3540 return(cur->parent);
3541 case XML_ATTRIBUTE_NODE: {
3542 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3543
3544 return(att->parent);
3545 }
3546 case XML_DOCUMENT_NODE:
3547 case XML_DOCUMENT_TYPE_NODE:
3548 case XML_DOCUMENT_FRAG_NODE:
3549 case XML_HTML_DOCUMENT_NODE:
3550#ifdef LIBXML_SGML_ENABLED
3551 case XML_SGML_DOCUMENT_NODE:
3552#endif
3553 return(NULL);
3554 case XML_NAMESPACE_DECL:
3555 /*
3556 * TODO !!! may require extending struct _xmlNs with
3557 * parent field
3558 * C.f. Infoset case...
3559 */
3560 return(NULL);
3561 }
3562 return(NULL);
3563}
3564
3565/**
3566 * xmlXPathNextAncestorOrSelf:
3567 * @ctxt: the XPath Parser context
3568 * @cur: the current node in the traversal
3569 *
3570 * Traversal function for the "ancestor-or-self" direction
3571 * he ancestor-or-self axis contains the context node and ancestors of
3572 * the context node in reverse document order; thus the context node is
3573 * the first node on the axis, and the context node's parent the second;
3574 * parent here is defined the same as with the parent axis.
3575 *
3576 * Returns the next element following that axis
3577 */
3578xmlNodePtr
3579xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3580 if (cur == NULL)
3581 return(ctxt->context->node);
3582 return(xmlXPathNextAncestor(ctxt, cur));
3583}
3584
3585/**
3586 * xmlXPathNextFollowingSibling:
3587 * @ctxt: the XPath Parser context
3588 * @cur: the current node in the traversal
3589 *
3590 * Traversal function for the "following-sibling" direction
3591 * The following-sibling axis contains the following siblings of the context
3592 * node in document order.
3593 *
3594 * Returns the next element following that axis
3595 */
3596xmlNodePtr
3597xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3598 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3599 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3600 return(NULL);
3601 if (cur == (xmlNodePtr) ctxt->context->doc)
3602 return(NULL);
3603 if (cur == NULL)
3604 return(ctxt->context->node->next);
3605 return(cur->next);
3606}
3607
3608/**
3609 * xmlXPathNextPrecedingSibling:
3610 * @ctxt: the XPath Parser context
3611 * @cur: the current node in the traversal
3612 *
3613 * Traversal function for the "preceding-sibling" direction
3614 * The preceding-sibling axis contains the preceding siblings of the context
3615 * node in reverse document order; the first preceding sibling is first on the
3616 * axis; the sibling preceding that node is the second on the axis and so on.
3617 *
3618 * Returns the next element following that axis
3619 */
3620xmlNodePtr
3621xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3622 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3623 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3624 return(NULL);
3625 if (cur == (xmlNodePtr) ctxt->context->doc)
3626 return(NULL);
3627 if (cur == NULL)
3628 return(ctxt->context->node->prev);
3629 return(cur->prev);
3630}
3631
3632/**
3633 * xmlXPathNextFollowing:
3634 * @ctxt: the XPath Parser context
3635 * @cur: the current node in the traversal
3636 *
3637 * Traversal function for the "following" direction
3638 * The following axis contains all nodes in the same document as the context
3639 * node that are after the context node in document order, excluding any
3640 * descendants and excluding attribute nodes and namespace nodes; the nodes
3641 * are ordered in document order
3642 *
3643 * Returns the next element following that axis
3644 */
3645xmlNodePtr
3646xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3647 if (cur != NULL && cur->children != NULL)
3648 return cur->children ;
3649 if (cur == NULL) cur = ctxt->context->node;
3650 if (cur == NULL) return(NULL) ; /* ERROR */
3651 if (cur->next != NULL) return(cur->next) ;
3652 do {
3653 cur = cur->parent;
3654 if (cur == NULL) return(NULL);
3655 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
3656 if (cur->next != NULL) return(cur->next);
3657 } while (cur != NULL);
3658 return(cur);
3659}
3660
3661/*
3662 * xmlXPathIsAncestor:
3663 * @ancestor: the ancestor node
3664 * @node: the current node
3665 *
3666 * Check that @ancestor is a @node's ancestor
3667 *
3668 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
3669 */
3670static int
3671xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
3672 if ((ancestor == NULL) || (node == NULL)) return(0);
3673 /* nodes need to be in the same document */
3674 if (ancestor->doc != node->doc) return(0);
3675 /* avoid searching if ancestor or node is the root node */
3676 if (ancestor == (xmlNodePtr) node->doc) return(1);
3677 if (node == (xmlNodePtr) ancestor->doc) return(0);
3678 while (node->parent != NULL) {
3679 if (node->parent == ancestor)
3680 return(1);
3681 node = node->parent;
3682 }
3683 return(0);
3684}
3685
3686/**
3687 * xmlXPathNextPreceding:
3688 * @ctxt: the XPath Parser context
3689 * @cur: the current node in the traversal
3690 *
3691 * Traversal function for the "preceding" direction
3692 * the preceding axis contains all nodes in the same document as the context
3693 * node that are before the context node in document order, excluding any
3694 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
3695 * ordered in reverse document order
3696 *
3697 * Returns the next element following that axis
3698 */
3699xmlNodePtr
3700xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3701 if (cur == NULL)
3702 cur = ctxt->context->node ;
3703 do {
3704 if (cur->prev != NULL) {
3705 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
3706 ;
3707 return(cur) ;
3708 }
3709
3710 cur = cur->parent;
3711 if (cur == NULL) return(NULL);
3712 if (cur == ctxt->context->doc->children) return(NULL);
3713 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
3714 return(cur);
3715}
3716
3717/**
3718 * xmlXPathNextNamespace:
3719 * @ctxt: the XPath Parser context
3720 * @cur: the current attribute in the traversal
3721 *
3722 * Traversal function for the "namespace" direction
3723 * the namespace axis contains the namespace nodes of the context node;
3724 * the order of nodes on this axis is implementation-defined; the axis will
3725 * be empty unless the context node is an element
3726 *
3727 * Returns the next element following that axis
3728 */
3729xmlNodePtr
3730xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3731 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3732 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
3733 if (ctxt->context->namespaces != NULL)
3734 xmlFree(ctxt->context->namespaces);
3735 ctxt->context->namespaces =
3736 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
3737 if (ctxt->context->namespaces == NULL) return(NULL);
3738 ctxt->context->nsNr = 0;
3739 }
3740 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
3741}
3742
3743/**
3744 * xmlXPathNextAttribute:
3745 * @ctxt: the XPath Parser context
3746 * @cur: the current attribute in the traversal
3747 *
3748 * Traversal function for the "attribute" direction
3749 * TODO: support DTD inherited default attributes
3750 *
3751 * Returns the next element following that axis
3752 */
3753xmlNodePtr
3754xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3755 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3756 if (cur == NULL) {
3757 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3758 return(NULL);
3759 return((xmlNodePtr)ctxt->context->node->properties);
3760 }
3761 return((xmlNodePtr)cur->next);
3762}
3763
3764/************************************************************************
3765 * *
3766 * NodeTest Functions *
3767 * *
3768 ************************************************************************/
3769
Owen Taylor3473f882001-02-23 17:55:21 +00003770#define IS_FUNCTION 200
3771
Owen Taylor3473f882001-02-23 17:55:21 +00003772
3773/************************************************************************
3774 * *
3775 * Implicit tree core function library *
3776 * *
3777 ************************************************************************/
3778
3779/**
3780 * xmlXPathRoot:
3781 * @ctxt: the XPath Parser context
3782 *
3783 * Initialize the context to the root of the document
3784 */
3785void
3786xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
3787 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
3788 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3789}
3790
3791/************************************************************************
3792 * *
3793 * The explicit core function library *
3794 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
3795 * *
3796 ************************************************************************/
3797
3798
3799/**
3800 * xmlXPathLastFunction:
3801 * @ctxt: the XPath Parser context
3802 * @nargs: the number of arguments
3803 *
3804 * Implement the last() XPath function
3805 * number last()
3806 * The last function returns the number of nodes in the context node list.
3807 */
3808void
3809xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3810 CHECK_ARITY(0);
3811 if (ctxt->context->contextSize >= 0) {
3812 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
3813#ifdef DEBUG_EXPR
3814 xmlGenericError(xmlGenericErrorContext,
3815 "last() : %d\n", ctxt->context->contextSize);
3816#endif
3817 } else {
3818 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
3819 }
3820}
3821
3822/**
3823 * xmlXPathPositionFunction:
3824 * @ctxt: the XPath Parser context
3825 * @nargs: the number of arguments
3826 *
3827 * Implement the position() XPath function
3828 * number position()
3829 * The position function returns the position of the context node in the
3830 * context node list. The first position is 1, and so the last positionr
3831 * will be equal to last().
3832 */
3833void
3834xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3835 CHECK_ARITY(0);
3836 if (ctxt->context->proximityPosition >= 0) {
3837 valuePush(ctxt,
3838 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
3839#ifdef DEBUG_EXPR
3840 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
3841 ctxt->context->proximityPosition);
3842#endif
3843 } else {
3844 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
3845 }
3846}
3847
3848/**
3849 * xmlXPathCountFunction:
3850 * @ctxt: the XPath Parser context
3851 * @nargs: the number of arguments
3852 *
3853 * Implement the count() XPath function
3854 * number count(node-set)
3855 */
3856void
3857xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3858 xmlXPathObjectPtr cur;
3859
3860 CHECK_ARITY(1);
3861 if ((ctxt->value == NULL) ||
3862 ((ctxt->value->type != XPATH_NODESET) &&
3863 (ctxt->value->type != XPATH_XSLT_TREE)))
3864 XP_ERROR(XPATH_INVALID_TYPE);
3865 cur = valuePop(ctxt);
3866
3867 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
3868 xmlXPathFreeObject(cur);
3869}
3870
3871/**
3872 * xmlXPathIdFunction:
3873 * @ctxt: the XPath Parser context
3874 * @nargs: the number of arguments
3875 *
3876 * Implement the id() XPath function
3877 * node-set id(object)
3878 * The id function selects elements by their unique ID
3879 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
3880 * then the result is the union of the result of applying id to the
3881 * string value of each of the nodes in the argument node-set. When the
3882 * argument to id is of any other type, the argument is converted to a
3883 * string as if by a call to the string function; the string is split
3884 * into a whitespace-separated list of tokens (whitespace is any sequence
3885 * of characters matching the production S); the result is a node-set
3886 * containing the elements in the same document as the context node that
3887 * have a unique ID equal to any of the tokens in the list.
3888 */
3889void
3890xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3891 const xmlChar *tokens;
3892 const xmlChar *cur;
3893 xmlChar *ID;
3894 xmlAttrPtr attr;
3895 xmlNodePtr elem = NULL;
3896 xmlXPathObjectPtr ret, obj;
3897
3898 CHECK_ARITY(1);
3899 obj = valuePop(ctxt);
3900 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3901 if (obj->type == XPATH_NODESET) {
3902 xmlXPathObjectPtr newobj;
3903 int i;
3904
3905 ret = xmlXPathNewNodeSet(NULL);
3906
3907 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
3908 valuePush(ctxt,
3909 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
3910 xmlXPathStringFunction(ctxt, 1);
3911 xmlXPathIdFunction(ctxt, 1);
3912 newobj = valuePop(ctxt);
3913 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
3914 newobj->nodesetval);
3915 xmlXPathFreeObject(newobj);
3916 }
3917
3918 xmlXPathFreeObject(obj);
3919 valuePush(ctxt, ret);
3920 return;
3921 }
3922 if (obj->type != XPATH_STRING) {
3923 valuePush(ctxt, obj);
3924 xmlXPathStringFunction(ctxt, 1);
3925 obj = valuePop(ctxt);
3926 if (obj->type != XPATH_STRING) {
3927 xmlXPathFreeObject(obj);
3928 return;
3929 }
3930 }
3931 tokens = obj->stringval;
3932
3933 ret = xmlXPathNewNodeSet(NULL);
3934 valuePush(ctxt, ret);
3935 if (tokens == NULL) {
3936 xmlXPathFreeObject(obj);
3937 return;
3938 }
3939
3940 cur = tokens;
3941
3942 while (IS_BLANK(*cur)) cur++;
3943 while (*cur != 0) {
3944 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
3945 (*cur == '.') || (*cur == '-') ||
3946 (*cur == '_') || (*cur == ':') ||
3947 (IS_COMBINING(*cur)) ||
3948 (IS_EXTENDER(*cur)))
3949 cur++;
3950
3951 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
3952
3953 ID = xmlStrndup(tokens, cur - tokens);
3954 attr = xmlGetID(ctxt->context->doc, ID);
3955 if (attr != NULL) {
3956 elem = attr->parent;
3957 xmlXPathNodeSetAdd(ret->nodesetval, elem);
3958 }
3959 if (ID != NULL)
3960 xmlFree(ID);
3961
3962 while (IS_BLANK(*cur)) cur++;
3963 tokens = cur;
3964 }
3965 xmlXPathFreeObject(obj);
3966 return;
3967}
3968
3969/**
3970 * xmlXPathLocalNameFunction:
3971 * @ctxt: the XPath Parser context
3972 * @nargs: the number of arguments
3973 *
3974 * Implement the local-name() XPath function
3975 * string local-name(node-set?)
3976 * The local-name function returns a string containing the local part
3977 * of the name of the node in the argument node-set that is first in
3978 * document order. If the node-set is empty or the first node has no
3979 * name, an empty string is returned. If the argument is omitted it
3980 * defaults to the context node.
3981 */
3982void
3983xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3984 xmlXPathObjectPtr cur;
3985
3986 if (nargs == 0) {
3987 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3988 nargs = 1;
3989 }
3990
3991 CHECK_ARITY(1);
3992 if ((ctxt->value == NULL) ||
3993 ((ctxt->value->type != XPATH_NODESET) &&
3994 (ctxt->value->type != XPATH_XSLT_TREE)))
3995 XP_ERROR(XPATH_INVALID_TYPE);
3996 cur = valuePop(ctxt);
3997
3998 if (cur->nodesetval->nodeNr == 0) {
3999 valuePush(ctxt, xmlXPathNewCString(""));
4000 } else {
4001 int i = 0; /* Should be first in document order !!!!! */
4002 switch (cur->nodesetval->nodeTab[i]->type) {
4003 case XML_ELEMENT_NODE:
4004 case XML_ATTRIBUTE_NODE:
4005 case XML_PI_NODE:
4006 valuePush(ctxt,
4007 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4008 break;
4009 case XML_NAMESPACE_DECL:
4010 valuePush(ctxt, xmlXPathNewString(
4011 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4012 break;
4013 default:
4014 valuePush(ctxt, xmlXPathNewCString(""));
4015 }
4016 }
4017 xmlXPathFreeObject(cur);
4018}
4019
4020/**
4021 * xmlXPathNamespaceURIFunction:
4022 * @ctxt: the XPath Parser context
4023 * @nargs: the number of arguments
4024 *
4025 * Implement the namespace-uri() XPath function
4026 * string namespace-uri(node-set?)
4027 * The namespace-uri function returns a string containing the
4028 * namespace URI of the expanded name of the node in the argument
4029 * node-set that is first in document order. If the node-set is empty,
4030 * the first node has no name, or the expanded name has no namespace
4031 * URI, an empty string is returned. If the argument is omitted it
4032 * defaults to the context node.
4033 */
4034void
4035xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4036 xmlXPathObjectPtr cur;
4037
4038 if (nargs == 0) {
4039 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4040 nargs = 1;
4041 }
4042 CHECK_ARITY(1);
4043 if ((ctxt->value == NULL) ||
4044 ((ctxt->value->type != XPATH_NODESET) &&
4045 (ctxt->value->type != XPATH_XSLT_TREE)))
4046 XP_ERROR(XPATH_INVALID_TYPE);
4047 cur = valuePop(ctxt);
4048
4049 if (cur->nodesetval->nodeNr == 0) {
4050 valuePush(ctxt, xmlXPathNewCString(""));
4051 } else {
4052 int i = 0; /* Should be first in document order !!!!! */
4053 switch (cur->nodesetval->nodeTab[i]->type) {
4054 case XML_ELEMENT_NODE:
4055 case XML_ATTRIBUTE_NODE:
4056 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4057 valuePush(ctxt, xmlXPathNewCString(""));
4058 else
4059 valuePush(ctxt, xmlXPathNewString(
4060 cur->nodesetval->nodeTab[i]->ns->href));
4061 break;
4062 default:
4063 valuePush(ctxt, xmlXPathNewCString(""));
4064 }
4065 }
4066 xmlXPathFreeObject(cur);
4067}
4068
4069/**
4070 * xmlXPathNameFunction:
4071 * @ctxt: the XPath Parser context
4072 * @nargs: the number of arguments
4073 *
4074 * Implement the name() XPath function
4075 * string name(node-set?)
4076 * The name function returns a string containing a QName representing
4077 * the name of the node in the argument node-set that is first in documenti
4078 * order. The QName must represent the name with respect to the namespace
4079 * declarations in effect on the node whose name is being represented.
4080 * Typically, this will be the form in which the name occurred in the XML
4081 * source. This need not be the case if there are namespace declarations
4082 * in effect on the node that associate multiple prefixes with the same
4083 * namespace. However, an implementation may include information about
4084 * the original prefix in its representation of nodes; in this case, an
4085 * implementation can ensure that the returned string is always the same
4086 * as the QName used in the XML source. If the argument it omitted it
4087 * defaults to the context node.
4088 * Libxml keep the original prefix so the "real qualified name" used is
4089 * returned.
4090 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004091static void
Owen Taylor3473f882001-02-23 17:55:21 +00004092xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4093 xmlXPathObjectPtr cur;
4094
4095 if (nargs == 0) {
4096 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4097 nargs = 1;
4098 }
4099
4100 CHECK_ARITY(1);
4101 if ((ctxt->value == NULL) ||
4102 ((ctxt->value->type != XPATH_NODESET) &&
4103 (ctxt->value->type != XPATH_XSLT_TREE)))
4104 XP_ERROR(XPATH_INVALID_TYPE);
4105 cur = valuePop(ctxt);
4106
4107 if (cur->nodesetval->nodeNr == 0) {
4108 valuePush(ctxt, xmlXPathNewCString(""));
4109 } else {
4110 int i = 0; /* Should be first in document order !!!!! */
4111
4112 switch (cur->nodesetval->nodeTab[i]->type) {
4113 case XML_ELEMENT_NODE:
4114 case XML_ATTRIBUTE_NODE:
4115 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4116 valuePush(ctxt, xmlXPathNewString(
4117 cur->nodesetval->nodeTab[i]->name));
4118
4119 else {
4120 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004121 snprintf(name, sizeof(name), "%s:%s",
4122 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4123 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004124 name[sizeof(name) - 1] = 0;
4125 valuePush(ctxt, xmlXPathNewCString(name));
4126 }
4127 break;
4128 default:
4129 valuePush(ctxt,
4130 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4131 xmlXPathLocalNameFunction(ctxt, 1);
4132 }
4133 }
4134 xmlXPathFreeObject(cur);
4135}
4136
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004137
4138/**
4139 * xmlXPathConvertString:
4140 * @val: an XPath object
4141 *
4142 * Converts an existing object to its string() equivalent
4143 *
4144 * Returns the new object, the old one is freed (or the operation
4145 * is done directly on @val)
4146 */
4147xmlXPathObjectPtr
4148xmlXPathConvertString(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004149 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004150
4151 if (val == NULL)
4152 return(xmlXPathNewCString(""));
4153 switch (val->type) {
4154 case XPATH_UNDEFINED:
4155#ifdef DEBUG_EXPR
4156 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
4157#endif
4158 ret = xmlXPathNewCString("");
4159 break;
4160 case XPATH_XSLT_TREE:
4161 case XPATH_NODESET:
4162 if (val->nodesetval == NULL)
4163 ret = xmlXPathNewCString("");
4164 else if (val->nodesetval->nodeNr == 0) {
4165 ret = xmlXPathNewCString("");
4166 } else {
4167 xmlChar *res;
4168
4169 xmlXPathNodeSetSort(val->nodesetval);
4170 res = xmlNodeGetContent(val->nodesetval->nodeTab[0]);
4171 /* TODO: avoid allocating res to free it */
4172 ret = xmlXPathNewString(res);
4173 if (res != NULL)
4174 xmlFree(res);
4175 }
4176 break;
4177 case XPATH_STRING:
4178 return(val);
4179 case XPATH_BOOLEAN:
4180 if (val->boolval) ret = xmlXPathNewCString("true");
4181 else ret = xmlXPathNewCString("false");
4182 break;
4183 case XPATH_NUMBER: {
4184 char buf[100];
4185
4186 xmlXPathFormatNumber(val->floatval, buf, sizeof(buf));
4187 ret = xmlXPathNewCString(buf);
4188 break;
4189 }
4190 case XPATH_USERS:
4191 case XPATH_POINT:
4192 case XPATH_RANGE:
4193 case XPATH_LOCATIONSET:
4194 TODO
4195 ret = xmlXPathNewCString("");
4196 break;
4197 }
4198 xmlXPathFreeObject(val);
4199 return(ret);
4200}
4201
Owen Taylor3473f882001-02-23 17:55:21 +00004202/**
4203 * xmlXPathStringFunction:
4204 * @ctxt: the XPath Parser context
4205 * @nargs: the number of arguments
4206 *
4207 * Implement the string() XPath function
4208 * string string(object?)
4209 * he string function converts an object to a string as follows:
4210 * - A node-set is converted to a string by returning the value of
4211 * the node in the node-set that is first in document order.
4212 * If the node-set is empty, an empty string is returned.
4213 * - A number is converted to a string as follows
4214 * + NaN is converted to the string NaN
4215 * + positive zero is converted to the string 0
4216 * + negative zero is converted to the string 0
4217 * + positive infinity is converted to the string Infinity
4218 * + negative infinity is converted to the string -Infinity
4219 * + if the number is an integer, the number is represented in
4220 * decimal form as a Number with no decimal point and no leading
4221 * zeros, preceded by a minus sign (-) if the number is negative
4222 * + otherwise, the number is represented in decimal form as a
4223 * Number including a decimal point with at least one digit
4224 * before the decimal point and at least one digit after the
4225 * decimal point, preceded by a minus sign (-) if the number
4226 * is negative; there must be no leading zeros before the decimal
4227 * point apart possibly from the one required digit immediatelyi
4228 * before the decimal point; beyond the one required digit
4229 * after the decimal point there must be as many, but only as
4230 * many, more digits as are needed to uniquely distinguish the
4231 * number from all other IEEE 754 numeric values.
4232 * - The boolean false value is converted to the string false.
4233 * The boolean true value is converted to the string true.
4234 *
4235 * If the argument is omitted, it defaults to a node-set with the
4236 * context node as its only member.
4237 */
4238void
4239xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4240 xmlXPathObjectPtr cur;
4241
4242 if (nargs == 0) {
4243 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4244 nargs = 1;
4245 }
4246
4247 CHECK_ARITY(1);
4248 cur = valuePop(ctxt);
4249 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004250 cur = xmlXPathConvertString(cur);
4251 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004252}
4253
4254/**
4255 * xmlXPathStringLengthFunction:
4256 * @ctxt: the XPath Parser context
4257 * @nargs: the number of arguments
4258 *
4259 * Implement the string-length() XPath function
4260 * number string-length(string?)
4261 * The string-length returns the number of characters in the string
4262 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4263 * the context node converted to a string, in other words the value
4264 * of the context node.
4265 */
4266void
4267xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4268 xmlXPathObjectPtr cur;
4269
4270 if (nargs == 0) {
4271 if (ctxt->context->node == NULL) {
4272 valuePush(ctxt, xmlXPathNewFloat(0));
4273 } else {
4274 xmlChar *content;
4275
4276 content = xmlNodeGetContent(ctxt->context->node);
4277 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
4278 xmlFree(content);
4279 }
4280 return;
4281 }
4282 CHECK_ARITY(1);
4283 CAST_TO_STRING;
4284 CHECK_TYPE(XPATH_STRING);
4285 cur = valuePop(ctxt);
4286 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
4287 xmlXPathFreeObject(cur);
4288}
4289
4290/**
4291 * xmlXPathConcatFunction:
4292 * @ctxt: the XPath Parser context
4293 * @nargs: the number of arguments
4294 *
4295 * Implement the concat() XPath function
4296 * string concat(string, string, string*)
4297 * The concat function returns the concatenation of its arguments.
4298 */
4299void
4300xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4301 xmlXPathObjectPtr cur, newobj;
4302 xmlChar *tmp;
4303
4304 if (nargs < 2) {
4305 CHECK_ARITY(2);
4306 }
4307
4308 CAST_TO_STRING;
4309 cur = valuePop(ctxt);
4310 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4311 xmlXPathFreeObject(cur);
4312 return;
4313 }
4314 nargs--;
4315
4316 while (nargs > 0) {
4317 CAST_TO_STRING;
4318 newobj = valuePop(ctxt);
4319 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4320 xmlXPathFreeObject(newobj);
4321 xmlXPathFreeObject(cur);
4322 XP_ERROR(XPATH_INVALID_TYPE);
4323 }
4324 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4325 newobj->stringval = cur->stringval;
4326 cur->stringval = tmp;
4327
4328 xmlXPathFreeObject(newobj);
4329 nargs--;
4330 }
4331 valuePush(ctxt, cur);
4332}
4333
4334/**
4335 * xmlXPathContainsFunction:
4336 * @ctxt: the XPath Parser context
4337 * @nargs: the number of arguments
4338 *
4339 * Implement the contains() XPath function
4340 * boolean contains(string, string)
4341 * The contains function returns true if the first argument string
4342 * contains the second argument string, and otherwise returns false.
4343 */
4344void
4345xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4346 xmlXPathObjectPtr hay, needle;
4347
4348 CHECK_ARITY(2);
4349 CAST_TO_STRING;
4350 CHECK_TYPE(XPATH_STRING);
4351 needle = valuePop(ctxt);
4352 CAST_TO_STRING;
4353 hay = valuePop(ctxt);
4354 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4355 xmlXPathFreeObject(hay);
4356 xmlXPathFreeObject(needle);
4357 XP_ERROR(XPATH_INVALID_TYPE);
4358 }
4359 if (xmlStrstr(hay->stringval, needle->stringval))
4360 valuePush(ctxt, xmlXPathNewBoolean(1));
4361 else
4362 valuePush(ctxt, xmlXPathNewBoolean(0));
4363 xmlXPathFreeObject(hay);
4364 xmlXPathFreeObject(needle);
4365}
4366
4367/**
4368 * xmlXPathStartsWithFunction:
4369 * @ctxt: the XPath Parser context
4370 * @nargs: the number of arguments
4371 *
4372 * Implement the starts-with() XPath function
4373 * boolean starts-with(string, string)
4374 * The starts-with function returns true if the first argument string
4375 * starts with the second argument string, and otherwise returns false.
4376 */
4377void
4378xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4379 xmlXPathObjectPtr hay, needle;
4380 int n;
4381
4382 CHECK_ARITY(2);
4383 CAST_TO_STRING;
4384 CHECK_TYPE(XPATH_STRING);
4385 needle = valuePop(ctxt);
4386 CAST_TO_STRING;
4387 hay = valuePop(ctxt);
4388 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4389 xmlXPathFreeObject(hay);
4390 xmlXPathFreeObject(needle);
4391 XP_ERROR(XPATH_INVALID_TYPE);
4392 }
4393 n = xmlStrlen(needle->stringval);
4394 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4395 valuePush(ctxt, xmlXPathNewBoolean(0));
4396 else
4397 valuePush(ctxt, xmlXPathNewBoolean(1));
4398 xmlXPathFreeObject(hay);
4399 xmlXPathFreeObject(needle);
4400}
4401
4402/**
4403 * xmlXPathSubstringFunction:
4404 * @ctxt: the XPath Parser context
4405 * @nargs: the number of arguments
4406 *
4407 * Implement the substring() XPath function
4408 * string substring(string, number, number?)
4409 * The substring function returns the substring of the first argument
4410 * starting at the position specified in the second argument with
4411 * length specified in the third argument. For example,
4412 * substring("12345",2,3) returns "234". If the third argument is not
4413 * specified, it returns the substring starting at the position specified
4414 * in the second argument and continuing to the end of the string. For
4415 * example, substring("12345",2) returns "2345". More precisely, each
4416 * character in the string (see [3.6 Strings]) is considered to have a
4417 * numeric position: the position of the first character is 1, the position
4418 * of the second character is 2 and so on. The returned substring contains
4419 * those characters for which the position of the character is greater than
4420 * or equal to the second argument and, if the third argument is specified,
4421 * less than the sum of the second and third arguments; the comparisons
4422 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4423 * - substring("12345", 1.5, 2.6) returns "234"
4424 * - substring("12345", 0, 3) returns "12"
4425 * - substring("12345", 0 div 0, 3) returns ""
4426 * - substring("12345", 1, 0 div 0) returns ""
4427 * - substring("12345", -42, 1 div 0) returns "12345"
4428 * - substring("12345", -1 div 0, 1 div 0) returns ""
4429 */
4430void
4431xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4432 xmlXPathObjectPtr str, start, len;
4433 double le, in;
4434 int i, l;
4435 xmlChar *ret;
4436
4437 /*
4438 * Conformance needs to be checked !!!!!
4439 */
4440 if (nargs < 2) {
4441 CHECK_ARITY(2);
4442 }
4443 if (nargs > 3) {
4444 CHECK_ARITY(3);
4445 }
4446 if (nargs == 3) {
4447 CAST_TO_NUMBER;
4448 CHECK_TYPE(XPATH_NUMBER);
4449 len = valuePop(ctxt);
4450 le = len->floatval;
4451 xmlXPathFreeObject(len);
4452 } else {
4453 le = 2000000000;
4454 }
4455 CAST_TO_NUMBER;
4456 CHECK_TYPE(XPATH_NUMBER);
4457 start = valuePop(ctxt);
4458 in = start->floatval;
4459 xmlXPathFreeObject(start);
4460 CAST_TO_STRING;
4461 CHECK_TYPE(XPATH_STRING);
4462 str = valuePop(ctxt);
4463 le += in;
4464
4465 /* integer index of the first char */
4466 i = (int) in;
4467 if (((double)i) != in) i++;
4468
4469 /* integer index of the last char */
4470 l = (int) le;
4471 if (((double)l) != le) l++;
4472
4473 /* back to a zero based len */
4474 i--;
4475 l--;
4476
4477 /* check against the string len */
4478 if (l > 1024) {
4479 l = xmlStrlen(str->stringval);
4480 }
4481 if (i < 0) {
4482 i = 0;
4483 }
4484
4485 /* number of chars to copy */
4486 l -= i;
4487
4488 ret = xmlStrsub(str->stringval, i, l);
4489 if (ret == NULL)
4490 valuePush(ctxt, xmlXPathNewCString(""));
4491 else {
4492 valuePush(ctxt, xmlXPathNewString(ret));
4493 xmlFree(ret);
4494 }
4495 xmlXPathFreeObject(str);
4496}
4497
4498/**
4499 * xmlXPathSubstringBeforeFunction:
4500 * @ctxt: the XPath Parser context
4501 * @nargs: the number of arguments
4502 *
4503 * Implement the substring-before() XPath function
4504 * string substring-before(string, string)
4505 * The substring-before function returns the substring of the first
4506 * argument string that precedes the first occurrence of the second
4507 * argument string in the first argument string, or the empty string
4508 * if the first argument string does not contain the second argument
4509 * string. For example, substring-before("1999/04/01","/") returns 1999.
4510 */
4511void
4512xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4513 xmlXPathObjectPtr str;
4514 xmlXPathObjectPtr find;
4515 xmlBufferPtr target;
4516 const xmlChar *point;
4517 int offset;
4518
4519 CHECK_ARITY(2);
4520 CAST_TO_STRING;
4521 find = valuePop(ctxt);
4522 CAST_TO_STRING;
4523 str = valuePop(ctxt);
4524
4525 target = xmlBufferCreate();
4526 if (target) {
4527 point = xmlStrstr(str->stringval, find->stringval);
4528 if (point) {
4529 offset = (int)(point - str->stringval);
4530 xmlBufferAdd(target, str->stringval, offset);
4531 }
4532 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4533 xmlBufferFree(target);
4534 }
4535
4536 xmlXPathFreeObject(str);
4537 xmlXPathFreeObject(find);
4538}
4539
4540/**
4541 * xmlXPathSubstringAfterFunction:
4542 * @ctxt: the XPath Parser context
4543 * @nargs: the number of arguments
4544 *
4545 * Implement the substring-after() XPath function
4546 * string substring-after(string, string)
4547 * The substring-after function returns the substring of the first
4548 * argument string that follows the first occurrence of the second
4549 * argument string in the first argument string, or the empty stringi
4550 * if the first argument string does not contain the second argument
4551 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4552 * and substring-after("1999/04/01","19") returns 99/04/01.
4553 */
4554void
4555xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4556 xmlXPathObjectPtr str;
4557 xmlXPathObjectPtr find;
4558 xmlBufferPtr target;
4559 const xmlChar *point;
4560 int offset;
4561
4562 CHECK_ARITY(2);
4563 CAST_TO_STRING;
4564 find = valuePop(ctxt);
4565 CAST_TO_STRING;
4566 str = valuePop(ctxt);
4567
4568 target = xmlBufferCreate();
4569 if (target) {
4570 point = xmlStrstr(str->stringval, find->stringval);
4571 if (point) {
4572 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4573 xmlBufferAdd(target, &str->stringval[offset],
4574 xmlStrlen(str->stringval) - offset);
4575 }
4576 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4577 xmlBufferFree(target);
4578 }
4579
4580 xmlXPathFreeObject(str);
4581 xmlXPathFreeObject(find);
4582}
4583
4584/**
4585 * xmlXPathNormalizeFunction:
4586 * @ctxt: the XPath Parser context
4587 * @nargs: the number of arguments
4588 *
4589 * Implement the normalize-space() XPath function
4590 * string normalize-space(string?)
4591 * The normalize-space function returns the argument string with white
4592 * space normalized by stripping leading and trailing whitespace
4593 * and replacing sequences of whitespace characters by a single
4594 * space. Whitespace characters are the same allowed by the S production
4595 * in XML. If the argument is omitted, it defaults to the context
4596 * node converted to a string, in other words the value of the context node.
4597 */
4598void
4599xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4600 xmlXPathObjectPtr obj = NULL;
4601 xmlChar *source = NULL;
4602 xmlBufferPtr target;
4603 xmlChar blank;
4604
4605 if (nargs == 0) {
4606 /* Use current context node */
4607 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4608 xmlXPathStringFunction(ctxt, 1);
4609 nargs = 1;
4610 }
4611
4612 CHECK_ARITY(1);
4613 CAST_TO_STRING;
4614 CHECK_TYPE(XPATH_STRING);
4615 obj = valuePop(ctxt);
4616 source = obj->stringval;
4617
4618 target = xmlBufferCreate();
4619 if (target && source) {
4620
4621 /* Skip leading whitespaces */
4622 while (IS_BLANK(*source))
4623 source++;
4624
4625 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4626 blank = 0;
4627 while (*source) {
4628 if (IS_BLANK(*source)) {
4629 blank = *source;
4630 } else {
4631 if (blank) {
4632 xmlBufferAdd(target, &blank, 1);
4633 blank = 0;
4634 }
4635 xmlBufferAdd(target, source, 1);
4636 }
4637 source++;
4638 }
4639
4640 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4641 xmlBufferFree(target);
4642 }
4643 xmlXPathFreeObject(obj);
4644}
4645
4646/**
4647 * xmlXPathTranslateFunction:
4648 * @ctxt: the XPath Parser context
4649 * @nargs: the number of arguments
4650 *
4651 * Implement the translate() XPath function
4652 * string translate(string, string, string)
4653 * The translate function returns the first argument string with
4654 * occurrences of characters in the second argument string replaced
4655 * by the character at the corresponding position in the third argument
4656 * string. For example, translate("bar","abc","ABC") returns the string
4657 * BAr. If there is a character in the second argument string with no
4658 * character at a corresponding position in the third argument string
4659 * (because the second argument string is longer than the third argument
4660 * string), then occurrences of that character in the first argument
4661 * string are removed. For example, translate("--aaa--","abc-","ABC")
4662 * returns "AAA". If a character occurs more than once in second
4663 * argument string, then the first occurrence determines the replacement
4664 * character. If the third argument string is longer than the second
4665 * argument string, then excess characters are ignored.
4666 */
4667void
4668xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4669 xmlXPathObjectPtr str;
4670 xmlXPathObjectPtr from;
4671 xmlXPathObjectPtr to;
4672 xmlBufferPtr target;
4673 int i, offset, max;
4674 xmlChar ch;
4675 const xmlChar *point;
4676
4677 CHECK_ARITY(3);
4678
4679 CAST_TO_STRING;
4680 to = valuePop(ctxt);
4681 CAST_TO_STRING;
4682 from = valuePop(ctxt);
4683 CAST_TO_STRING;
4684 str = valuePop(ctxt);
4685
4686 target = xmlBufferCreate();
4687 if (target) {
4688 max = xmlStrlen(to->stringval);
4689 for (i = 0; (ch = str->stringval[i]); i++) {
4690 point = xmlStrchr(from->stringval, ch);
4691 if (point) {
4692 /* Warning: This may not work with UTF-8 */
4693 offset = (int)(point - from->stringval);
4694 if (offset < max)
4695 xmlBufferAdd(target, &to->stringval[offset], 1);
4696 } else
4697 xmlBufferAdd(target, &ch, 1);
4698 }
4699 }
4700 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4701 xmlBufferFree(target);
4702 xmlXPathFreeObject(str);
4703 xmlXPathFreeObject(from);
4704 xmlXPathFreeObject(to);
4705}
4706
4707/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004708 * xmlXPathConvertBoolean:
4709 * @val: an XPath object
4710 *
4711 * Converts an existing object to its boolean() equivalent
4712 *
4713 * Returns the new object, the old one is freed (or the operation
4714 * is done directly on @val)
4715 */
4716xmlXPathObjectPtr
4717xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4718 int res = 0;
4719
4720 if (val == NULL)
4721 return(NULL);
4722 switch (val->type) {
4723 case XPATH_NODESET:
4724 case XPATH_XSLT_TREE:
4725 if ((val->nodesetval == NULL) ||
4726 (val->nodesetval->nodeNr == 0)) res = 0;
4727 else
4728 res = 1;
4729 break;
4730 case XPATH_STRING:
4731 if ((val->stringval == NULL) ||
4732 (val->stringval[0] == 0)) res = 0;
4733 else
4734 res = 1;
4735 break;
4736 case XPATH_BOOLEAN:
4737 return(val);
4738 case XPATH_NUMBER:
4739 if (val->floatval) res = 1;
4740 break;
4741 default:
4742 STRANGE
4743 }
4744 xmlXPathFreeObject(val);
4745 return(xmlXPathNewBoolean(res));
4746}
4747
4748/**
Owen Taylor3473f882001-02-23 17:55:21 +00004749 * xmlXPathBooleanFunction:
4750 * @ctxt: the XPath Parser context
4751 * @nargs: the number of arguments
4752 *
4753 * Implement the boolean() XPath function
4754 * boolean boolean(object)
4755 * he boolean function converts its argument to a boolean as follows:
4756 * - a number is true if and only if it is neither positive or
4757 * negative zero nor NaN
4758 * - a node-set is true if and only if it is non-empty
4759 * - a string is true if and only if its length is non-zero
4760 */
4761void
4762xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4763 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00004764
4765 CHECK_ARITY(1);
4766 cur = valuePop(ctxt);
4767 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004768 cur = xmlXPathConvertBoolean(cur);
4769 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004770}
4771
4772/**
4773 * xmlXPathNotFunction:
4774 * @ctxt: the XPath Parser context
4775 * @nargs: the number of arguments
4776 *
4777 * Implement the not() XPath function
4778 * boolean not(boolean)
4779 * The not function returns true if its argument is false,
4780 * and false otherwise.
4781 */
4782void
4783xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4784 CHECK_ARITY(1);
4785 CAST_TO_BOOLEAN;
4786 CHECK_TYPE(XPATH_BOOLEAN);
4787 ctxt->value->boolval = ! ctxt->value->boolval;
4788}
4789
4790/**
4791 * xmlXPathTrueFunction:
4792 * @ctxt: the XPath Parser context
4793 * @nargs: the number of arguments
4794 *
4795 * Implement the true() XPath function
4796 * boolean true()
4797 */
4798void
4799xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4800 CHECK_ARITY(0);
4801 valuePush(ctxt, xmlXPathNewBoolean(1));
4802}
4803
4804/**
4805 * xmlXPathFalseFunction:
4806 * @ctxt: the XPath Parser context
4807 * @nargs: the number of arguments
4808 *
4809 * Implement the false() XPath function
4810 * boolean false()
4811 */
4812void
4813xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4814 CHECK_ARITY(0);
4815 valuePush(ctxt, xmlXPathNewBoolean(0));
4816}
4817
4818/**
4819 * xmlXPathLangFunction:
4820 * @ctxt: the XPath Parser context
4821 * @nargs: the number of arguments
4822 *
4823 * Implement the lang() XPath function
4824 * boolean lang(string)
4825 * The lang function returns true or false depending on whether the
4826 * language of the context node as specified by xml:lang attributes
4827 * is the same as or is a sublanguage of the language specified by
4828 * the argument string. The language of the context node is determined
4829 * by the value of the xml:lang attribute on the context node, or, if
4830 * the context node has no xml:lang attribute, by the value of the
4831 * xml:lang attribute on the nearest ancestor of the context node that
4832 * has an xml:lang attribute. If there is no such attribute, then lang
4833 * returns false. If there is such an attribute, then lang returns
4834 * true if the attribute value is equal to the argument ignoring case,
4835 * or if there is some suffix starting with - such that the attribute
4836 * value is equal to the argument ignoring that suffix of the attribute
4837 * value and ignoring case.
4838 */
4839void
4840xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4841 xmlXPathObjectPtr val;
4842 const xmlChar *theLang;
4843 const xmlChar *lang;
4844 int ret = 0;
4845 int i;
4846
4847 CHECK_ARITY(1);
4848 CAST_TO_STRING;
4849 CHECK_TYPE(XPATH_STRING);
4850 val = valuePop(ctxt);
4851 lang = val->stringval;
4852 theLang = xmlNodeGetLang(ctxt->context->node);
4853 if ((theLang != NULL) && (lang != NULL)) {
4854 for (i = 0;lang[i] != 0;i++)
4855 if (toupper(lang[i]) != toupper(theLang[i]))
4856 goto not_equal;
4857 ret = 1;
4858 }
4859not_equal:
4860 xmlXPathFreeObject(val);
4861 valuePush(ctxt, xmlXPathNewBoolean(ret));
4862}
4863
4864/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004865 * xmlXPathConvertNumber:
4866 * @val: an XPath object
4867 *
4868 * Converts an existing object to its number() equivalent
4869 *
4870 * Returns the new object, the old one is freed (or the operation
4871 * is done directly on @val)
4872 */
4873xmlXPathObjectPtr
4874xmlXPathConvertNumber(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004875 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004876 double res;
4877
4878 if (val == NULL)
4879 return(xmlXPathNewFloat(0.0));
4880 switch (val->type) {
4881 case XPATH_UNDEFINED:
4882#ifdef DEBUG_EXPR
4883 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
4884#endif
4885 ret = xmlXPathNewFloat(0.0);
4886 break;
4887 case XPATH_XSLT_TREE:
4888 case XPATH_NODESET:
4889 val = xmlXPathConvertString(val);
4890 /* no break on purpose */
4891 case XPATH_STRING:
4892 res = xmlXPathStringEvalNumber(val->stringval);
4893 ret = xmlXPathNewFloat(res);
4894 break;
4895 case XPATH_BOOLEAN:
4896 if (val->boolval) ret = xmlXPathNewFloat(1.0);
4897 else ret = xmlXPathNewFloat(0.0);
4898 break;
4899 case XPATH_NUMBER:
4900 return(val);
4901 case XPATH_USERS:
4902 case XPATH_POINT:
4903 case XPATH_RANGE:
4904 case XPATH_LOCATIONSET:
4905 TODO
4906 ret = xmlXPathNewFloat(0.0);
4907 break;
4908 }
4909 xmlXPathFreeObject(val);
4910 return(ret);
4911}
4912
4913/**
Owen Taylor3473f882001-02-23 17:55:21 +00004914 * xmlXPathNumberFunction:
4915 * @ctxt: the XPath Parser context
4916 * @nargs: the number of arguments
4917 *
4918 * Implement the number() XPath function
4919 * number number(object?)
4920 */
4921void
4922xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4923 xmlXPathObjectPtr cur;
4924 double res;
4925
4926 if (nargs == 0) {
4927 if (ctxt->context->node == NULL) {
4928 valuePush(ctxt, xmlXPathNewFloat(0.0));
4929 } else {
4930 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
4931
4932 res = xmlXPathStringEvalNumber(content);
4933 valuePush(ctxt, xmlXPathNewFloat(res));
4934 xmlFree(content);
4935 }
4936 return;
4937 }
4938
4939 CHECK_ARITY(1);
4940 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004941 cur = xmlXPathConvertNumber(cur);
4942 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004943}
4944
4945/**
4946 * xmlXPathSumFunction:
4947 * @ctxt: the XPath Parser context
4948 * @nargs: the number of arguments
4949 *
4950 * Implement the sum() XPath function
4951 * number sum(node-set)
4952 * The sum function returns the sum of the values of the nodes in
4953 * the argument node-set.
4954 */
4955void
4956xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4957 xmlXPathObjectPtr cur;
4958 int i;
4959
4960 CHECK_ARITY(1);
4961 if ((ctxt->value == NULL) ||
4962 ((ctxt->value->type != XPATH_NODESET) &&
4963 (ctxt->value->type != XPATH_XSLT_TREE)))
4964 XP_ERROR(XPATH_INVALID_TYPE);
4965 cur = valuePop(ctxt);
4966
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004967 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004968 valuePush(ctxt, xmlXPathNewFloat(0.0));
4969 } else {
4970 valuePush(ctxt,
4971 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
4972 xmlXPathNumberFunction(ctxt, 1);
4973 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
4974 valuePush(ctxt,
4975 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4976 xmlXPathAddValues(ctxt);
4977 }
4978 }
4979 xmlXPathFreeObject(cur);
4980}
4981
4982/**
4983 * xmlXPathFloorFunction:
4984 * @ctxt: the XPath Parser context
4985 * @nargs: the number of arguments
4986 *
4987 * Implement the floor() XPath function
4988 * number floor(number)
4989 * The floor function returns the largest (closest to positive infinity)
4990 * number that is not greater than the argument and that is an integer.
4991 */
4992void
4993xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4994 CHECK_ARITY(1);
4995 CAST_TO_NUMBER;
4996 CHECK_TYPE(XPATH_NUMBER);
4997#if 0
4998 ctxt->value->floatval = floor(ctxt->value->floatval);
4999#else
5000 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5001 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5002#endif
5003}
5004
5005/**
5006 * xmlXPathCeilingFunction:
5007 * @ctxt: the XPath Parser context
5008 * @nargs: the number of arguments
5009 *
5010 * Implement the ceiling() XPath function
5011 * number ceiling(number)
5012 * The ceiling function returns the smallest (closest to negative infinity)
5013 * number that is not less than the argument and that is an integer.
5014 */
5015void
5016xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5017 double f;
5018
5019 CHECK_ARITY(1);
5020 CAST_TO_NUMBER;
5021 CHECK_TYPE(XPATH_NUMBER);
5022
5023#if 0
5024 ctxt->value->floatval = ceil(ctxt->value->floatval);
5025#else
5026 f = (double)((int) ctxt->value->floatval);
5027 if (f != ctxt->value->floatval)
5028 ctxt->value->floatval = f + 1;
5029#endif
5030}
5031
5032/**
5033 * xmlXPathRoundFunction:
5034 * @ctxt: the XPath Parser context
5035 * @nargs: the number of arguments
5036 *
5037 * Implement the round() XPath function
5038 * number round(number)
5039 * The round function returns the number that is closest to the
5040 * argument and that is an integer. If there are two such numbers,
5041 * then the one that is even is returned.
5042 */
5043void
5044xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5045 double f;
5046
5047 CHECK_ARITY(1);
5048 CAST_TO_NUMBER;
5049 CHECK_TYPE(XPATH_NUMBER);
5050
5051 if ((ctxt->value->floatval == xmlXPathNAN) ||
5052 (ctxt->value->floatval == xmlXPathPINF) ||
5053 (ctxt->value->floatval == xmlXPathNINF) ||
5054 (ctxt->value->floatval == 0.0))
5055 return;
5056
5057#if 0
5058 f = floor(ctxt->value->floatval);
5059#else
5060 f = (double)((int) ctxt->value->floatval);
5061#endif
5062 if (ctxt->value->floatval < f + 0.5)
5063 ctxt->value->floatval = f;
5064 else
5065 ctxt->value->floatval = f + 1;
5066}
5067
5068/************************************************************************
5069 * *
5070 * The Parser *
5071 * *
5072 ************************************************************************/
5073
5074/*
5075 * a couple of forward declarations since we use a recursive call based
5076 * implementation.
5077 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005078static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005079static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005080static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005081#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005082static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5083#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005084#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005085static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005086#endif
5087
5088/**
5089 * xmlXPathParseNCName:
5090 * @ctxt: the XPath Parser context
5091 *
5092 * parse an XML namespace non qualified name.
5093 *
5094 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5095 *
5096 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5097 * CombiningChar | Extender
5098 *
5099 * Returns the namespace name or NULL
5100 */
5101
5102xmlChar *
5103xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
5104 const xmlChar *q;
5105 xmlChar *ret = NULL;
5106
5107 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
5108 q = NEXT;
5109
5110 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
5111 (CUR == '.') || (CUR == '-') ||
5112 (CUR == '_') ||
5113 (IS_COMBINING(CUR)) ||
5114 (IS_EXTENDER(CUR)))
5115 NEXT;
5116
5117 ret = xmlStrndup(q, CUR_PTR - q);
5118
5119 return(ret);
5120}
5121
5122/**
5123 * xmlXPathParseQName:
5124 * @ctxt: the XPath Parser context
5125 * @prefix: a xmlChar **
5126 *
5127 * parse an XML qualified name
5128 *
5129 * [NS 5] QName ::= (Prefix ':')? LocalPart
5130 *
5131 * [NS 6] Prefix ::= NCName
5132 *
5133 * [NS 7] LocalPart ::= NCName
5134 *
5135 * Returns the function returns the local part, and prefix is updated
5136 * to get the Prefix if any.
5137 */
5138
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005139static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005140xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5141 xmlChar *ret = NULL;
5142
5143 *prefix = NULL;
5144 ret = xmlXPathParseNCName(ctxt);
5145 if (CUR == ':') {
5146 *prefix = ret;
5147 NEXT;
5148 ret = xmlXPathParseNCName(ctxt);
5149 }
5150 return(ret);
5151}
5152
5153/**
5154 * xmlXPathParseName:
5155 * @ctxt: the XPath Parser context
5156 *
5157 * parse an XML name
5158 *
5159 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5160 * CombiningChar | Extender
5161 *
5162 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5163 *
5164 * Returns the namespace name or NULL
5165 */
5166
5167xmlChar *
5168xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
5169 const xmlChar *q;
5170 xmlChar *ret = NULL;
5171
5172 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
5173 q = NEXT;
5174
5175 /* TODO Make this UTF8 compliant !!! */
5176 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
5177 (CUR == '.') || (CUR == '-') ||
5178 (CUR == '_') || (CUR == ':') ||
5179 (IS_COMBINING(CUR)) ||
5180 (IS_EXTENDER(CUR)))
5181 NEXT;
5182
5183 ret = xmlStrndup(q, CUR_PTR - q);
5184
5185 return(ret);
5186}
5187
5188/**
5189 * xmlXPathStringEvalNumber:
5190 * @str: A string to scan
5191 *
5192 * [30] Number ::= Digits ('.' Digits?)?
5193 * | '.' Digits
5194 * [31] Digits ::= [0-9]+
5195 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005196 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005197 * In complement of the Number expression, this function also handles
5198 * negative values : '-' Number.
5199 *
5200 * Returns the double value.
5201 */
5202double
5203xmlXPathStringEvalNumber(const xmlChar *str) {
5204 const xmlChar *cur = str;
5205 double ret = 0.0;
5206 double mult = 1;
5207 int ok = 0;
5208 int isneg = 0;
5209
5210 while (IS_BLANK(*cur)) cur++;
5211 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5212 return(xmlXPathNAN);
5213 }
5214 if (*cur == '-') {
5215 isneg = 1;
5216 cur++;
5217 }
5218 while ((*cur >= '0') && (*cur <= '9')) {
5219 ret = ret * 10 + (*cur - '0');
5220 ok = 1;
5221 cur++;
5222 }
5223 if (*cur == '.') {
5224 cur++;
5225 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5226 return(xmlXPathNAN);
5227 }
5228 while ((*cur >= '0') && (*cur <= '9')) {
5229 mult /= 10;
5230 ret = ret + (*cur - '0') * mult;
5231 cur++;
5232 }
5233 }
5234 while (IS_BLANK(*cur)) cur++;
5235 if (*cur != 0) return(xmlXPathNAN);
5236 if (isneg) ret = -ret;
5237 return(ret);
5238}
5239
5240/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005241 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005242 * @ctxt: the XPath Parser context
5243 *
5244 * [30] Number ::= Digits ('.' Digits?)?
5245 * | '.' Digits
5246 * [31] Digits ::= [0-9]+
5247 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005248 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005249 *
5250 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005251static void
5252xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005253 double ret = 0.0;
5254 double mult = 1;
5255 int ok = 0;
5256
5257 CHECK_ERROR;
5258 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5259 XP_ERROR(XPATH_NUMBER_ERROR);
5260 }
5261 while ((CUR >= '0') && (CUR <= '9')) {
5262 ret = ret * 10 + (CUR - '0');
5263 ok = 1;
5264 NEXT;
5265 }
5266 if (CUR == '.') {
5267 NEXT;
5268 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5269 XP_ERROR(XPATH_NUMBER_ERROR);
5270 }
5271 while ((CUR >= '0') && (CUR <= '9')) {
5272 mult /= 10;
5273 ret = ret + (CUR - '0') * mult;
5274 NEXT;
5275 }
5276 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005277 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5278 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005279}
5280
5281/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005282 * xmlXPathParseLiteral:
5283 * @ctxt: the XPath Parser context
5284 *
5285 * Parse a Literal
5286 *
5287 * [29] Literal ::= '"' [^"]* '"'
5288 * | "'" [^']* "'"
5289 *
5290 * Returns the value found or NULL in case of error
5291 */
5292static xmlChar *
5293xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5294 const xmlChar *q;
5295 xmlChar *ret = NULL;
5296
5297 if (CUR == '"') {
5298 NEXT;
5299 q = CUR_PTR;
5300 while ((IS_CHAR(CUR)) && (CUR != '"'))
5301 NEXT;
5302 if (!IS_CHAR(CUR)) {
5303 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5304 } else {
5305 ret = xmlStrndup(q, CUR_PTR - q);
5306 NEXT;
5307 }
5308 } else if (CUR == '\'') {
5309 NEXT;
5310 q = CUR_PTR;
5311 while ((IS_CHAR(CUR)) && (CUR != '\''))
5312 NEXT;
5313 if (!IS_CHAR(CUR)) {
5314 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5315 } else {
5316 ret = xmlStrndup(q, CUR_PTR - q);
5317 NEXT;
5318 }
5319 } else {
5320 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5321 }
5322 return(ret);
5323}
5324
5325/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005326 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005327 * @ctxt: the XPath Parser context
5328 *
5329 * Parse a Literal and push it on the stack.
5330 *
5331 * [29] Literal ::= '"' [^"]* '"'
5332 * | "'" [^']* "'"
5333 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005334 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005335 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005336static void
5337xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005338 const xmlChar *q;
5339 xmlChar *ret = NULL;
5340
5341 if (CUR == '"') {
5342 NEXT;
5343 q = CUR_PTR;
5344 while ((IS_CHAR(CUR)) && (CUR != '"'))
5345 NEXT;
5346 if (!IS_CHAR(CUR)) {
5347 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5348 } else {
5349 ret = xmlStrndup(q, CUR_PTR - q);
5350 NEXT;
5351 }
5352 } else if (CUR == '\'') {
5353 NEXT;
5354 q = CUR_PTR;
5355 while ((IS_CHAR(CUR)) && (CUR != '\''))
5356 NEXT;
5357 if (!IS_CHAR(CUR)) {
5358 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5359 } else {
5360 ret = xmlStrndup(q, CUR_PTR - q);
5361 NEXT;
5362 }
5363 } else {
5364 XP_ERROR(XPATH_START_LITERAL_ERROR);
5365 }
5366 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005367 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5368 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005369 xmlFree(ret);
5370}
5371
5372/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005373 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005374 * @ctxt: the XPath Parser context
5375 *
5376 * Parse a VariableReference, evaluate it and push it on the stack.
5377 *
5378 * The variable bindings consist of a mapping from variable names
5379 * to variable values. The value of a variable is an object, which
5380 * of any of the types that are possible for the value of an expression,
5381 * and may also be of additional types not specified here.
5382 *
5383 * Early evaluation is possible since:
5384 * The variable bindings [...] used to evaluate a subexpression are
5385 * always the same as those used to evaluate the containing expression.
5386 *
5387 * [36] VariableReference ::= '$' QName
5388 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005389static void
5390xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005391 xmlChar *name;
5392 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005393
5394 SKIP_BLANKS;
5395 if (CUR != '$') {
5396 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5397 }
5398 NEXT;
5399 name = xmlXPathParseQName(ctxt, &prefix);
5400 if (name == NULL) {
5401 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5402 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005403 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005404 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5405 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005406 SKIP_BLANKS;
5407}
5408
5409/**
5410 * xmlXPathIsNodeType:
5411 * @ctxt: the XPath Parser context
5412 * @name: a name string
5413 *
5414 * Is the name given a NodeType one.
5415 *
5416 * [38] NodeType ::= 'comment'
5417 * | 'text'
5418 * | 'processing-instruction'
5419 * | 'node'
5420 *
5421 * Returns 1 if true 0 otherwise
5422 */
5423int
5424xmlXPathIsNodeType(const xmlChar *name) {
5425 if (name == NULL)
5426 return(0);
5427
5428 if (xmlStrEqual(name, BAD_CAST "comment"))
5429 return(1);
5430 if (xmlStrEqual(name, BAD_CAST "text"))
5431 return(1);
5432 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5433 return(1);
5434 if (xmlStrEqual(name, BAD_CAST "node"))
5435 return(1);
5436 return(0);
5437}
5438
5439/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005440 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005441 * @ctxt: the XPath Parser context
5442 *
5443 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5444 * [17] Argument ::= Expr
5445 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005446 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00005447 * pushed on the stack
5448 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005449static void
5450xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005451 xmlChar *name;
5452 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005453 int nbargs = 0;
5454
5455 name = xmlXPathParseQName(ctxt, &prefix);
5456 if (name == NULL) {
5457 XP_ERROR(XPATH_EXPR_ERROR);
5458 }
5459 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005460#ifdef DEBUG_EXPR
5461 if (prefix == NULL)
5462 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5463 name);
5464 else
5465 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5466 prefix, name);
5467#endif
5468
Owen Taylor3473f882001-02-23 17:55:21 +00005469 if (CUR != '(') {
5470 XP_ERROR(XPATH_EXPR_ERROR);
5471 }
5472 NEXT;
5473 SKIP_BLANKS;
5474
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005475 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005476 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005477 int op1 = ctxt->comp->last;
5478 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005479 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005480 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005481 nbargs++;
5482 if (CUR == ')') break;
5483 if (CUR != ',') {
5484 XP_ERROR(XPATH_EXPR_ERROR);
5485 }
5486 NEXT;
5487 SKIP_BLANKS;
5488 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005489 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
5490 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005491 NEXT;
5492 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005493}
5494
5495/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005496 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005497 * @ctxt: the XPath Parser context
5498 *
5499 * [15] PrimaryExpr ::= VariableReference
5500 * | '(' Expr ')'
5501 * | Literal
5502 * | Number
5503 * | FunctionCall
5504 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005505 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005506 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005507static void
5508xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005509 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005510 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005511 else if (CUR == '(') {
5512 NEXT;
5513 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005514 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005515 if (CUR != ')') {
5516 XP_ERROR(XPATH_EXPR_ERROR);
5517 }
5518 NEXT;
5519 SKIP_BLANKS;
5520 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005521 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005522 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005523 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005524 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005525 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005526 }
5527 SKIP_BLANKS;
5528}
5529
5530/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005531 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005532 * @ctxt: the XPath Parser context
5533 *
5534 * [20] FilterExpr ::= PrimaryExpr
5535 * | FilterExpr Predicate
5536 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005537 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005538 * Square brackets are used to filter expressions in the same way that
5539 * they are used in location paths. It is an error if the expression to
5540 * be filtered does not evaluate to a node-set. The context node list
5541 * used for evaluating the expression in square brackets is the node-set
5542 * to be filtered listed in document order.
5543 */
5544
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005545static void
5546xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
5547 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005548 CHECK_ERROR;
5549 SKIP_BLANKS;
5550
5551 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005552 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00005553 SKIP_BLANKS;
5554 }
5555
5556
5557}
5558
5559/**
5560 * xmlXPathScanName:
5561 * @ctxt: the XPath Parser context
5562 *
5563 * Trickery: parse an XML name but without consuming the input flow
5564 * Needed to avoid insanity in the parser state.
5565 *
5566 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5567 * CombiningChar | Extender
5568 *
5569 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5570 *
5571 * [6] Names ::= Name (S Name)*
5572 *
5573 * Returns the Name parsed or NULL
5574 */
5575
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005576static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005577xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
5578 xmlChar buf[XML_MAX_NAMELEN];
5579 int len = 0;
5580
5581 SKIP_BLANKS;
5582 if (!IS_LETTER(CUR) && (CUR != '_') &&
5583 (CUR != ':')) {
5584 return(NULL);
5585 }
5586
5587 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5588 (NXT(len) == '.') || (NXT(len) == '-') ||
5589 (NXT(len) == '_') || (NXT(len) == ':') ||
5590 (IS_COMBINING(NXT(len))) ||
5591 (IS_EXTENDER(NXT(len)))) {
5592 buf[len] = NXT(len);
5593 len++;
5594 if (len >= XML_MAX_NAMELEN) {
5595 xmlGenericError(xmlGenericErrorContext,
5596 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5597 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5598 (NXT(len) == '.') || (NXT(len) == '-') ||
5599 (NXT(len) == '_') || (NXT(len) == ':') ||
5600 (IS_COMBINING(NXT(len))) ||
5601 (IS_EXTENDER(NXT(len))))
5602 len++;
5603 break;
5604 }
5605 }
5606 return(xmlStrndup(buf, len));
5607}
5608
5609/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005610 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005611 * @ctxt: the XPath Parser context
5612 *
5613 * [19] PathExpr ::= LocationPath
5614 * | FilterExpr
5615 * | FilterExpr '/' RelativeLocationPath
5616 * | FilterExpr '//' RelativeLocationPath
5617 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005618 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005619 * The / operator and // operators combine an arbitrary expression
5620 * and a relative location path. It is an error if the expression
5621 * does not evaluate to a node-set.
5622 * The / operator does composition in the same way as when / is
5623 * used in a location path. As in location paths, // is short for
5624 * /descendant-or-self::node()/.
5625 */
5626
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005627static void
5628xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005629 int lc = 1; /* Should we branch to LocationPath ? */
5630 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5631
5632 SKIP_BLANKS;
5633 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5634 (CUR == '\'') || (CUR == '"')) {
5635 lc = 0;
5636 } else if (CUR == '*') {
5637 /* relative or absolute location path */
5638 lc = 1;
5639 } else if (CUR == '/') {
5640 /* relative or absolute location path */
5641 lc = 1;
5642 } else if (CUR == '@') {
5643 /* relative abbreviated attribute location path */
5644 lc = 1;
5645 } else if (CUR == '.') {
5646 /* relative abbreviated attribute location path */
5647 lc = 1;
5648 } else {
5649 /*
5650 * Problem is finding if we have a name here whether it's:
5651 * - a nodetype
5652 * - a function call in which case it's followed by '('
5653 * - an axis in which case it's followed by ':'
5654 * - a element name
5655 * We do an a priori analysis here rather than having to
5656 * maintain parsed token content through the recursive function
5657 * calls. This looks uglier but makes the code quite easier to
5658 * read/write/debug.
5659 */
5660 SKIP_BLANKS;
5661 name = xmlXPathScanName(ctxt);
5662 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
5663#ifdef DEBUG_STEP
5664 xmlGenericError(xmlGenericErrorContext,
5665 "PathExpr: Axis\n");
5666#endif
5667 lc = 1;
5668 xmlFree(name);
5669 } else if (name != NULL) {
5670 int len =xmlStrlen(name);
5671 int blank = 0;
5672
5673
5674 while (NXT(len) != 0) {
5675 if (NXT(len) == '/') {
5676 /* element name */
5677#ifdef DEBUG_STEP
5678 xmlGenericError(xmlGenericErrorContext,
5679 "PathExpr: AbbrRelLocation\n");
5680#endif
5681 lc = 1;
5682 break;
5683 } else if (IS_BLANK(NXT(len))) {
5684 /* skip to next */
5685 blank = 1;
5686 } else if (NXT(len) == ':') {
5687#ifdef DEBUG_STEP
5688 xmlGenericError(xmlGenericErrorContext,
5689 "PathExpr: AbbrRelLocation\n");
5690#endif
5691 lc = 1;
5692 break;
5693 } else if ((NXT(len) == '(')) {
5694 /* Note Type or Function */
5695 if (xmlXPathIsNodeType(name)) {
5696#ifdef DEBUG_STEP
5697 xmlGenericError(xmlGenericErrorContext,
5698 "PathExpr: Type search\n");
5699#endif
5700 lc = 1;
5701 } else {
5702#ifdef DEBUG_STEP
5703 xmlGenericError(xmlGenericErrorContext,
5704 "PathExpr: function call\n");
5705#endif
5706 lc = 0;
5707 }
5708 break;
5709 } else if ((NXT(len) == '[')) {
5710 /* element name */
5711#ifdef DEBUG_STEP
5712 xmlGenericError(xmlGenericErrorContext,
5713 "PathExpr: AbbrRelLocation\n");
5714#endif
5715 lc = 1;
5716 break;
5717 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5718 (NXT(len) == '=')) {
5719 lc = 1;
5720 break;
5721 } else {
5722 lc = 1;
5723 break;
5724 }
5725 len++;
5726 }
5727 if (NXT(len) == 0) {
5728#ifdef DEBUG_STEP
5729 xmlGenericError(xmlGenericErrorContext,
5730 "PathExpr: AbbrRelLocation\n");
5731#endif
5732 /* element name */
5733 lc = 1;
5734 }
5735 xmlFree(name);
5736 } else {
5737 /* make sure all cases are covered explicitely */
5738 XP_ERROR(XPATH_EXPR_ERROR);
5739 }
5740 }
5741
5742 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005743 if (CUR == '/') {
5744 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
5745 } else {
5746 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005747 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005748 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005749 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005750 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005751 CHECK_ERROR;
5752 if ((CUR == '/') && (NXT(1) == '/')) {
5753 SKIP(2);
5754 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005755
5756 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
5757 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5758 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
5759
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005760 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005761 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005762 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005763 }
5764 }
5765 SKIP_BLANKS;
5766}
5767
5768/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005769 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005770 * @ctxt: the XPath Parser context
5771 *
5772 * [18] UnionExpr ::= PathExpr
5773 * | UnionExpr '|' PathExpr
5774 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005775 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005776 */
5777
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005778static void
5779xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
5780 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005781 CHECK_ERROR;
5782 SKIP_BLANKS;
5783 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005784 int op1 = ctxt->comp->last;
5785 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005786
5787 NEXT;
5788 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005789 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005790
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005791 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
5792
Owen Taylor3473f882001-02-23 17:55:21 +00005793 SKIP_BLANKS;
5794 }
Owen Taylor3473f882001-02-23 17:55:21 +00005795}
5796
5797/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005798 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005799 * @ctxt: the XPath Parser context
5800 *
5801 * [27] UnaryExpr ::= UnionExpr
5802 * | '-' UnaryExpr
5803 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005804 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005805 */
5806
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005807static void
5808xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005809 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005810 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005811
5812 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00005813 while (CUR == '-') {
5814 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005815 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005816 NEXT;
5817 SKIP_BLANKS;
5818 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005819
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005820 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005821 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005822 if (found) {
5823 if (minus)
5824 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
5825 else
5826 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005827 }
5828}
5829
5830/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005831 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005832 * @ctxt: the XPath Parser context
5833 *
5834 * [26] MultiplicativeExpr ::= UnaryExpr
5835 * | MultiplicativeExpr MultiplyOperator UnaryExpr
5836 * | MultiplicativeExpr 'div' UnaryExpr
5837 * | MultiplicativeExpr 'mod' UnaryExpr
5838 * [34] MultiplyOperator ::= '*'
5839 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005840 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005841 */
5842
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005843static void
5844xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
5845 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005846 CHECK_ERROR;
5847 SKIP_BLANKS;
5848 while ((CUR == '*') ||
5849 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
5850 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
5851 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005852 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005853
5854 if (CUR == '*') {
5855 op = 0;
5856 NEXT;
5857 } else if (CUR == 'd') {
5858 op = 1;
5859 SKIP(3);
5860 } else if (CUR == 'm') {
5861 op = 2;
5862 SKIP(3);
5863 }
5864 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005865 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005866 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005867 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005868 SKIP_BLANKS;
5869 }
5870}
5871
5872/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005873 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005874 * @ctxt: the XPath Parser context
5875 *
5876 * [25] AdditiveExpr ::= MultiplicativeExpr
5877 * | AdditiveExpr '+' MultiplicativeExpr
5878 * | AdditiveExpr '-' MultiplicativeExpr
5879 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005880 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005881 */
5882
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005883static void
5884xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005885
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005886 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005887 CHECK_ERROR;
5888 SKIP_BLANKS;
5889 while ((CUR == '+') || (CUR == '-')) {
5890 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005891 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005892
5893 if (CUR == '+') plus = 1;
5894 else plus = 0;
5895 NEXT;
5896 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005897 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005898 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005899 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005900 SKIP_BLANKS;
5901 }
5902}
5903
5904/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005905 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005906 * @ctxt: the XPath Parser context
5907 *
5908 * [24] RelationalExpr ::= AdditiveExpr
5909 * | RelationalExpr '<' AdditiveExpr
5910 * | RelationalExpr '>' AdditiveExpr
5911 * | RelationalExpr '<=' AdditiveExpr
5912 * | RelationalExpr '>=' AdditiveExpr
5913 *
5914 * A <= B > C is allowed ? Answer from James, yes with
5915 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
5916 * which is basically what got implemented.
5917 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005918 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00005919 * on the stack
5920 */
5921
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005922static void
5923xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
5924 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005925 CHECK_ERROR;
5926 SKIP_BLANKS;
5927 while ((CUR == '<') ||
5928 (CUR == '>') ||
5929 ((CUR == '<') && (NXT(1) == '=')) ||
5930 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005931 int inf, strict;
5932 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005933
5934 if (CUR == '<') inf = 1;
5935 else inf = 0;
5936 if (NXT(1) == '=') strict = 0;
5937 else strict = 1;
5938 NEXT;
5939 if (!strict) NEXT;
5940 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005941 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005942 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005943 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00005944 SKIP_BLANKS;
5945 }
5946}
5947
5948/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005949 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005950 * @ctxt: the XPath Parser context
5951 *
5952 * [23] EqualityExpr ::= RelationalExpr
5953 * | EqualityExpr '=' RelationalExpr
5954 * | EqualityExpr '!=' RelationalExpr
5955 *
5956 * A != B != C is allowed ? Answer from James, yes with
5957 * (RelationalExpr = RelationalExpr) = RelationalExpr
5958 * (RelationalExpr != RelationalExpr) != RelationalExpr
5959 * which is basically what got implemented.
5960 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005961 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005962 *
5963 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005964static void
5965xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
5966 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005967 CHECK_ERROR;
5968 SKIP_BLANKS;
5969 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005970 int eq;
5971 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005972
5973 if (CUR == '=') eq = 1;
5974 else eq = 0;
5975 NEXT;
5976 if (!eq) NEXT;
5977 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005978 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005979 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005980 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005981 SKIP_BLANKS;
5982 }
5983}
5984
5985/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005986 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005987 * @ctxt: the XPath Parser context
5988 *
5989 * [22] AndExpr ::= EqualityExpr
5990 * | AndExpr 'and' EqualityExpr
5991 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005992 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005993 *
5994 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005995static void
5996xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
5997 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005998 CHECK_ERROR;
5999 SKIP_BLANKS;
6000 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006001 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006002 SKIP(3);
6003 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006004 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006005 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006006 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006007 SKIP_BLANKS;
6008 }
6009}
6010
6011/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006012 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006013 * @ctxt: the XPath Parser context
6014 *
6015 * [14] Expr ::= OrExpr
6016 * [21] OrExpr ::= AndExpr
6017 * | OrExpr 'or' AndExpr
6018 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006019 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006020 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006021static void
6022xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6023 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006024 CHECK_ERROR;
6025 SKIP_BLANKS;
6026 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006027 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006028 SKIP(2);
6029 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006030 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006031 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006032 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6033 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006034 SKIP_BLANKS;
6035 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006036 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6037 /* more ops could be optimized too */
6038 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6039 }
Owen Taylor3473f882001-02-23 17:55:21 +00006040}
6041
6042/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006043 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006044 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006045 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006046 *
6047 * [8] Predicate ::= '[' PredicateExpr ']'
6048 * [9] PredicateExpr ::= Expr
6049 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006050 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006051 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006052static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006053xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006054 int op1 = ctxt->comp->last;
6055
6056 SKIP_BLANKS;
6057 if (CUR != '[') {
6058 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6059 }
6060 NEXT;
6061 SKIP_BLANKS;
6062
6063 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006064 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006065 CHECK_ERROR;
6066
6067 if (CUR != ']') {
6068 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6069 }
6070
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006071 if (filter)
6072 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6073 else
6074 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006075
6076 NEXT;
6077 SKIP_BLANKS;
6078}
6079
6080/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006081 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006082 * @ctxt: the XPath Parser context
6083 * @test: pointer to a xmlXPathTestVal
6084 * @type: pointer to a xmlXPathTypeVal
6085 * @prefix: placeholder for a possible name prefix
6086 *
6087 * [7] NodeTest ::= NameTest
6088 * | NodeType '(' ')'
6089 * | 'processing-instruction' '(' Literal ')'
6090 *
6091 * [37] NameTest ::= '*'
6092 * | NCName ':' '*'
6093 * | QName
6094 * [38] NodeType ::= 'comment'
6095 * | 'text'
6096 * | 'processing-instruction'
6097 * | 'node'
6098 *
6099 * Returns the name found and update @test, @type and @prefix appropriately
6100 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006101static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006102xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6103 xmlXPathTypeVal *type, const xmlChar **prefix,
6104 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006105 int blanks;
6106
6107 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6108 STRANGE;
6109 return(NULL);
6110 }
6111 *type = 0;
6112 *test = 0;
6113 *prefix = NULL;
6114 SKIP_BLANKS;
6115
6116 if ((name == NULL) && (CUR == '*')) {
6117 /*
6118 * All elements
6119 */
6120 NEXT;
6121 *test = NODE_TEST_ALL;
6122 return(NULL);
6123 }
6124
6125 if (name == NULL)
6126 name = xmlXPathParseNCName(ctxt);
6127 if (name == NULL) {
6128 XP_ERROR0(XPATH_EXPR_ERROR);
6129 }
6130
6131 blanks = IS_BLANK(CUR);
6132 SKIP_BLANKS;
6133 if (CUR == '(') {
6134 NEXT;
6135 /*
6136 * NodeType or PI search
6137 */
6138 if (xmlStrEqual(name, BAD_CAST "comment"))
6139 *type = NODE_TYPE_COMMENT;
6140 else if (xmlStrEqual(name, BAD_CAST "node"))
6141 *type = NODE_TYPE_NODE;
6142 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6143 *type = NODE_TYPE_PI;
6144 else if (xmlStrEqual(name, BAD_CAST "text"))
6145 *type = NODE_TYPE_TEXT;
6146 else {
6147 if (name != NULL)
6148 xmlFree(name);
6149 XP_ERROR0(XPATH_EXPR_ERROR);
6150 }
6151
6152 *test = NODE_TEST_TYPE;
6153
6154 SKIP_BLANKS;
6155 if (*type == NODE_TYPE_PI) {
6156 /*
6157 * Specific case: search a PI by name.
6158 */
Owen Taylor3473f882001-02-23 17:55:21 +00006159 if (name != NULL)
6160 xmlFree(name);
6161
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006162 name = xmlXPathParseLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006163 CHECK_ERROR 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006164 SKIP_BLANKS;
6165 }
6166 if (CUR != ')') {
6167 if (name != NULL)
6168 xmlFree(name);
6169 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6170 }
6171 NEXT;
6172 return(name);
6173 }
6174 *test = NODE_TEST_NAME;
6175 if ((!blanks) && (CUR == ':')) {
6176 NEXT;
6177
6178 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006179 * Since currently the parser context don't have a
6180 * namespace list associated:
6181 * The namespace name for this prefix can be computed
6182 * only at evaluation time. The compilation is done
6183 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006184 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006185#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006186 *prefix = xmlXPathNsLookup(ctxt->context, name);
6187 if (name != NULL)
6188 xmlFree(name);
6189 if (*prefix == NULL) {
6190 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6191 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006192#else
6193 *prefix = name;
6194#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006195
6196 if (CUR == '*') {
6197 /*
6198 * All elements
6199 */
6200 NEXT;
6201 *test = NODE_TEST_ALL;
6202 return(NULL);
6203 }
6204
6205 name = xmlXPathParseNCName(ctxt);
6206 if (name == NULL) {
6207 XP_ERROR0(XPATH_EXPR_ERROR);
6208 }
6209 }
6210 return(name);
6211}
6212
6213/**
6214 * xmlXPathIsAxisName:
6215 * @name: a preparsed name token
6216 *
6217 * [6] AxisName ::= 'ancestor'
6218 * | 'ancestor-or-self'
6219 * | 'attribute'
6220 * | 'child'
6221 * | 'descendant'
6222 * | 'descendant-or-self'
6223 * | 'following'
6224 * | 'following-sibling'
6225 * | 'namespace'
6226 * | 'parent'
6227 * | 'preceding'
6228 * | 'preceding-sibling'
6229 * | 'self'
6230 *
6231 * Returns the axis or 0
6232 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006233static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006234xmlXPathIsAxisName(const xmlChar *name) {
6235 xmlXPathAxisVal ret = 0;
6236 switch (name[0]) {
6237 case 'a':
6238 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6239 ret = AXIS_ANCESTOR;
6240 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6241 ret = AXIS_ANCESTOR_OR_SELF;
6242 if (xmlStrEqual(name, BAD_CAST "attribute"))
6243 ret = AXIS_ATTRIBUTE;
6244 break;
6245 case 'c':
6246 if (xmlStrEqual(name, BAD_CAST "child"))
6247 ret = AXIS_CHILD;
6248 break;
6249 case 'd':
6250 if (xmlStrEqual(name, BAD_CAST "descendant"))
6251 ret = AXIS_DESCENDANT;
6252 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6253 ret = AXIS_DESCENDANT_OR_SELF;
6254 break;
6255 case 'f':
6256 if (xmlStrEqual(name, BAD_CAST "following"))
6257 ret = AXIS_FOLLOWING;
6258 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6259 ret = AXIS_FOLLOWING_SIBLING;
6260 break;
6261 case 'n':
6262 if (xmlStrEqual(name, BAD_CAST "namespace"))
6263 ret = AXIS_NAMESPACE;
6264 break;
6265 case 'p':
6266 if (xmlStrEqual(name, BAD_CAST "parent"))
6267 ret = AXIS_PARENT;
6268 if (xmlStrEqual(name, BAD_CAST "preceding"))
6269 ret = AXIS_PRECEDING;
6270 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6271 ret = AXIS_PRECEDING_SIBLING;
6272 break;
6273 case 's':
6274 if (xmlStrEqual(name, BAD_CAST "self"))
6275 ret = AXIS_SELF;
6276 break;
6277 }
6278 return(ret);
6279}
6280
6281/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006282 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006283 * @ctxt: the XPath Parser context
6284 *
6285 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6286 * | AbbreviatedStep
6287 *
6288 * [12] AbbreviatedStep ::= '.' | '..'
6289 *
6290 * [5] AxisSpecifier ::= AxisName '::'
6291 * | AbbreviatedAxisSpecifier
6292 *
6293 * [13] AbbreviatedAxisSpecifier ::= '@'?
6294 *
6295 * Modified for XPtr range support as:
6296 *
6297 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6298 * | AbbreviatedStep
6299 * | 'range-to' '(' Expr ')' Predicate*
6300 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006301 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006302 * A location step of . is short for self::node(). This is
6303 * particularly useful in conjunction with //. For example, the
6304 * location path .//para is short for
6305 * self::node()/descendant-or-self::node()/child::para
6306 * and so will select all para descendant elements of the context
6307 * node.
6308 * Similarly, a location step of .. is short for parent::node().
6309 * For example, ../title is short for parent::node()/child::title
6310 * and so will select the title children of the parent of the context
6311 * node.
6312 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006313static void
6314xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006315 SKIP_BLANKS;
6316 if ((CUR == '.') && (NXT(1) == '.')) {
6317 SKIP(2);
6318 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006319 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6320 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006321 } else if (CUR == '.') {
6322 NEXT;
6323 SKIP_BLANKS;
6324 } else {
6325 xmlChar *name = NULL;
6326 const xmlChar *prefix = NULL;
6327 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006328 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006329 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006330 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006331
6332 /*
6333 * The modification needed for XPointer change to the production
6334 */
6335#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006336 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006337 name = xmlXPathParseNCName(ctxt);
6338 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006339 int op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006340 xmlFree(name);
6341 SKIP_BLANKS;
6342 if (CUR != '(') {
6343 XP_ERROR(XPATH_EXPR_ERROR);
6344 }
6345 NEXT;
6346 SKIP_BLANKS;
6347
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006348 xmlXPathCompileExpr(ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006349 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006350 CHECK_ERROR;
6351
6352 SKIP_BLANKS;
6353 if (CUR != ')') {
6354 XP_ERROR(XPATH_EXPR_ERROR);
6355 }
6356 NEXT;
6357 goto eval_predicates;
6358 }
6359 }
6360#endif
6361 if (name == NULL)
6362 name = xmlXPathParseNCName(ctxt);
6363 if (name != NULL) {
6364 axis = xmlXPathIsAxisName(name);
6365 if (axis != 0) {
6366 SKIP_BLANKS;
6367 if ((CUR == ':') && (NXT(1) == ':')) {
6368 SKIP(2);
6369 xmlFree(name);
6370 name = NULL;
6371 } else {
6372 /* an element name can conflict with an axis one :-\ */
6373 axis = AXIS_CHILD;
6374 }
6375 } else {
6376 axis = AXIS_CHILD;
6377 }
6378 } else if (CUR == '@') {
6379 NEXT;
6380 axis = AXIS_ATTRIBUTE;
6381 } else {
6382 axis = AXIS_CHILD;
6383 }
6384
6385 CHECK_ERROR;
6386
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006387 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006388 if (test == 0)
6389 return;
6390
6391#ifdef DEBUG_STEP
6392 xmlGenericError(xmlGenericErrorContext,
6393 "Basis : computing new set\n");
6394#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006395
Owen Taylor3473f882001-02-23 17:55:21 +00006396#ifdef DEBUG_STEP
6397 xmlGenericError(xmlGenericErrorContext, "Basis : ");
6398 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
6399#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006400
6401eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006402 op1 = ctxt->comp->last;
6403 ctxt->comp->last = -1;
6404
Owen Taylor3473f882001-02-23 17:55:21 +00006405 SKIP_BLANKS;
6406 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006407 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006408 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006409
6410 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
6411 test, type, (void *)prefix, (void *)name);
6412
Owen Taylor3473f882001-02-23 17:55:21 +00006413 }
6414#ifdef DEBUG_STEP
6415 xmlGenericError(xmlGenericErrorContext, "Step : ");
6416 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6417 ctxt->value->nodesetval);
6418#endif
6419}
6420
6421/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006422 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006423 * @ctxt: the XPath Parser context
6424 *
6425 * [3] RelativeLocationPath ::= Step
6426 * | RelativeLocationPath '/' Step
6427 * | AbbreviatedRelativeLocationPath
6428 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6429 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006430 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00006431 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006432static void
Owen Taylor3473f882001-02-23 17:55:21 +00006433#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006434xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006435#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006436xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006437#endif
6438(xmlXPathParserContextPtr ctxt) {
6439 SKIP_BLANKS;
6440 if ((CUR == '/') && (NXT(1) == '/')) {
6441 SKIP(2);
6442 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006443 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6444 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006445 } else if (CUR == '/') {
6446 NEXT;
6447 SKIP_BLANKS;
6448 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006449 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006450 SKIP_BLANKS;
6451 while (CUR == '/') {
6452 if ((CUR == '/') && (NXT(1) == '/')) {
6453 SKIP(2);
6454 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006455 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00006456 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006457 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006458 } else if (CUR == '/') {
6459 NEXT;
6460 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006461 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006462 }
6463 SKIP_BLANKS;
6464 }
6465}
6466
6467/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006468 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006469 * @ctxt: the XPath Parser context
6470 *
6471 * [1] LocationPath ::= RelativeLocationPath
6472 * | AbsoluteLocationPath
6473 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6474 * | AbbreviatedAbsoluteLocationPath
6475 * [10] AbbreviatedAbsoluteLocationPath ::=
6476 * '//' RelativeLocationPath
6477 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006478 * Compile a location path
6479 *
Owen Taylor3473f882001-02-23 17:55:21 +00006480 * // is short for /descendant-or-self::node()/. For example,
6481 * //para is short for /descendant-or-self::node()/child::para and
6482 * so will select any para element in the document (even a para element
6483 * that is a document element will be selected by //para since the
6484 * document element node is a child of the root node); div//para is
6485 * short for div/descendant-or-self::node()/child::para and so will
6486 * select all para descendants of div children.
6487 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006488static void
6489xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006490 SKIP_BLANKS;
6491 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006492 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006493 } else {
6494 while (CUR == '/') {
6495 if ((CUR == '/') && (NXT(1) == '/')) {
6496 SKIP(2);
6497 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006498 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6499 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006500 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006501 } else if (CUR == '/') {
6502 NEXT;
6503 SKIP_BLANKS;
6504 if (CUR != 0)
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006505 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006506 }
6507 }
6508 }
6509}
6510
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006511/************************************************************************
6512 * *
6513 * XPath precompiled expression evaluation *
6514 * *
6515 ************************************************************************/
6516
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006517static void
6518xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
6519
6520/**
6521 * xmlXPathNodeCollectAndTest:
6522 * @ctxt: the XPath Parser context
6523 * @op: the XPath precompiled step operation
6524 *
6525 * This is the function implementing a step: based on the current list
6526 * of nodes, it builds up a new list, looking at all nodes under that
6527 * axis and selecting them it also do the predicate filtering
6528 *
6529 * Pushes the new NodeSet resulting from the search.
6530 */
6531static void
6532xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
6533 xmlXPathStepOpPtr op) {
6534 xmlXPathAxisVal axis = op->value;
6535 xmlXPathTestVal test = op->value2;
6536 xmlXPathTypeVal type = op->value3;
6537 const xmlChar *prefix = op->value4;
6538 const xmlChar *name = op->value5;
6539
6540#ifdef DEBUG_STEP
6541 int n = 0, t = 0;
6542#endif
6543 int i;
6544 xmlNodeSetPtr ret, list;
6545 xmlXPathTraversalFunction next = NULL;
6546 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
6547 xmlNodePtr cur = NULL;
6548 xmlXPathObjectPtr obj;
6549 xmlNodeSetPtr nodelist;
6550 xmlNodePtr tmp;
6551
6552 CHECK_TYPE(XPATH_NODESET);
6553 obj = valuePop(ctxt);
6554 addNode = xmlXPathNodeSetAdd;
6555
6556#ifdef DEBUG_STEP
6557 xmlGenericError(xmlGenericErrorContext,
6558 "new step : ");
6559#endif
6560 switch (axis) {
6561 case AXIS_ANCESTOR:
6562#ifdef DEBUG_STEP
6563 xmlGenericError(xmlGenericErrorContext,
6564 "axis 'ancestors' ");
6565#endif
6566 next = xmlXPathNextAncestor; break;
6567 case AXIS_ANCESTOR_OR_SELF:
6568#ifdef DEBUG_STEP
6569 xmlGenericError(xmlGenericErrorContext,
6570 "axis 'ancestors-or-self' ");
6571#endif
6572 next = xmlXPathNextAncestorOrSelf; break;
6573 case AXIS_ATTRIBUTE:
6574#ifdef DEBUG_STEP
6575 xmlGenericError(xmlGenericErrorContext,
6576 "axis 'attributes' ");
6577#endif
6578 next = xmlXPathNextAttribute; break;
6579 break;
6580 case AXIS_CHILD:
6581#ifdef DEBUG_STEP
6582 xmlGenericError(xmlGenericErrorContext,
6583 "axis 'child' ");
6584#endif
6585 next = xmlXPathNextChild; break;
6586 case AXIS_DESCENDANT:
6587#ifdef DEBUG_STEP
6588 xmlGenericError(xmlGenericErrorContext,
6589 "axis 'descendant' ");
6590#endif
6591 next = xmlXPathNextDescendant; break;
6592 case AXIS_DESCENDANT_OR_SELF:
6593#ifdef DEBUG_STEP
6594 xmlGenericError(xmlGenericErrorContext,
6595 "axis 'descendant-or-self' ");
6596#endif
6597 next = xmlXPathNextDescendantOrSelf; break;
6598 case AXIS_FOLLOWING:
6599#ifdef DEBUG_STEP
6600 xmlGenericError(xmlGenericErrorContext,
6601 "axis 'following' ");
6602#endif
6603 next = xmlXPathNextFollowing; break;
6604 case AXIS_FOLLOWING_SIBLING:
6605#ifdef DEBUG_STEP
6606 xmlGenericError(xmlGenericErrorContext,
6607 "axis 'following-siblings' ");
6608#endif
6609 next = xmlXPathNextFollowingSibling; break;
6610 case AXIS_NAMESPACE:
6611#ifdef DEBUG_STEP
6612 xmlGenericError(xmlGenericErrorContext,
6613 "axis 'namespace' ");
6614#endif
6615 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
6616 break;
6617 case AXIS_PARENT:
6618#ifdef DEBUG_STEP
6619 xmlGenericError(xmlGenericErrorContext,
6620 "axis 'parent' ");
6621#endif
6622 next = xmlXPathNextParent; break;
6623 case AXIS_PRECEDING:
6624#ifdef DEBUG_STEP
6625 xmlGenericError(xmlGenericErrorContext,
6626 "axis 'preceding' ");
6627#endif
6628 next = xmlXPathNextPreceding; break;
6629 case AXIS_PRECEDING_SIBLING:
6630#ifdef DEBUG_STEP
6631 xmlGenericError(xmlGenericErrorContext,
6632 "axis 'preceding-sibling' ");
6633#endif
6634 next = xmlXPathNextPrecedingSibling; break;
6635 case AXIS_SELF:
6636#ifdef DEBUG_STEP
6637 xmlGenericError(xmlGenericErrorContext,
6638 "axis 'self' ");
6639#endif
6640 next = xmlXPathNextSelf; break;
6641 }
6642 if (next == NULL)
6643 return;
6644
6645 nodelist = obj->nodesetval;
6646 if (nodelist == NULL) {
6647 xmlXPathFreeObject(obj);
6648 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
6649 return;
6650 }
6651 addNode = xmlXPathNodeSetAddUnique;
6652 ret = NULL;
6653#ifdef DEBUG_STEP
6654 xmlGenericError(xmlGenericErrorContext,
6655 " context contains %d nodes\n",
6656 nodelist->nodeNr);
6657 switch (test) {
6658 case NODE_TEST_NODE:
6659 xmlGenericError(xmlGenericErrorContext,
6660 " searching all nodes\n");
6661 break;
6662 case NODE_TEST_NONE:
6663 xmlGenericError(xmlGenericErrorContext,
6664 " searching for none !!!\n");
6665 break;
6666 case NODE_TEST_TYPE:
6667 xmlGenericError(xmlGenericErrorContext,
6668 " searching for type %d\n", type);
6669 break;
6670 case NODE_TEST_PI:
6671 xmlGenericError(xmlGenericErrorContext,
6672 " searching for PI !!!\n");
6673 break;
6674 case NODE_TEST_ALL:
6675 xmlGenericError(xmlGenericErrorContext,
6676 " searching for *\n");
6677 break;
6678 case NODE_TEST_NS:
6679 xmlGenericError(xmlGenericErrorContext,
6680 " searching for namespace %s\n",
6681 prefix);
6682 break;
6683 case NODE_TEST_NAME:
6684 xmlGenericError(xmlGenericErrorContext,
6685 " searching for name %s\n", name);
6686 if (prefix != NULL)
6687 xmlGenericError(xmlGenericErrorContext,
6688 " with namespace %s\n",
6689 prefix);
6690 break;
6691 }
6692 xmlGenericError(xmlGenericErrorContext, "Testing : ");
6693#endif
6694 /*
6695 * 2.3 Node Tests
6696 * - For the attribute axis, the principal node type is attribute.
6697 * - For the namespace axis, the principal node type is namespace.
6698 * - For other axes, the principal node type is element.
6699 *
6700 * A node test * is true for any node of the
6701 * principal node type. For example, child::* willi
6702 * select all element children of the context node
6703 */
6704 tmp = ctxt->context->node;
6705 for (i = 0;i < nodelist->nodeNr; i++) {
6706 ctxt->context->node = nodelist->nodeTab[i];
6707
6708 cur = NULL;
6709 list = xmlXPathNodeSetCreate(NULL);
6710 do {
6711 cur = next(ctxt, cur);
6712 if (cur == NULL) break;
6713#ifdef DEBUG_STEP
6714 t++;
6715 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
6716#endif
6717 switch (test) {
6718 case NODE_TEST_NONE:
6719 ctxt->context->node = tmp;
6720 STRANGE
6721 return;
6722 case NODE_TEST_TYPE:
6723 if ((cur->type == type) ||
6724 ((type == NODE_TYPE_NODE) &&
6725 ((cur->type == XML_DOCUMENT_NODE) ||
6726 (cur->type == XML_HTML_DOCUMENT_NODE) ||
6727 (cur->type == XML_ELEMENT_NODE) ||
6728 (cur->type == XML_PI_NODE) ||
6729 (cur->type == XML_COMMENT_NODE) ||
6730 (cur->type == XML_CDATA_SECTION_NODE) ||
6731 (cur->type == XML_TEXT_NODE)))) {
6732#ifdef DEBUG_STEP
6733 n++;
6734#endif
6735 addNode(list, cur);
6736 }
6737 break;
6738 case NODE_TEST_PI:
6739 if (cur->type == XML_PI_NODE) {
6740 if ((name != NULL) &&
6741 (!xmlStrEqual(name, cur->name)))
6742 break;
6743#ifdef DEBUG_STEP
6744 n++;
6745#endif
6746 addNode(list, cur);
6747 }
6748 break;
6749 case NODE_TEST_ALL:
6750 if (axis == AXIS_ATTRIBUTE) {
6751 if (cur->type == XML_ATTRIBUTE_NODE) {
6752#ifdef DEBUG_STEP
6753 n++;
6754#endif
6755 addNode(list, cur);
6756 }
6757 } else if (axis == AXIS_NAMESPACE) {
6758 if (cur->type == XML_NAMESPACE_DECL) {
6759#ifdef DEBUG_STEP
6760 n++;
6761#endif
6762 addNode(list, cur);
6763 }
6764 } else {
6765 if ((cur->type == XML_ELEMENT_NODE) ||
6766 (cur->type == XML_DOCUMENT_NODE) ||
6767 (cur->type == XML_HTML_DOCUMENT_NODE)) {
6768 if (prefix == NULL) {
6769#ifdef DEBUG_STEP
6770 n++;
6771#endif
6772 addNode(list, cur);
6773 } else if ((cur->ns != NULL) &&
6774 (xmlStrEqual(prefix,
6775 cur->ns->href))) {
6776#ifdef DEBUG_STEP
6777 n++;
6778#endif
6779 addNode(list, cur);
6780 }
6781 }
6782 }
6783 break;
6784 case NODE_TEST_NS: {
6785 TODO;
6786 break;
6787 }
6788 case NODE_TEST_NAME:
6789 switch (cur->type) {
6790 case XML_ELEMENT_NODE:
6791 if (xmlStrEqual(name, cur->name)) {
6792 if (prefix == NULL) {
6793 if ((cur->ns == NULL) ||
6794 (cur->ns->prefix == NULL)) {
6795#ifdef DEBUG_STEP
6796 n++;
6797#endif
6798 addNode(list, cur);
6799 }
6800 } else {
6801 if ((cur->ns != NULL) &&
6802 (xmlStrEqual(prefix,
6803 cur->ns->href))) {
6804#ifdef DEBUG_STEP
6805 n++;
6806#endif
6807 addNode(list, cur);
6808 }
6809 }
6810 }
6811 break;
6812 case XML_ATTRIBUTE_NODE: {
6813 xmlAttrPtr attr = (xmlAttrPtr) cur;
6814 if (xmlStrEqual(name, attr->name)) {
6815 if (prefix == NULL) {
6816 if ((attr->ns == NULL) ||
6817 (attr->ns->prefix == NULL)) {
6818#ifdef DEBUG_STEP
6819 n++;
6820#endif
6821 addNode(list, (xmlNodePtr) attr);
6822 }
6823 } else {
6824 if ((attr->ns != NULL) &&
6825 (xmlStrEqual(prefix,
6826 attr->ns->href))) {
6827#ifdef DEBUG_STEP
6828 n++;
6829#endif
6830 addNode(list, (xmlNodePtr) attr);
6831 }
6832 }
6833 }
6834 break;
6835 }
6836 case XML_NAMESPACE_DECL: {
6837 TODO;
6838 break;
6839 }
6840 default:
6841 break;
6842 }
6843 break;
6844 }
6845 } while (cur != NULL);
6846
6847 /*
6848 * If there is some predicate filtering do it now
6849 */
6850 if (op->ch2 != -1) {
6851 xmlXPathObjectPtr obj2;
6852
6853 valuePush(ctxt, xmlXPathWrapNodeSet(list));
6854 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
6855 CHECK_TYPE(XPATH_NODESET);
6856 obj2 = valuePop(ctxt);
6857 list = obj2->nodesetval;
6858 obj2->nodesetval = NULL;
6859 xmlXPathFreeObject(obj2);
6860 }
6861 if (ret == NULL) {
6862 ret = list;
6863 } else {
6864 ret = xmlXPathNodeSetMerge(ret, list);
6865 xmlXPathFreeNodeSet(list);
6866 }
6867 }
6868 ctxt->context->node = tmp;
6869#ifdef DEBUG_STEP
6870 xmlGenericError(xmlGenericErrorContext,
6871 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
6872#endif
6873 xmlXPathFreeObject(obj);
6874 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
6875}
6876
Owen Taylor3473f882001-02-23 17:55:21 +00006877/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006878 * xmlXPathCompOpEval:
6879 * @ctxt: the XPath parser context with the compiled expression
6880 * @op: an XPath compiled operation
6881 *
6882 * Evaluate the Precompiled XPath operation
6883 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006884static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006885xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
6886 int equal, ret;
6887 xmlXPathCompExprPtr comp;
6888 xmlXPathObjectPtr arg1, arg2;
6889
6890 comp = ctxt->comp;
6891 switch (op->op) {
6892 case XPATH_OP_END:
6893 return;
6894 case XPATH_OP_AND:
6895 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6896 xmlXPathBooleanFunction(ctxt, 1);
6897 if (ctxt->value->boolval == 0)
6898 return;
6899 arg2 = valuePop(ctxt);
6900 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6901 xmlXPathBooleanFunction(ctxt, 1);
6902 arg1 = valuePop(ctxt);
6903 arg1->boolval &= arg2->boolval;
6904 valuePush(ctxt, arg1);
6905 xmlXPathFreeObject(arg2);
6906 return;
6907 case XPATH_OP_OR:
6908 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6909 xmlXPathBooleanFunction(ctxt, 1);
6910 if (ctxt->value->boolval == 1)
6911 return;
6912 arg2 = valuePop(ctxt);
6913 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6914 xmlXPathBooleanFunction(ctxt, 1);
6915 arg1 = valuePop(ctxt);
6916 arg1->boolval |= arg2->boolval;
6917 valuePush(ctxt, arg1);
6918 xmlXPathFreeObject(arg2);
6919 return;
6920 case XPATH_OP_EQUAL:
6921 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6922 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6923 equal = xmlXPathEqualValues(ctxt);
6924 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
6925 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
6926 return;
6927 case XPATH_OP_CMP:
6928 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6929 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6930 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
6931 valuePush(ctxt, xmlXPathNewBoolean(ret));
6932 return;
6933 case XPATH_OP_PLUS:
6934 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6935 if (op->ch2 != -1)
6936 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6937 if (op->value == 0) xmlXPathSubValues(ctxt);
6938 else if (op->value == 1) xmlXPathAddValues(ctxt);
6939 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
6940 else if (op->value == 3) {
6941 xmlXPathObjectPtr arg;
6942
6943 POP_FLOAT
6944 valuePush(ctxt, arg);
6945 }
6946 return;
6947 case XPATH_OP_MULT:
6948 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6949 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6950 if (op->value == 0) xmlXPathMultValues(ctxt);
6951 else if (op->value == 1) xmlXPathDivValues(ctxt);
6952 else if (op->value == 2) xmlXPathModValues(ctxt);
6953 return;
6954 case XPATH_OP_UNION:
6955 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6956 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6957 CHECK_TYPE(XPATH_NODESET);
6958 arg2 = valuePop(ctxt);
6959
6960 CHECK_TYPE(XPATH_NODESET);
6961 arg1 = valuePop(ctxt);
6962
6963 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
6964 arg2->nodesetval);
6965 valuePush(ctxt, arg1);
6966 xmlXPathFreeObject(arg2);
6967 return;
6968 case XPATH_OP_ROOT:
6969 xmlXPathRoot(ctxt);
6970 return;
6971 case XPATH_OP_NODE:
6972 if (op->ch1 != -1)
6973 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6974 if (op->ch2 != -1)
6975 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6976 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6977 return;
6978 case XPATH_OP_RESET:
6979 if (op->ch1 != -1)
6980 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6981 if (op->ch2 != -1)
6982 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6983 ctxt->context->node = NULL;
6984 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006985 case XPATH_OP_COLLECT: {
6986 if (op->ch1 == -1)
6987 return;
6988
6989 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6990 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006991 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006992 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006993 case XPATH_OP_VALUE:
6994 valuePush(ctxt,
6995 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
6996 return;
6997 case XPATH_OP_VARIABLE: {
6998 if (op->ch1 != -1)
6999 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7000 if (op->value5 == NULL)
7001 valuePush(ctxt,
7002 xmlXPathVariableLookup(ctxt->context, op->value4));
7003 else {
7004 const xmlChar *URI;
7005 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7006 if (URI == NULL) {
7007 xmlGenericError(xmlGenericErrorContext,
7008 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7009 op->value4, op->value5);
7010 return;
7011 }
7012 valuePush(ctxt,
7013 xmlXPathVariableLookupNS(ctxt->context,
7014 op->value4, URI));
7015 }
7016 return;
7017 }
7018 case XPATH_OP_FUNCTION: {
7019 xmlXPathFunction func;
7020
7021 if (op->ch1 != -1)
7022 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7023 if (op->value5 == NULL)
7024 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7025 else {
7026 const xmlChar *URI;
7027 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7028 if (URI == NULL) {
7029 xmlGenericError(xmlGenericErrorContext,
7030 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7031 op->value4, op->value5);
7032 return;
7033 }
7034 func = xmlXPathFunctionLookupNS(ctxt->context,
7035 op->value4, URI);
7036 }
7037 if (func == NULL) {
7038 xmlGenericError(xmlGenericErrorContext,
7039 "xmlXPathRunEval: function %s not found\n",
7040 op->value4);
7041 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
7042 return;
7043 }
7044 func(ctxt, op->value);
7045 return;
7046 }
7047 case XPATH_OP_ARG:
7048 if (op->ch1 != -1)
7049 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7050 if (op->ch2 != -1)
7051 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7052 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007053 case XPATH_OP_PREDICATE:
7054 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007055 xmlXPathObjectPtr res;
7056 xmlXPathObjectPtr obj, tmp;
7057 xmlNodeSetPtr newset = NULL;
7058 xmlNodeSetPtr oldset;
7059 xmlNodePtr oldnode;
7060 int i;
7061
7062 if (op->ch1 != -1)
7063 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7064 if (op->ch2 == -1)
7065 return;
7066
7067 oldnode = ctxt->context->node;
7068
7069#ifdef LIBXML_XPTR_ENABLED
7070 /*
7071 * Hum are we filtering the result of an XPointer expression
7072 */
7073 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007074 xmlLocationSetPtr newlocset = NULL;
7075 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007076
7077 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007078 * Extract the old locset, and then evaluate the result of the
7079 * expression for all the element in the locset. use it to grow
7080 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007081 */
7082 CHECK_TYPE(XPATH_LOCATIONSET);
7083 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007084 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007085 ctxt->context->node = NULL;
7086
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007087 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007088 ctxt->context->contextSize = 0;
7089 ctxt->context->proximityPosition = 0;
7090 if (op->ch2 != -1)
7091 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7092 res = valuePop(ctxt);
7093 if (res != NULL)
7094 xmlXPathFreeObject(res);
7095 valuePush(ctxt, obj);
7096 CHECK_ERROR;
7097 return;
7098 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007099 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007100
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007101 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007102 /*
7103 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007104 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007105 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007106 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007107 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7108 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007109 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007110 ctxt->context->proximityPosition = i + 1;
7111
7112 if (op->ch2 != -1)
7113 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7114 CHECK_ERROR;
7115
7116 /*
7117 * The result of the evaluation need to be tested to
7118 * decided whether the filter succeeded or not
7119 */
7120 res = valuePop(ctxt);
7121 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007122 xmlXPtrLocationSetAdd(newlocset,
7123 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007124 }
7125
7126 /*
7127 * Cleanup
7128 */
7129 if (res != NULL)
7130 xmlXPathFreeObject(res);
7131 if (ctxt->value == tmp) {
7132 res = valuePop(ctxt);
7133 xmlXPathFreeObject(res);
7134 }
7135
7136 ctxt->context->node = NULL;
7137 }
7138
7139 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007140 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007141 */
7142 xmlXPathFreeObject(obj);
7143 ctxt->context->node = NULL;
7144 ctxt->context->contextSize = -1;
7145 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007146 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007147 ctxt->context->node = oldnode;
7148 return;
7149 }
7150#endif /* LIBXML_XPTR_ENABLED */
7151
7152 /*
7153 * Extract the old set, and then evaluate the result of the
7154 * expression for all the element in the set. use it to grow
7155 * up a new set.
7156 */
7157 CHECK_TYPE(XPATH_NODESET);
7158 obj = valuePop(ctxt);
7159 oldset = obj->nodesetval;
7160 oldnode = ctxt->context->node;
7161 ctxt->context->node = NULL;
7162
7163 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7164 ctxt->context->contextSize = 0;
7165 ctxt->context->proximityPosition = 0;
7166 if (op->ch2 != -1)
7167 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7168 res = valuePop(ctxt);
7169 if (res != NULL)
7170 xmlXPathFreeObject(res);
7171 valuePush(ctxt, obj);
7172 CHECK_ERROR;
7173 } else {
7174 /*
7175 * Initialize the new set.
7176 */
7177 newset = xmlXPathNodeSetCreate(NULL);
7178
7179 for (i = 0; i < oldset->nodeNr; i++) {
7180 /*
7181 * Run the evaluation with a node list made of
7182 * a single item in the nodeset.
7183 */
7184 ctxt->context->node = oldset->nodeTab[i];
7185 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7186 valuePush(ctxt, tmp);
7187 ctxt->context->contextSize = oldset->nodeNr;
7188 ctxt->context->proximityPosition = i + 1;
7189
7190 if (op->ch2 != -1)
7191 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7192 CHECK_ERROR;
7193
7194 /*
7195 * The result of the evaluation need to be tested to
7196 * decided whether the filter succeeded or not
7197 */
7198 res = valuePop(ctxt);
7199 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7200 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7201 }
7202
7203 /*
7204 * Cleanup
7205 */
7206 if (res != NULL)
7207 xmlXPathFreeObject(res);
7208 if (ctxt->value == tmp) {
7209 res = valuePop(ctxt);
7210 xmlXPathFreeObject(res);
7211 }
7212
7213 ctxt->context->node = NULL;
7214 }
7215
7216 /*
7217 * The result is used as the new evaluation set.
7218 */
7219 xmlXPathFreeObject(obj);
7220 ctxt->context->node = NULL;
7221 ctxt->context->contextSize = -1;
7222 ctxt->context->proximityPosition = -1;
7223 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7224 }
7225 ctxt->context->node = oldnode;
7226 return;
7227 }
7228 case XPATH_OP_SORT:
7229 if (op->ch1 != -1)
7230 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7231 if ((ctxt->value != NULL) &&
7232 (ctxt->value->type == XPATH_NODESET) &&
7233 (ctxt->value->nodesetval != NULL))
7234 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7235 return;
7236#ifdef LIBXML_XPTR_ENABLED
7237 case XPATH_OP_RANGETO: {
7238 xmlXPathObjectPtr range;
7239 xmlXPathObjectPtr res, obj;
7240 xmlXPathObjectPtr tmp;
7241 xmlLocationSetPtr newset = NULL;
7242 xmlNodeSetPtr oldset;
7243 int i;
7244
7245 if (op->ch1 != -1)
7246 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7247 if (op->ch2 == -1)
7248 return;
7249
7250 CHECK_TYPE(XPATH_NODESET);
7251 obj = valuePop(ctxt);
7252 oldset = obj->nodesetval;
7253 ctxt->context->node = NULL;
7254
7255 newset = xmlXPtrLocationSetCreate(NULL);
7256
7257 for (i = 0; i < oldset->nodeNr; i++) {
7258 /*
7259 * Run the evaluation with a node list made of a single item
7260 * in the nodeset.
7261 */
7262 ctxt->context->node = oldset->nodeTab[i];
7263 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7264 valuePush(ctxt, tmp);
7265
7266 if (op->ch2 != -1)
7267 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7268 CHECK_ERROR;
7269
7270 /*
7271 * The result of the evaluation need to be tested to
7272 * decided whether the filter succeeded or not
7273 */
7274 res = valuePop(ctxt);
7275 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7276 if (range != NULL) {
7277 xmlXPtrLocationSetAdd(newset, range);
7278 }
7279
7280 /*
7281 * Cleanup
7282 */
7283 if (res != NULL)
7284 xmlXPathFreeObject(res);
7285 if (ctxt->value == tmp) {
7286 res = valuePop(ctxt);
7287 xmlXPathFreeObject(res);
7288 }
7289
7290 ctxt->context->node = NULL;
7291 }
7292
7293 /*
7294 * The result is used as the new evaluation set.
7295 */
7296 xmlXPathFreeObject(obj);
7297 ctxt->context->node = NULL;
7298 ctxt->context->contextSize = -1;
7299 ctxt->context->proximityPosition = -1;
7300 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7301 return;
7302 }
7303#endif /* LIBXML_XPTR_ENABLED */
7304 }
7305 xmlGenericError(xmlGenericErrorContext,
7306 "XPath: unknown precompiled operation %d\n",
7307 op->op);
7308 return;
7309}
7310
7311/**
7312 * xmlXPathRunEval:
7313 * @ctxt: the XPath parser context with the compiled expression
7314 *
7315 * Evaluate the Precompiled XPath expression in the given context.
7316 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007317static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007318xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7319 xmlXPathCompExprPtr comp;
7320
7321 if ((ctxt == NULL) || (ctxt->comp == NULL))
7322 return;
7323
7324 if (ctxt->valueTab == NULL) {
7325 /* Allocate the value stack */
7326 ctxt->valueTab = (xmlXPathObjectPtr *)
7327 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7328 if (ctxt->valueTab == NULL) {
7329 xmlFree(ctxt);
7330 xmlGenericError(xmlGenericErrorContext,
7331 "xmlXPathRunEval: out of memory\n");
7332 return;
7333 }
7334 ctxt->valueNr = 0;
7335 ctxt->valueMax = 10;
7336 ctxt->value = NULL;
7337 }
7338 comp = ctxt->comp;
7339 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7340}
7341
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007342/************************************************************************
7343 * *
7344 * Public interfaces *
7345 * *
7346 ************************************************************************/
7347
7348/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007349 * xmlXPathEvalPredicate:
7350 * @ctxt: the XPath context
7351 * @res: the Predicate Expression evaluation result
7352 *
7353 * Evaluate a predicate result for the current node.
7354 * A PredicateExpr is evaluated by evaluating the Expr and converting
7355 * the result to a boolean. If the result is a number, the result will
7356 * be converted to true if the number is equal to the position of the
7357 * context node in the context node list (as returned by the position
7358 * function) and will be converted to false otherwise; if the result
7359 * is not a number, then the result will be converted as if by a call
7360 * to the boolean function.
7361 *
7362 * Return 1 if predicate is true, 0 otherwise
7363 */
7364int
7365xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7366 if (res == NULL) return(0);
7367 switch (res->type) {
7368 case XPATH_BOOLEAN:
7369 return(res->boolval);
7370 case XPATH_NUMBER:
7371 return(res->floatval == ctxt->proximityPosition);
7372 case XPATH_NODESET:
7373 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007374 if (res->nodesetval == NULL)
7375 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007376 return(res->nodesetval->nodeNr != 0);
7377 case XPATH_STRING:
7378 return((res->stringval != NULL) &&
7379 (xmlStrlen(res->stringval) != 0));
7380 default:
7381 STRANGE
7382 }
7383 return(0);
7384}
7385
7386/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007387 * xmlXPathEvaluatePredicateResult:
7388 * @ctxt: the XPath Parser context
7389 * @res: the Predicate Expression evaluation result
7390 *
7391 * Evaluate a predicate result for the current node.
7392 * A PredicateExpr is evaluated by evaluating the Expr and converting
7393 * the result to a boolean. If the result is a number, the result will
7394 * be converted to true if the number is equal to the position of the
7395 * context node in the context node list (as returned by the position
7396 * function) and will be converted to false otherwise; if the result
7397 * is not a number, then the result will be converted as if by a call
7398 * to the boolean function.
7399 *
7400 * Return 1 if predicate is true, 0 otherwise
7401 */
7402int
7403xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
7404 xmlXPathObjectPtr res) {
7405 if (res == NULL) return(0);
7406 switch (res->type) {
7407 case XPATH_BOOLEAN:
7408 return(res->boolval);
7409 case XPATH_NUMBER:
7410 return(res->floatval == ctxt->context->proximityPosition);
7411 case XPATH_NODESET:
7412 case XPATH_XSLT_TREE:
7413 return(res->nodesetval->nodeNr != 0);
7414 case XPATH_STRING:
7415 return((res->stringval != NULL) &&
7416 (xmlStrlen(res->stringval) != 0));
7417 default:
7418 STRANGE
7419 }
7420 return(0);
7421}
7422
7423/**
7424 * xmlXPathCompile:
7425 * @str: the XPath expression
7426 *
7427 * Compile an XPath expression
7428 *
7429 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7430 * the caller has to free the object.
7431 */
7432xmlXPathCompExprPtr
7433xmlXPathCompile(const xmlChar *str) {
7434 xmlXPathParserContextPtr ctxt;
7435 xmlXPathCompExprPtr comp;
7436
7437 xmlXPathInit();
7438
7439 ctxt = xmlXPathNewParserContext(str, NULL);
7440 xmlXPathCompileExpr(ctxt);
7441
7442 comp = ctxt->comp;
7443 ctxt->comp = NULL;
7444 xmlXPathFreeParserContext(ctxt);
7445 return(comp);
7446}
7447
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007448/**
7449 * xmlXPathCompiledEval:
7450 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00007451 * @ctx: the XPath context
7452 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007453 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00007454 *
7455 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7456 * the caller has to free the object.
7457 */
7458xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007459xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00007460 xmlXPathParserContextPtr ctxt;
7461 xmlXPathObjectPtr res, tmp, init = NULL;
7462 int stack = 0;
7463
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007464 if ((comp == NULL) || (ctx == NULL))
7465 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007466 xmlXPathInit();
7467
7468 CHECK_CONTEXT(ctx)
7469
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007470 ctxt = xmlXPathCompParserContext(comp, ctx);
7471 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007472
7473 if (ctxt->value == NULL) {
7474 xmlGenericError(xmlGenericErrorContext,
7475 "xmlXPathEval: evaluation failed\n");
7476 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007477 } else {
7478 res = valuePop(ctxt);
7479 }
7480
7481 do {
7482 tmp = valuePop(ctxt);
7483 if (tmp != NULL) {
7484 if (tmp != init)
7485 stack++;
7486 xmlXPathFreeObject(tmp);
7487 }
7488 } while (tmp != NULL);
7489 if ((stack != 0) && (res != NULL)) {
7490 xmlGenericError(xmlGenericErrorContext,
7491 "xmlXPathEval: %d object left on the stack\n",
7492 stack);
7493 }
7494 if (ctxt->error != XPATH_EXPRESSION_OK) {
7495 xmlXPathFreeObject(res);
7496 res = NULL;
7497 }
7498
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007499
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007500 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007501 xmlXPathFreeParserContext(ctxt);
7502 return(res);
7503}
7504
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007505/**
7506 * xmlXPathEvalExpr:
7507 * @ctxt: the XPath Parser context
7508 *
7509 * Parse and evaluate an XPath expression in the given context,
7510 * then push the result on the context stack
7511 */
7512void
7513xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
7514 xmlXPathCompileExpr(ctxt);
7515 xmlXPathRunEval(ctxt);
7516}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007517
7518/**
7519 * xmlXPathEval:
7520 * @str: the XPath expression
7521 * @ctx: the XPath context
7522 *
7523 * Evaluate the XPath Location Path in the given context.
7524 *
7525 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7526 * the caller has to free the object.
7527 */
7528xmlXPathObjectPtr
7529xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
7530 xmlXPathParserContextPtr ctxt;
7531 xmlXPathObjectPtr res, tmp, init = NULL;
7532 int stack = 0;
7533
7534 xmlXPathInit();
7535
7536 CHECK_CONTEXT(ctx)
7537
7538 ctxt = xmlXPathNewParserContext(str, ctx);
7539 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007540
7541 if (ctxt->value == NULL) {
7542 xmlGenericError(xmlGenericErrorContext,
7543 "xmlXPathEval: evaluation failed\n");
7544 res = NULL;
7545 } else if (*ctxt->cur != 0) {
7546 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7547 res = NULL;
7548 } else {
7549 res = valuePop(ctxt);
7550 }
7551
7552 do {
7553 tmp = valuePop(ctxt);
7554 if (tmp != NULL) {
7555 if (tmp != init)
7556 stack++;
7557 xmlXPathFreeObject(tmp);
7558 }
7559 } while (tmp != NULL);
7560 if ((stack != 0) && (res != NULL)) {
7561 xmlGenericError(xmlGenericErrorContext,
7562 "xmlXPathEval: %d object left on the stack\n",
7563 stack);
7564 }
7565 if (ctxt->error != XPATH_EXPRESSION_OK) {
7566 xmlXPathFreeObject(res);
7567 res = NULL;
7568 }
7569
Owen Taylor3473f882001-02-23 17:55:21 +00007570 xmlXPathFreeParserContext(ctxt);
7571 return(res);
7572}
7573
7574/**
7575 * xmlXPathEvalExpression:
7576 * @str: the XPath expression
7577 * @ctxt: the XPath context
7578 *
7579 * Evaluate the XPath expression in the given context.
7580 *
7581 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
7582 * the caller has to free the object.
7583 */
7584xmlXPathObjectPtr
7585xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
7586 xmlXPathParserContextPtr pctxt;
7587 xmlXPathObjectPtr res, tmp;
7588 int stack = 0;
7589
7590 xmlXPathInit();
7591
7592 CHECK_CONTEXT(ctxt)
7593
7594 pctxt = xmlXPathNewParserContext(str, ctxt);
7595 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007596
7597 if (*pctxt->cur != 0) {
7598 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7599 res = NULL;
7600 } else {
7601 res = valuePop(pctxt);
7602 }
7603 do {
7604 tmp = valuePop(pctxt);
7605 if (tmp != NULL) {
7606 xmlXPathFreeObject(tmp);
7607 stack++;
7608 }
7609 } while (tmp != NULL);
7610 if ((stack != 0) && (res != NULL)) {
7611 xmlGenericError(xmlGenericErrorContext,
7612 "xmlXPathEvalExpression: %d object left on the stack\n",
7613 stack);
7614 }
7615 xmlXPathFreeParserContext(pctxt);
7616 return(res);
7617}
7618
7619/**
7620 * xmlXPathRegisterAllFunctions:
7621 * @ctxt: the XPath context
7622 *
7623 * Registers all default XPath functions in this context
7624 */
7625void
7626xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
7627{
7628 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
7629 xmlXPathBooleanFunction);
7630 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
7631 xmlXPathCeilingFunction);
7632 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
7633 xmlXPathCountFunction);
7634 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
7635 xmlXPathConcatFunction);
7636 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
7637 xmlXPathContainsFunction);
7638 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
7639 xmlXPathIdFunction);
7640 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
7641 xmlXPathFalseFunction);
7642 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
7643 xmlXPathFloorFunction);
7644 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
7645 xmlXPathLastFunction);
7646 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
7647 xmlXPathLangFunction);
7648 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
7649 xmlXPathLocalNameFunction);
7650 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
7651 xmlXPathNotFunction);
7652 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
7653 xmlXPathNameFunction);
7654 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
7655 xmlXPathNamespaceURIFunction);
7656 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
7657 xmlXPathNormalizeFunction);
7658 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
7659 xmlXPathNumberFunction);
7660 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
7661 xmlXPathPositionFunction);
7662 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
7663 xmlXPathRoundFunction);
7664 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
7665 xmlXPathStringFunction);
7666 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
7667 xmlXPathStringLengthFunction);
7668 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
7669 xmlXPathStartsWithFunction);
7670 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
7671 xmlXPathSubstringFunction);
7672 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
7673 xmlXPathSubstringBeforeFunction);
7674 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
7675 xmlXPathSubstringAfterFunction);
7676 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
7677 xmlXPathSumFunction);
7678 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
7679 xmlXPathTrueFunction);
7680 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
7681 xmlXPathTranslateFunction);
7682}
7683
7684#endif /* LIBXML_XPATH_ENABLED */