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