blob: 134565b3a49098bf0514a30f770a3dbe02f2622b [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
2354 ret->comp = comp;
2355
Owen Taylor3473f882001-02-23 17:55:21 +00002356 return(ret);
2357}
2358
2359/**
2360 * xmlXPathFreeParserContext:
2361 * @ctxt: the context to free
2362 *
2363 * Free up an xmlXPathParserContext
2364 */
2365void
2366xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2367 if (ctxt->valueTab != NULL) {
Daniel Veillard48b2f892001-02-25 16:11:03 +00002368 MEM_CLEANUP(ctxt->valueTab, 10 * (size_t) sizeof(xmlXPathObjectPtr));
Owen Taylor3473f882001-02-23 17:55:21 +00002369 xmlFree(ctxt->valueTab);
2370 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002371 if (ctxt->comp)
2372 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard48b2f892001-02-25 16:11:03 +00002373 MEM_CLEANUP(ctxt, (size_t) sizeof(xmlXPathParserContext));
Owen Taylor3473f882001-02-23 17:55:21 +00002374 xmlFree(ctxt);
2375}
2376
2377/************************************************************************
2378 * *
2379 * The implicit core function library *
2380 * *
2381 ************************************************************************/
2382
2383/*
2384 * Auto-pop and cast to a number
2385 */
2386void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
2387
2388
2389#define POP_FLOAT \
2390 arg = valuePop(ctxt); \
2391 if (arg == NULL) { \
2392 XP_ERROR(XPATH_INVALID_OPERAND); \
2393 } \
2394 if (arg->type != XPATH_NUMBER) { \
2395 valuePush(ctxt, arg); \
2396 xmlXPathNumberFunction(ctxt, 1); \
2397 arg = valuePop(ctxt); \
2398 }
2399
2400/**
2401 * xmlXPathCompareNodeSetFloat:
2402 * @ctxt: the XPath Parser context
2403 * @inf: less than (1) or greater than (0)
2404 * @strict: is the comparison strict
2405 * @arg: the node set
2406 * @f: the value
2407 *
2408 * Implement the compare operation between a nodeset and a number
2409 * @ns < @val (1, 1, ...
2410 * @ns <= @val (1, 0, ...
2411 * @ns > @val (0, 1, ...
2412 * @ns >= @val (0, 0, ...
2413 *
2414 * If one object to be compared is a node-set and the other is a number,
2415 * then the comparison will be true if and only if there is a node in the
2416 * node-set such that the result of performing the comparison on the number
2417 * to be compared and on the result of converting the string-value of that
2418 * node to a number using the number function is true.
2419 *
2420 * Returns 0 or 1 depending on the results of the test.
2421 */
2422int
2423xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2424 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2425 int i, ret = 0;
2426 xmlNodeSetPtr ns;
2427 xmlChar *str2;
2428
2429 if ((f == NULL) || (arg == NULL) ||
2430 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2431 xmlXPathFreeObject(arg);
2432 xmlXPathFreeObject(f);
2433 return(0);
2434 }
2435 ns = arg->nodesetval;
2436 for (i = 0;i < ns->nodeNr;i++) {
2437 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2438 if (str2 != NULL) {
2439 valuePush(ctxt,
2440 xmlXPathNewString(str2));
2441 xmlFree(str2);
2442 xmlXPathNumberFunction(ctxt, 1);
2443 valuePush(ctxt, xmlXPathObjectCopy(f));
2444 ret = xmlXPathCompareValues(ctxt, inf, strict);
2445 if (ret)
2446 break;
2447 }
2448 }
2449 xmlXPathFreeObject(arg);
2450 xmlXPathFreeObject(f);
2451 return(ret);
2452}
2453
2454/**
2455 * xmlXPathCompareNodeSetString:
2456 * @ctxt: the XPath Parser context
2457 * @inf: less than (1) or greater than (0)
2458 * @strict: is the comparison strict
2459 * @arg: the node set
2460 * @s: the value
2461 *
2462 * Implement the compare operation between a nodeset and a string
2463 * @ns < @val (1, 1, ...
2464 * @ns <= @val (1, 0, ...
2465 * @ns > @val (0, 1, ...
2466 * @ns >= @val (0, 0, ...
2467 *
2468 * If one object to be compared is a node-set and the other is a string,
2469 * then the comparison will be true if and only if there is a node in
2470 * the node-set such that the result of performing the comparison on the
2471 * string-value of the node and the other string is true.
2472 *
2473 * Returns 0 or 1 depending on the results of the test.
2474 */
2475int
2476xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2477 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2478 int i, ret = 0;
2479 xmlNodeSetPtr ns;
2480 xmlChar *str2;
2481
2482 if ((s == NULL) || (arg == NULL) ||
2483 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2484 xmlXPathFreeObject(arg);
2485 xmlXPathFreeObject(s);
2486 return(0);
2487 }
2488 ns = arg->nodesetval;
2489 for (i = 0;i < ns->nodeNr;i++) {
2490 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2491 if (str2 != NULL) {
2492 valuePush(ctxt,
2493 xmlXPathNewString(str2));
2494 xmlFree(str2);
2495 valuePush(ctxt, xmlXPathObjectCopy(s));
2496 ret = xmlXPathCompareValues(ctxt, inf, strict);
2497 if (ret)
2498 break;
2499 }
2500 }
2501 xmlXPathFreeObject(arg);
2502 xmlXPathFreeObject(s);
2503 return(ret);
2504}
2505
2506/**
2507 * xmlXPathCompareNodeSets:
2508 * @ctxt: the XPath Parser context
2509 * @op: less than (-1), equal (0) or greater than (1)
2510 * @strict: is the comparison strict
2511 * @arg1: the fist node set object
2512 * @arg2: the second node set object
2513 *
2514 * Implement the compare operation on nodesets:
2515 *
2516 * If both objects to be compared are node-sets, then the comparison
2517 * will be true if and only if there is a node in the first node-set
2518 * and a node in the second node-set such that the result of performing
2519 * the comparison on the string-values of the two nodes is true.
2520 * ....
2521 * When neither object to be compared is a node-set and the operator
2522 * is <=, <, >= or >, then the objects are compared by converting both
2523 * objects to numbers and comparing the numbers according to IEEE 754.
2524 * ....
2525 * The number function converts its argument to a number as follows:
2526 * - a string that consists of optional whitespace followed by an
2527 * optional minus sign followed by a Number followed by whitespace
2528 * is converted to the IEEE 754 number that is nearest (according
2529 * to the IEEE 754 round-to-nearest rule) to the mathematical value
2530 * represented by the string; any other string is converted to NaN
2531 *
2532 * Conclusion all nodes need to be converted first to their string value
2533 * and then the comparison must be done when possible
2534 */
2535int
2536xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
2537 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2538 int i, j, init = 0;
2539 double val1;
2540 double *values2;
2541 int ret = 0;
2542 xmlChar *str;
2543 xmlNodeSetPtr ns1;
2544 xmlNodeSetPtr ns2;
2545
2546 if ((arg1 == NULL) ||
2547 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
2548 return(0);
2549 if ((arg2 == NULL) ||
2550 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
2551 return(0);
2552
2553 ns1 = arg1->nodesetval;
2554 ns2 = arg2->nodesetval;
2555
2556 if (ns1->nodeNr <= 0)
2557 return(0);
2558 if (ns2->nodeNr <= 0)
2559 return(0);
2560
2561 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
2562 if (values2 == NULL) {
2563 return(0);
2564 }
2565 for (i = 0;i < ns1->nodeNr;i++) {
2566 str = xmlNodeGetContent(ns1->nodeTab[i]);
2567 if (str == NULL)
2568 continue;
2569 val1 = xmlXPathStringEvalNumber(str);
2570 xmlFree(str);
2571 if (isnan(val1))
2572 continue;
2573 for (j = 0;j < ns2->nodeNr;j++) {
2574 if (init == 0) {
2575 str = xmlNodeGetContent(ns2->nodeTab[j]);
2576 if (str == NULL) {
2577 values2[j] = xmlXPathNAN;
2578 } else {
2579 values2[j] = xmlXPathStringEvalNumber(str);
2580 xmlFree(str);
2581 }
2582 }
2583 if (isnan(values2[j]))
2584 continue;
2585 if (inf && strict)
2586 ret = (val1 < values2[j]);
2587 else if (inf && !strict)
2588 ret = (val1 <= values2[j]);
2589 else if (!inf && strict)
2590 ret = (val1 > values2[j]);
2591 else if (!inf && !strict)
2592 ret = (val1 >= values2[j]);
2593 if (ret)
2594 break;
2595 }
2596 if (ret)
2597 break;
2598 init = 1;
2599 }
2600 xmlFree(values2);
2601 return(ret);
2602 return(0);
2603}
2604
2605/**
2606 * xmlXPathCompareNodeSetValue:
2607 * @ctxt: the XPath Parser context
2608 * @inf: less than (1) or greater than (0)
2609 * @strict: is the comparison strict
2610 * @arg: the node set
2611 * @val: the value
2612 *
2613 * Implement the compare operation between a nodeset and a value
2614 * @ns < @val (1, 1, ...
2615 * @ns <= @val (1, 0, ...
2616 * @ns > @val (0, 1, ...
2617 * @ns >= @val (0, 0, ...
2618 *
2619 * If one object to be compared is a node-set and the other is a boolean,
2620 * then the comparison will be true if and only if the result of performing
2621 * the comparison on the boolean and on the result of converting
2622 * the node-set to a boolean using the boolean function is true.
2623 *
2624 * Returns 0 or 1 depending on the results of the test.
2625 */
2626int
2627xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
2628 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
2629 if ((val == NULL) || (arg == NULL) ||
2630 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2631 return(0);
2632
2633 switch(val->type) {
2634 case XPATH_NUMBER:
2635 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
2636 case XPATH_NODESET:
2637 case XPATH_XSLT_TREE:
2638 return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
2639 case XPATH_STRING:
2640 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
2641 case XPATH_BOOLEAN:
2642 valuePush(ctxt, arg);
2643 xmlXPathBooleanFunction(ctxt, 1);
2644 valuePush(ctxt, val);
2645 return(xmlXPathCompareValues(ctxt, inf, strict));
2646 default:
2647 TODO
2648 return(0);
2649 }
2650 return(0);
2651}
2652
2653/**
2654 * xmlXPathEqualNodeSetString
2655 * @arg: the nodeset object argument
2656 * @str: the string to compare to.
2657 *
2658 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2659 * If one object to be compared is a node-set and the other is a string,
2660 * then the comparison will be true if and only if there is a node in
2661 * the node-set such that the result of performing the comparison on the
2662 * string-value of the node and the other string is true.
2663 *
2664 * Returns 0 or 1 depending on the results of the test.
2665 */
2666int
2667xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
2668 int i;
2669 xmlNodeSetPtr ns;
2670 xmlChar *str2;
2671
2672 if ((str == NULL) || (arg == NULL) ||
2673 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2674 return(0);
2675 ns = arg->nodesetval;
2676 if (ns->nodeNr <= 0)
2677 return(0);
2678 for (i = 0;i < ns->nodeNr;i++) {
2679 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2680 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
2681 xmlFree(str2);
2682 return(1);
2683 }
2684 if (str2 != NULL)
2685 xmlFree(str2);
2686 }
2687 return(0);
2688}
2689
2690/**
2691 * xmlXPathEqualNodeSetFloat
2692 * @arg: the nodeset object argument
2693 * @f: the float to compare to
2694 *
2695 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2696 * If one object to be compared is a node-set and the other is a number,
2697 * then the comparison will be true if and only if there is a node in
2698 * the node-set such that the result of performing the comparison on the
2699 * number to be compared and on the result of converting the string-value
2700 * of that node to a number using the number function is true.
2701 *
2702 * Returns 0 or 1 depending on the results of the test.
2703 */
2704int
2705xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
2706 char buf[100] = "";
2707
2708 if ((arg == NULL) ||
2709 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2710 return(0);
2711
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002712 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00002713 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
2714}
2715
2716
2717/**
2718 * xmlXPathEqualNodeSets
2719 * @arg1: first nodeset object argument
2720 * @arg2: second nodeset object argument
2721 *
2722 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
2723 * If both objects to be compared are node-sets, then the comparison
2724 * will be true if and only if there is a node in the first node-set and
2725 * a node in the second node-set such that the result of performing the
2726 * comparison on the string-values of the two nodes is true.
2727 *
2728 * (needless to say, this is a costly operation)
2729 *
2730 * Returns 0 or 1 depending on the results of the test.
2731 */
2732int
2733xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2734 int i, j;
2735 xmlChar **values1;
2736 xmlChar **values2;
2737 int ret = 0;
2738 xmlNodeSetPtr ns1;
2739 xmlNodeSetPtr ns2;
2740
2741 if ((arg1 == NULL) ||
2742 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
2743 return(0);
2744 if ((arg2 == NULL) ||
2745 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
2746 return(0);
2747
2748 ns1 = arg1->nodesetval;
2749 ns2 = arg2->nodesetval;
2750
2751 if (ns1->nodeNr <= 0)
2752 return(0);
2753 if (ns2->nodeNr <= 0)
2754 return(0);
2755
2756 /*
2757 * check if there is a node pertaining to both sets
2758 */
2759 for (i = 0;i < ns1->nodeNr;i++)
2760 for (j = 0;j < ns2->nodeNr;j++)
2761 if (ns1->nodeTab[i] == ns2->nodeTab[j])
2762 return(1);
2763
2764 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
2765 if (values1 == NULL)
2766 return(0);
2767 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
2768 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
2769 if (values2 == NULL) {
2770 xmlFree(values1);
2771 return(0);
2772 }
2773 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
2774 for (i = 0;i < ns1->nodeNr;i++) {
2775 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
2776 for (j = 0;j < ns2->nodeNr;j++) {
2777 if (i == 0)
2778 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
2779 ret = xmlStrEqual(values1[i], values2[j]);
2780 if (ret)
2781 break;
2782 }
2783 if (ret)
2784 break;
2785 }
2786 for (i = 0;i < ns1->nodeNr;i++)
2787 if (values1[i] != NULL)
2788 xmlFree(values1[i]);
2789 for (j = 0;j < ns2->nodeNr;j++)
2790 if (values2[j] != NULL)
2791 xmlFree(values2[j]);
2792 xmlFree(values1);
2793 xmlFree(values2);
2794 return(ret);
2795}
2796
2797/**
2798 * xmlXPathEqualValues:
2799 * @ctxt: the XPath Parser context
2800 *
2801 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2802 *
2803 * Returns 0 or 1 depending on the results of the test.
2804 */
2805int
2806xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
2807 xmlXPathObjectPtr arg1, arg2;
2808 int ret = 0;
2809
2810 arg1 = valuePop(ctxt);
2811 if (arg1 == NULL)
2812 XP_ERROR0(XPATH_INVALID_OPERAND);
2813
2814 arg2 = valuePop(ctxt);
2815 if (arg2 == NULL) {
2816 xmlXPathFreeObject(arg1);
2817 XP_ERROR0(XPATH_INVALID_OPERAND);
2818 }
2819
2820 if (arg1 == arg2) {
2821#ifdef DEBUG_EXPR
2822 xmlGenericError(xmlGenericErrorContext,
2823 "Equal: by pointer\n");
2824#endif
2825 return(1);
2826 }
2827
2828 switch (arg1->type) {
2829 case XPATH_UNDEFINED:
2830#ifdef DEBUG_EXPR
2831 xmlGenericError(xmlGenericErrorContext,
2832 "Equal: undefined\n");
2833#endif
2834 break;
2835 case XPATH_XSLT_TREE:
2836 case XPATH_NODESET:
2837 switch (arg2->type) {
2838 case XPATH_UNDEFINED:
2839#ifdef DEBUG_EXPR
2840 xmlGenericError(xmlGenericErrorContext,
2841 "Equal: undefined\n");
2842#endif
2843 break;
2844 case XPATH_XSLT_TREE:
2845 case XPATH_NODESET:
2846 ret = xmlXPathEqualNodeSets(arg1, arg2);
2847 break;
2848 case XPATH_BOOLEAN:
2849 if ((arg1->nodesetval == NULL) ||
2850 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2851 else
2852 ret = 1;
2853 ret = (ret == arg2->boolval);
2854 break;
2855 case XPATH_NUMBER:
2856 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2857 break;
2858 case XPATH_STRING:
2859 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2860 break;
2861 case XPATH_USERS:
2862 case XPATH_POINT:
2863 case XPATH_RANGE:
2864 case XPATH_LOCATIONSET:
2865 TODO
2866 break;
2867 }
2868 break;
2869 case XPATH_BOOLEAN:
2870 switch (arg2->type) {
2871 case XPATH_UNDEFINED:
2872#ifdef DEBUG_EXPR
2873 xmlGenericError(xmlGenericErrorContext,
2874 "Equal: undefined\n");
2875#endif
2876 break;
2877 case XPATH_NODESET:
2878 case XPATH_XSLT_TREE:
2879 if ((arg2->nodesetval == NULL) ||
2880 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2881 else
2882 ret = 1;
2883 break;
2884 case XPATH_BOOLEAN:
2885#ifdef DEBUG_EXPR
2886 xmlGenericError(xmlGenericErrorContext,
2887 "Equal: %d boolean %d \n",
2888 arg1->boolval, arg2->boolval);
2889#endif
2890 ret = (arg1->boolval == arg2->boolval);
2891 break;
2892 case XPATH_NUMBER:
2893 if (arg2->floatval) ret = 1;
2894 else ret = 0;
2895 ret = (arg1->boolval == ret);
2896 break;
2897 case XPATH_STRING:
2898 if ((arg2->stringval == NULL) ||
2899 (arg2->stringval[0] == 0)) ret = 0;
2900 else
2901 ret = 1;
2902 ret = (arg1->boolval == ret);
2903 break;
2904 case XPATH_USERS:
2905 case XPATH_POINT:
2906 case XPATH_RANGE:
2907 case XPATH_LOCATIONSET:
2908 TODO
2909 break;
2910 }
2911 break;
2912 case XPATH_NUMBER:
2913 switch (arg2->type) {
2914 case XPATH_UNDEFINED:
2915#ifdef DEBUG_EXPR
2916 xmlGenericError(xmlGenericErrorContext,
2917 "Equal: undefined\n");
2918#endif
2919 break;
2920 case XPATH_NODESET:
2921 case XPATH_XSLT_TREE:
2922 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2923 break;
2924 case XPATH_BOOLEAN:
2925 if (arg1->floatval) ret = 1;
2926 else ret = 0;
2927 ret = (arg2->boolval == ret);
2928 break;
2929 case XPATH_STRING:
2930 valuePush(ctxt, arg2);
2931 xmlXPathNumberFunction(ctxt, 1);
2932 arg2 = valuePop(ctxt);
2933 /* no break on purpose */
2934 case XPATH_NUMBER:
2935 ret = (arg1->floatval == arg2->floatval);
2936 break;
2937 case XPATH_USERS:
2938 case XPATH_POINT:
2939 case XPATH_RANGE:
2940 case XPATH_LOCATIONSET:
2941 TODO
2942 break;
2943 }
2944 break;
2945 case XPATH_STRING:
2946 switch (arg2->type) {
2947 case XPATH_UNDEFINED:
2948#ifdef DEBUG_EXPR
2949 xmlGenericError(xmlGenericErrorContext,
2950 "Equal: undefined\n");
2951#endif
2952 break;
2953 case XPATH_NODESET:
2954 case XPATH_XSLT_TREE:
2955 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2956 break;
2957 case XPATH_BOOLEAN:
2958 if ((arg1->stringval == NULL) ||
2959 (arg1->stringval[0] == 0)) ret = 0;
2960 else
2961 ret = 1;
2962 ret = (arg2->boolval == ret);
2963 break;
2964 case XPATH_STRING:
2965 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
2966 break;
2967 case XPATH_NUMBER:
2968 valuePush(ctxt, arg1);
2969 xmlXPathNumberFunction(ctxt, 1);
2970 arg1 = valuePop(ctxt);
2971 ret = (arg1->floatval == arg2->floatval);
2972 break;
2973 case XPATH_USERS:
2974 case XPATH_POINT:
2975 case XPATH_RANGE:
2976 case XPATH_LOCATIONSET:
2977 TODO
2978 break;
2979 }
2980 break;
2981 case XPATH_USERS:
2982 case XPATH_POINT:
2983 case XPATH_RANGE:
2984 case XPATH_LOCATIONSET:
2985 TODO
2986 break;
2987 }
2988 xmlXPathFreeObject(arg1);
2989 xmlXPathFreeObject(arg2);
2990 return(ret);
2991}
2992
2993
2994/**
2995 * xmlXPathCompareValues:
2996 * @ctxt: the XPath Parser context
2997 * @inf: less than (1) or greater than (0)
2998 * @strict: is the comparison strict
2999 *
3000 * Implement the compare operation on XPath objects:
3001 * @arg1 < @arg2 (1, 1, ...
3002 * @arg1 <= @arg2 (1, 0, ...
3003 * @arg1 > @arg2 (0, 1, ...
3004 * @arg1 >= @arg2 (0, 0, ...
3005 *
3006 * When neither object to be compared is a node-set and the operator is
3007 * <=, <, >=, >, then the objects are compared by converted both objects
3008 * to numbers and comparing the numbers according to IEEE 754. The <
3009 * comparison will be true if and only if the first number is less than the
3010 * second number. The <= comparison will be true if and only if the first
3011 * number is less than or equal to the second number. The > comparison
3012 * will be true if and only if the first number is greater than the second
3013 * number. The >= comparison will be true if and only if the first number
3014 * is greater than or equal to the second number.
3015 *
3016 * Returns 1 if the comparaison succeeded, 0 if it failed
3017 */
3018int
3019xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3020 int ret = 0;
3021 xmlXPathObjectPtr arg1, arg2;
3022
3023 arg2 = valuePop(ctxt);
3024 if (arg2 == NULL) {
3025 XP_ERROR0(XPATH_INVALID_OPERAND);
3026 }
3027
3028 arg1 = valuePop(ctxt);
3029 if (arg1 == NULL) {
3030 xmlXPathFreeObject(arg2);
3031 XP_ERROR0(XPATH_INVALID_OPERAND);
3032 }
3033
3034 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3035 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
3036 ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
3037 } else {
3038 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003039 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3040 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003041 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003042 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3043 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003044 }
3045 }
3046 return(ret);
3047 }
3048
3049 if (arg1->type != XPATH_NUMBER) {
3050 valuePush(ctxt, arg1);
3051 xmlXPathNumberFunction(ctxt, 1);
3052 arg1 = valuePop(ctxt);
3053 }
3054 if (arg1->type != XPATH_NUMBER) {
3055 xmlXPathFreeObject(arg1);
3056 xmlXPathFreeObject(arg2);
3057 XP_ERROR0(XPATH_INVALID_OPERAND);
3058 }
3059 if (arg2->type != XPATH_NUMBER) {
3060 valuePush(ctxt, arg2);
3061 xmlXPathNumberFunction(ctxt, 1);
3062 arg2 = valuePop(ctxt);
3063 }
3064 if (arg2->type != XPATH_NUMBER) {
3065 xmlXPathFreeObject(arg1);
3066 xmlXPathFreeObject(arg2);
3067 XP_ERROR0(XPATH_INVALID_OPERAND);
3068 }
3069 /*
3070 * Add tests for infinity and nan
3071 * => feedback on 3.4 for Inf and NaN
3072 */
3073 if (inf && strict)
3074 ret = (arg1->floatval < arg2->floatval);
3075 else if (inf && !strict)
3076 ret = (arg1->floatval <= arg2->floatval);
3077 else if (!inf && strict)
3078 ret = (arg1->floatval > arg2->floatval);
3079 else if (!inf && !strict)
3080 ret = (arg1->floatval >= arg2->floatval);
3081 xmlXPathFreeObject(arg1);
3082 xmlXPathFreeObject(arg2);
3083 return(ret);
3084}
3085
3086/**
3087 * xmlXPathValueFlipSign:
3088 * @ctxt: the XPath Parser context
3089 *
3090 * Implement the unary - operation on an XPath object
3091 * The numeric operators convert their operands to numbers as if
3092 * by calling the number function.
3093 */
3094void
3095xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
3096 xmlXPathObjectPtr arg;
3097
3098 POP_FLOAT
3099 arg->floatval = -arg->floatval;
3100 valuePush(ctxt, arg);
3101}
3102
3103/**
3104 * xmlXPathAddValues:
3105 * @ctxt: the XPath Parser context
3106 *
3107 * Implement the add operation on XPath objects:
3108 * The numeric operators convert their operands to numbers as if
3109 * by calling the number function.
3110 */
3111void
3112xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3113 xmlXPathObjectPtr arg;
3114 double val;
3115
3116 POP_FLOAT
3117 val = arg->floatval;
3118 xmlXPathFreeObject(arg);
3119
3120 POP_FLOAT
3121 arg->floatval += val;
3122 valuePush(ctxt, arg);
3123}
3124
3125/**
3126 * xmlXPathSubValues:
3127 * @ctxt: the XPath Parser context
3128 *
3129 * Implement the substraction operation on XPath objects:
3130 * The numeric operators convert their operands to numbers as if
3131 * by calling the number function.
3132 */
3133void
3134xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3135 xmlXPathObjectPtr arg;
3136 double val;
3137
3138 POP_FLOAT
3139 val = arg->floatval;
3140 xmlXPathFreeObject(arg);
3141
3142 POP_FLOAT
3143 arg->floatval -= val;
3144 valuePush(ctxt, arg);
3145}
3146
3147/**
3148 * xmlXPathMultValues:
3149 * @ctxt: the XPath Parser context
3150 *
3151 * Implement the multiply operation on XPath objects:
3152 * The numeric operators convert their operands to numbers as if
3153 * by calling the number function.
3154 */
3155void
3156xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3157 xmlXPathObjectPtr arg;
3158 double val;
3159
3160 POP_FLOAT
3161 val = arg->floatval;
3162 xmlXPathFreeObject(arg);
3163
3164 POP_FLOAT
3165 arg->floatval *= val;
3166 valuePush(ctxt, arg);
3167}
3168
3169/**
3170 * xmlXPathDivValues:
3171 * @ctxt: the XPath Parser context
3172 *
3173 * Implement the div operation on XPath objects @arg1 / @arg2:
3174 * The numeric operators convert their operands to numbers as if
3175 * by calling the number function.
3176 */
3177void
3178xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3179 xmlXPathObjectPtr arg;
3180 double val;
3181
3182 POP_FLOAT
3183 val = arg->floatval;
3184 xmlXPathFreeObject(arg);
3185
3186 POP_FLOAT
3187 arg->floatval /= val;
3188 valuePush(ctxt, arg);
3189}
3190
3191/**
3192 * xmlXPathModValues:
3193 * @ctxt: the XPath Parser context
3194 *
3195 * Implement the mod operation on XPath objects: @arg1 / @arg2
3196 * The numeric operators convert their operands to numbers as if
3197 * by calling the number function.
3198 */
3199void
3200xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3201 xmlXPathObjectPtr arg;
3202 int arg1, arg2;
3203
3204 POP_FLOAT
3205 arg2 = (int) arg->floatval;
3206 xmlXPathFreeObject(arg);
3207
3208 POP_FLOAT
3209 arg1 = (int) arg->floatval;
3210 arg->floatval = arg1 % arg2;
3211 valuePush(ctxt, arg);
3212}
3213
3214/************************************************************************
3215 * *
3216 * The traversal functions *
3217 * *
3218 ************************************************************************/
3219
Owen Taylor3473f882001-02-23 17:55:21 +00003220/*
3221 * A traversal function enumerates nodes along an axis.
3222 * Initially it must be called with NULL, and it indicates
3223 * termination on the axis by returning NULL.
3224 */
3225typedef xmlNodePtr (*xmlXPathTraversalFunction)
3226 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3227
3228/**
3229 * xmlXPathNextSelf:
3230 * @ctxt: the XPath Parser context
3231 * @cur: the current node in the traversal
3232 *
3233 * Traversal function for the "self" direction
3234 * The self axis contains just the context node itself
3235 *
3236 * Returns the next element following that axis
3237 */
3238xmlNodePtr
3239xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3240 if (cur == NULL)
3241 return(ctxt->context->node);
3242 return(NULL);
3243}
3244
3245/**
3246 * xmlXPathNextChild:
3247 * @ctxt: the XPath Parser context
3248 * @cur: the current node in the traversal
3249 *
3250 * Traversal function for the "child" direction
3251 * The child axis contains the children of the context node in document order.
3252 *
3253 * Returns the next element following that axis
3254 */
3255xmlNodePtr
3256xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3257 if (cur == NULL) {
3258 if (ctxt->context->node == NULL) return(NULL);
3259 switch (ctxt->context->node->type) {
3260 case XML_ELEMENT_NODE:
3261 case XML_TEXT_NODE:
3262 case XML_CDATA_SECTION_NODE:
3263 case XML_ENTITY_REF_NODE:
3264 case XML_ENTITY_NODE:
3265 case XML_PI_NODE:
3266 case XML_COMMENT_NODE:
3267 case XML_NOTATION_NODE:
3268 case XML_DTD_NODE:
3269 return(ctxt->context->node->children);
3270 case XML_DOCUMENT_NODE:
3271 case XML_DOCUMENT_TYPE_NODE:
3272 case XML_DOCUMENT_FRAG_NODE:
3273 case XML_HTML_DOCUMENT_NODE:
3274#ifdef LIBXML_SGML_ENABLED
3275 case XML_SGML_DOCUMENT_NODE:
3276#endif
3277 return(((xmlDocPtr) ctxt->context->node)->children);
3278 case XML_ELEMENT_DECL:
3279 case XML_ATTRIBUTE_DECL:
3280 case XML_ENTITY_DECL:
3281 case XML_ATTRIBUTE_NODE:
3282 case XML_NAMESPACE_DECL:
3283 case XML_XINCLUDE_START:
3284 case XML_XINCLUDE_END:
3285 return(NULL);
3286 }
3287 return(NULL);
3288 }
3289 if ((cur->type == XML_DOCUMENT_NODE) ||
3290 (cur->type == XML_HTML_DOCUMENT_NODE))
3291 return(NULL);
3292 return(cur->next);
3293}
3294
3295/**
3296 * xmlXPathNextDescendant:
3297 * @ctxt: the XPath Parser context
3298 * @cur: the current node in the traversal
3299 *
3300 * Traversal function for the "descendant" direction
3301 * the descendant axis contains the descendants of the context node in document
3302 * order; a descendant is a child or a child of a child and so on.
3303 *
3304 * Returns the next element following that axis
3305 */
3306xmlNodePtr
3307xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3308 if (cur == NULL) {
3309 if (ctxt->context->node == NULL)
3310 return(NULL);
3311 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3312 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3313 return(NULL);
3314
3315 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3316 return(ctxt->context->doc->children);
3317 return(ctxt->context->node->children);
3318 }
3319
3320 if (cur->children != NULL)
3321 {
3322 if (cur->children->type != XML_ENTITY_DECL)
3323 return(cur->children);
3324 }
3325 if (cur->next != NULL) return(cur->next);
3326
3327 do {
3328 cur = cur->parent;
3329 if (cur == NULL) return(NULL);
3330 if (cur == ctxt->context->node) return(NULL);
3331 if (cur->next != NULL) {
3332 cur = cur->next;
3333 return(cur);
3334 }
3335 } while (cur != NULL);
3336 return(cur);
3337}
3338
3339/**
3340 * xmlXPathNextDescendantOrSelf:
3341 * @ctxt: the XPath Parser context
3342 * @cur: the current node in the traversal
3343 *
3344 * Traversal function for the "descendant-or-self" direction
3345 * the descendant-or-self axis contains the context node and the descendants
3346 * of the context node in document order; thus the context node is the first
3347 * node on the axis, and the first child of the context node is the second node
3348 * on the axis
3349 *
3350 * Returns the next element following that axis
3351 */
3352xmlNodePtr
3353xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3354 if (cur == NULL) {
3355 if (ctxt->context->node == NULL)
3356 return(NULL);
3357 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3358 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3359 return(NULL);
3360 return(ctxt->context->node);
3361 }
3362
3363 return(xmlXPathNextDescendant(ctxt, cur));
3364}
3365
3366/**
3367 * xmlXPathNextParent:
3368 * @ctxt: the XPath Parser context
3369 * @cur: the current node in the traversal
3370 *
3371 * Traversal function for the "parent" direction
3372 * The parent axis contains the parent of the context node, if there is one.
3373 *
3374 * Returns the next element following that axis
3375 */
3376xmlNodePtr
3377xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3378 /*
3379 * the parent of an attribute or namespace node is the element
3380 * to which the attribute or namespace node is attached
3381 * Namespace handling !!!
3382 */
3383 if (cur == NULL) {
3384 if (ctxt->context->node == NULL) return(NULL);
3385 switch (ctxt->context->node->type) {
3386 case XML_ELEMENT_NODE:
3387 case XML_TEXT_NODE:
3388 case XML_CDATA_SECTION_NODE:
3389 case XML_ENTITY_REF_NODE:
3390 case XML_ENTITY_NODE:
3391 case XML_PI_NODE:
3392 case XML_COMMENT_NODE:
3393 case XML_NOTATION_NODE:
3394 case XML_DTD_NODE:
3395 case XML_ELEMENT_DECL:
3396 case XML_ATTRIBUTE_DECL:
3397 case XML_XINCLUDE_START:
3398 case XML_XINCLUDE_END:
3399 case XML_ENTITY_DECL:
3400 if (ctxt->context->node->parent == NULL)
3401 return((xmlNodePtr) ctxt->context->doc);
3402 return(ctxt->context->node->parent);
3403 case XML_ATTRIBUTE_NODE: {
3404 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3405
3406 return(att->parent);
3407 }
3408 case XML_DOCUMENT_NODE:
3409 case XML_DOCUMENT_TYPE_NODE:
3410 case XML_DOCUMENT_FRAG_NODE:
3411 case XML_HTML_DOCUMENT_NODE:
3412#ifdef LIBXML_SGML_ENABLED
3413 case XML_SGML_DOCUMENT_NODE:
3414#endif
3415 return(NULL);
3416 case XML_NAMESPACE_DECL:
3417 /*
3418 * TODO !!! may require extending struct _xmlNs with
3419 * parent field
3420 * C.f. Infoset case...
3421 */
3422 return(NULL);
3423 }
3424 }
3425 return(NULL);
3426}
3427
3428/**
3429 * xmlXPathNextAncestor:
3430 * @ctxt: the XPath Parser context
3431 * @cur: the current node in the traversal
3432 *
3433 * Traversal function for the "ancestor" direction
3434 * the ancestor axis contains the ancestors of the context node; the ancestors
3435 * of the context node consist of the parent of context node and the parent's
3436 * parent and so on; the nodes are ordered in reverse document order; thus the
3437 * parent is the first node on the axis, and the parent's parent is the second
3438 * node on the axis
3439 *
3440 * Returns the next element following that axis
3441 */
3442xmlNodePtr
3443xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3444 /*
3445 * the parent of an attribute or namespace node is the element
3446 * to which the attribute or namespace node is attached
3447 * !!!!!!!!!!!!!
3448 */
3449 if (cur == NULL) {
3450 if (ctxt->context->node == NULL) return(NULL);
3451 switch (ctxt->context->node->type) {
3452 case XML_ELEMENT_NODE:
3453 case XML_TEXT_NODE:
3454 case XML_CDATA_SECTION_NODE:
3455 case XML_ENTITY_REF_NODE:
3456 case XML_ENTITY_NODE:
3457 case XML_PI_NODE:
3458 case XML_COMMENT_NODE:
3459 case XML_DTD_NODE:
3460 case XML_ELEMENT_DECL:
3461 case XML_ATTRIBUTE_DECL:
3462 case XML_ENTITY_DECL:
3463 case XML_NOTATION_NODE:
3464 case XML_XINCLUDE_START:
3465 case XML_XINCLUDE_END:
3466 if (ctxt->context->node->parent == NULL)
3467 return((xmlNodePtr) ctxt->context->doc);
3468 return(ctxt->context->node->parent);
3469 case XML_ATTRIBUTE_NODE: {
3470 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
3471
3472 return(cur->parent);
3473 }
3474 case XML_DOCUMENT_NODE:
3475 case XML_DOCUMENT_TYPE_NODE:
3476 case XML_DOCUMENT_FRAG_NODE:
3477 case XML_HTML_DOCUMENT_NODE:
3478#ifdef LIBXML_SGML_ENABLED
3479 case XML_SGML_DOCUMENT_NODE:
3480#endif
3481 return(NULL);
3482 case XML_NAMESPACE_DECL:
3483 /*
3484 * TODO !!! may require extending struct _xmlNs with
3485 * parent field
3486 * C.f. Infoset case...
3487 */
3488 return(NULL);
3489 }
3490 return(NULL);
3491 }
3492 if (cur == ctxt->context->doc->children)
3493 return((xmlNodePtr) ctxt->context->doc);
3494 if (cur == (xmlNodePtr) ctxt->context->doc)
3495 return(NULL);
3496 switch (cur->type) {
3497 case XML_ELEMENT_NODE:
3498 case XML_TEXT_NODE:
3499 case XML_CDATA_SECTION_NODE:
3500 case XML_ENTITY_REF_NODE:
3501 case XML_ENTITY_NODE:
3502 case XML_PI_NODE:
3503 case XML_COMMENT_NODE:
3504 case XML_NOTATION_NODE:
3505 case XML_DTD_NODE:
3506 case XML_ELEMENT_DECL:
3507 case XML_ATTRIBUTE_DECL:
3508 case XML_ENTITY_DECL:
3509 case XML_XINCLUDE_START:
3510 case XML_XINCLUDE_END:
3511 return(cur->parent);
3512 case XML_ATTRIBUTE_NODE: {
3513 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3514
3515 return(att->parent);
3516 }
3517 case XML_DOCUMENT_NODE:
3518 case XML_DOCUMENT_TYPE_NODE:
3519 case XML_DOCUMENT_FRAG_NODE:
3520 case XML_HTML_DOCUMENT_NODE:
3521#ifdef LIBXML_SGML_ENABLED
3522 case XML_SGML_DOCUMENT_NODE:
3523#endif
3524 return(NULL);
3525 case XML_NAMESPACE_DECL:
3526 /*
3527 * TODO !!! may require extending struct _xmlNs with
3528 * parent field
3529 * C.f. Infoset case...
3530 */
3531 return(NULL);
3532 }
3533 return(NULL);
3534}
3535
3536/**
3537 * xmlXPathNextAncestorOrSelf:
3538 * @ctxt: the XPath Parser context
3539 * @cur: the current node in the traversal
3540 *
3541 * Traversal function for the "ancestor-or-self" direction
3542 * he ancestor-or-self axis contains the context node and ancestors of
3543 * the context node in reverse document order; thus the context node is
3544 * the first node on the axis, and the context node's parent the second;
3545 * parent here is defined the same as with the parent axis.
3546 *
3547 * Returns the next element following that axis
3548 */
3549xmlNodePtr
3550xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3551 if (cur == NULL)
3552 return(ctxt->context->node);
3553 return(xmlXPathNextAncestor(ctxt, cur));
3554}
3555
3556/**
3557 * xmlXPathNextFollowingSibling:
3558 * @ctxt: the XPath Parser context
3559 * @cur: the current node in the traversal
3560 *
3561 * Traversal function for the "following-sibling" direction
3562 * The following-sibling axis contains the following siblings of the context
3563 * node in document order.
3564 *
3565 * Returns the next element following that axis
3566 */
3567xmlNodePtr
3568xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3569 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3570 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3571 return(NULL);
3572 if (cur == (xmlNodePtr) ctxt->context->doc)
3573 return(NULL);
3574 if (cur == NULL)
3575 return(ctxt->context->node->next);
3576 return(cur->next);
3577}
3578
3579/**
3580 * xmlXPathNextPrecedingSibling:
3581 * @ctxt: the XPath Parser context
3582 * @cur: the current node in the traversal
3583 *
3584 * Traversal function for the "preceding-sibling" direction
3585 * The preceding-sibling axis contains the preceding siblings of the context
3586 * node in reverse document order; the first preceding sibling is first on the
3587 * axis; the sibling preceding that node is the second on the axis and so on.
3588 *
3589 * Returns the next element following that axis
3590 */
3591xmlNodePtr
3592xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3593 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3594 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3595 return(NULL);
3596 if (cur == (xmlNodePtr) ctxt->context->doc)
3597 return(NULL);
3598 if (cur == NULL)
3599 return(ctxt->context->node->prev);
3600 return(cur->prev);
3601}
3602
3603/**
3604 * xmlXPathNextFollowing:
3605 * @ctxt: the XPath Parser context
3606 * @cur: the current node in the traversal
3607 *
3608 * Traversal function for the "following" direction
3609 * The following axis contains all nodes in the same document as the context
3610 * node that are after the context node in document order, excluding any
3611 * descendants and excluding attribute nodes and namespace nodes; the nodes
3612 * are ordered in document order
3613 *
3614 * Returns the next element following that axis
3615 */
3616xmlNodePtr
3617xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3618 if (cur != NULL && cur->children != NULL)
3619 return cur->children ;
3620 if (cur == NULL) cur = ctxt->context->node;
3621 if (cur == NULL) return(NULL) ; /* ERROR */
3622 if (cur->next != NULL) return(cur->next) ;
3623 do {
3624 cur = cur->parent;
3625 if (cur == NULL) return(NULL);
3626 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
3627 if (cur->next != NULL) return(cur->next);
3628 } while (cur != NULL);
3629 return(cur);
3630}
3631
3632/*
3633 * xmlXPathIsAncestor:
3634 * @ancestor: the ancestor node
3635 * @node: the current node
3636 *
3637 * Check that @ancestor is a @node's ancestor
3638 *
3639 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
3640 */
3641static int
3642xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
3643 if ((ancestor == NULL) || (node == NULL)) return(0);
3644 /* nodes need to be in the same document */
3645 if (ancestor->doc != node->doc) return(0);
3646 /* avoid searching if ancestor or node is the root node */
3647 if (ancestor == (xmlNodePtr) node->doc) return(1);
3648 if (node == (xmlNodePtr) ancestor->doc) return(0);
3649 while (node->parent != NULL) {
3650 if (node->parent == ancestor)
3651 return(1);
3652 node = node->parent;
3653 }
3654 return(0);
3655}
3656
3657/**
3658 * xmlXPathNextPreceding:
3659 * @ctxt: the XPath Parser context
3660 * @cur: the current node in the traversal
3661 *
3662 * Traversal function for the "preceding" direction
3663 * the preceding axis contains all nodes in the same document as the context
3664 * node that are before the context node in document order, excluding any
3665 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
3666 * ordered in reverse document order
3667 *
3668 * Returns the next element following that axis
3669 */
3670xmlNodePtr
3671xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3672 if (cur == NULL)
3673 cur = ctxt->context->node ;
3674 do {
3675 if (cur->prev != NULL) {
3676 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
3677 ;
3678 return(cur) ;
3679 }
3680
3681 cur = cur->parent;
3682 if (cur == NULL) return(NULL);
3683 if (cur == ctxt->context->doc->children) return(NULL);
3684 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
3685 return(cur);
3686}
3687
3688/**
3689 * xmlXPathNextNamespace:
3690 * @ctxt: the XPath Parser context
3691 * @cur: the current attribute in the traversal
3692 *
3693 * Traversal function for the "namespace" direction
3694 * the namespace axis contains the namespace nodes of the context node;
3695 * the order of nodes on this axis is implementation-defined; the axis will
3696 * be empty unless the context node is an element
3697 *
3698 * Returns the next element following that axis
3699 */
3700xmlNodePtr
3701xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3702 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3703 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
3704 if (ctxt->context->namespaces != NULL)
3705 xmlFree(ctxt->context->namespaces);
3706 ctxt->context->namespaces =
3707 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
3708 if (ctxt->context->namespaces == NULL) return(NULL);
3709 ctxt->context->nsNr = 0;
3710 }
3711 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
3712}
3713
3714/**
3715 * xmlXPathNextAttribute:
3716 * @ctxt: the XPath Parser context
3717 * @cur: the current attribute in the traversal
3718 *
3719 * Traversal function for the "attribute" direction
3720 * TODO: support DTD inherited default attributes
3721 *
3722 * Returns the next element following that axis
3723 */
3724xmlNodePtr
3725xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3726 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3727 if (cur == NULL) {
3728 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3729 return(NULL);
3730 return((xmlNodePtr)ctxt->context->node->properties);
3731 }
3732 return((xmlNodePtr)cur->next);
3733}
3734
3735/************************************************************************
3736 * *
3737 * NodeTest Functions *
3738 * *
3739 ************************************************************************/
3740
Owen Taylor3473f882001-02-23 17:55:21 +00003741#define IS_FUNCTION 200
3742
3743/**
3744 * xmlXPathNodeCollectAndTest:
3745 * @ctxt: the XPath Parser context
3746 * @axis: the XPath axis
3747 * @test: the XPath test
3748 * @type: the XPath type
3749 * @prefix: the namesapce prefix if any
3750 * @name: the name used in the search if any
3751 *
3752 * This is the function implementing a step: based on the current list
3753 * of nodes, it builds up a new list, looking at all nodes under that
3754 * axis and selecting them.
3755 *
3756 * Returns the new NodeSet resulting from the search.
3757 */
3758void
3759xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
3760 xmlXPathTestVal test, xmlXPathTypeVal type,
3761 const xmlChar *prefix, const xmlChar *name) {
3762#ifdef DEBUG_STEP
3763 int n = 0, t = 0;
3764#endif
3765 int i;
3766 xmlNodeSetPtr ret;
3767 xmlXPathTraversalFunction next = NULL;
3768 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
3769 xmlNodePtr cur = NULL;
3770 xmlXPathObjectPtr obj;
3771 xmlNodeSetPtr nodelist;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003772 xmlNodePtr tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00003773
3774 CHECK_TYPE(XPATH_NODESET);
3775 obj = valuePop(ctxt);
3776 addNode = xmlXPathNodeSetAdd;
3777
3778#ifdef DEBUG_STEP
3779 xmlGenericError(xmlGenericErrorContext,
3780 "new step : ");
3781#endif
3782 switch (axis) {
3783 case AXIS_ANCESTOR:
3784#ifdef DEBUG_STEP
3785 xmlGenericError(xmlGenericErrorContext,
3786 "axis 'ancestors' ");
3787#endif
3788 next = xmlXPathNextAncestor; break;
3789 case AXIS_ANCESTOR_OR_SELF:
3790#ifdef DEBUG_STEP
3791 xmlGenericError(xmlGenericErrorContext,
3792 "axis 'ancestors-or-self' ");
3793#endif
3794 next = xmlXPathNextAncestorOrSelf; break;
3795 case AXIS_ATTRIBUTE:
3796#ifdef DEBUG_STEP
3797 xmlGenericError(xmlGenericErrorContext,
3798 "axis 'attributes' ");
3799#endif
3800 next = xmlXPathNextAttribute; break;
3801 break;
3802 case AXIS_CHILD:
3803#ifdef DEBUG_STEP
3804 xmlGenericError(xmlGenericErrorContext,
3805 "axis 'child' ");
3806#endif
3807 next = xmlXPathNextChild; break;
3808 case AXIS_DESCENDANT:
3809#ifdef DEBUG_STEP
3810 xmlGenericError(xmlGenericErrorContext,
3811 "axis 'descendant' ");
3812#endif
3813 next = xmlXPathNextDescendant; break;
3814 case AXIS_DESCENDANT_OR_SELF:
3815#ifdef DEBUG_STEP
3816 xmlGenericError(xmlGenericErrorContext,
3817 "axis 'descendant-or-self' ");
3818#endif
3819 next = xmlXPathNextDescendantOrSelf; break;
3820 case AXIS_FOLLOWING:
3821#ifdef DEBUG_STEP
3822 xmlGenericError(xmlGenericErrorContext,
3823 "axis 'following' ");
3824#endif
3825 next = xmlXPathNextFollowing; break;
3826 case AXIS_FOLLOWING_SIBLING:
3827#ifdef DEBUG_STEP
3828 xmlGenericError(xmlGenericErrorContext,
3829 "axis 'following-siblings' ");
3830#endif
3831 next = xmlXPathNextFollowingSibling; break;
3832 case AXIS_NAMESPACE:
3833#ifdef DEBUG_STEP
3834 xmlGenericError(xmlGenericErrorContext,
3835 "axis 'namespace' ");
3836#endif
3837 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
3838 break;
3839 case AXIS_PARENT:
3840#ifdef DEBUG_STEP
3841 xmlGenericError(xmlGenericErrorContext,
3842 "axis 'parent' ");
3843#endif
3844 next = xmlXPathNextParent; break;
3845 case AXIS_PRECEDING:
3846#ifdef DEBUG_STEP
3847 xmlGenericError(xmlGenericErrorContext,
3848 "axis 'preceding' ");
3849#endif
3850 next = xmlXPathNextPreceding; break;
3851 case AXIS_PRECEDING_SIBLING:
3852#ifdef DEBUG_STEP
3853 xmlGenericError(xmlGenericErrorContext,
3854 "axis 'preceding-sibling' ");
3855#endif
3856 next = xmlXPathNextPrecedingSibling; break;
3857 case AXIS_SELF:
3858#ifdef DEBUG_STEP
3859 xmlGenericError(xmlGenericErrorContext,
3860 "axis 'self' ");
3861#endif
3862 next = xmlXPathNextSelf; break;
3863 }
3864 if (next == NULL)
3865 return;
3866
3867 nodelist = obj->nodesetval;
3868 if ((nodelist != NULL) &&
3869 (nodelist->nodeNr <= 1))
3870 addNode = xmlXPathNodeSetAddUnique;
3871 else
3872 addNode = xmlXPathNodeSetAdd;
3873 ret = xmlXPathNodeSetCreate(NULL);
3874#ifdef DEBUG_STEP
3875 xmlGenericError(xmlGenericErrorContext,
3876 " context contains %d nodes\n",
3877 nodelist->nodeNr);
3878 switch (test) {
3879 case NODE_TEST_NODE:
3880 xmlGenericError(xmlGenericErrorContext,
3881 " searching all nodes\n");
3882 break;
3883 case NODE_TEST_NONE:
3884 xmlGenericError(xmlGenericErrorContext,
3885 " searching for none !!!\n");
3886 break;
3887 case NODE_TEST_TYPE:
3888 xmlGenericError(xmlGenericErrorContext,
3889 " searching for type %d\n", type);
3890 break;
3891 case NODE_TEST_PI:
3892 xmlGenericError(xmlGenericErrorContext,
3893 " searching for PI !!!\n");
3894 break;
3895 case NODE_TEST_ALL:
3896 xmlGenericError(xmlGenericErrorContext,
3897 " searching for *\n");
3898 break;
3899 case NODE_TEST_NS:
3900 xmlGenericError(xmlGenericErrorContext,
3901 " searching for namespace %s\n",
3902 prefix);
3903 break;
3904 case NODE_TEST_NAME:
3905 xmlGenericError(xmlGenericErrorContext,
3906 " searching for name %s\n", name);
3907 if (prefix != NULL)
3908 xmlGenericError(xmlGenericErrorContext,
3909 " with namespace %s\n",
3910 prefix);
3911 break;
3912 }
3913 xmlGenericError(xmlGenericErrorContext, "Testing : ");
3914#endif
3915 /*
3916 * 2.3 Node Tests
3917 * - For the attribute axis, the principal node type is attribute.
3918 * - For the namespace axis, the principal node type is namespace.
3919 * - For other axes, the principal node type is element.
3920 *
3921 * A node test * is true for any node of the
3922 * principal node type. For example, child::* willi
3923 * select all element children of the context node
3924 */
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003925 tmp = ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00003926 for (i = 0;i < nodelist->nodeNr; i++) {
3927 ctxt->context->node = nodelist->nodeTab[i];
3928
3929 cur = NULL;
3930 do {
3931 cur = next(ctxt, cur);
3932 if (cur == NULL) break;
3933#ifdef DEBUG_STEP
3934 t++;
3935 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
3936#endif
3937 switch (test) {
3938 case NODE_TEST_NONE:
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003939 ctxt->context->node = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00003940 STRANGE
3941 return;
3942 case NODE_TEST_TYPE:
3943 if ((cur->type == type) ||
3944 ((type == NODE_TYPE_NODE) &&
3945 ((cur->type == XML_DOCUMENT_NODE) ||
3946 (cur->type == XML_HTML_DOCUMENT_NODE) ||
3947 (cur->type == XML_ELEMENT_NODE) ||
3948 (cur->type == XML_PI_NODE) ||
3949 (cur->type == XML_COMMENT_NODE) ||
3950 (cur->type == XML_CDATA_SECTION_NODE) ||
3951 (cur->type == XML_TEXT_NODE)))) {
3952#ifdef DEBUG_STEP
3953 n++;
3954#endif
3955 addNode(ret, cur);
3956 }
3957 break;
3958 case NODE_TEST_PI:
3959 if (cur->type == XML_PI_NODE) {
3960 if ((name != NULL) &&
3961 (!xmlStrEqual(name, cur->name)))
3962 break;
3963#ifdef DEBUG_STEP
3964 n++;
3965#endif
3966 addNode(ret, cur);
3967 }
3968 break;
3969 case NODE_TEST_ALL:
3970 if (axis == AXIS_ATTRIBUTE) {
3971 if (cur->type == XML_ATTRIBUTE_NODE) {
3972#ifdef DEBUG_STEP
3973 n++;
3974#endif
3975 addNode(ret, cur);
3976 }
3977 } else if (axis == AXIS_NAMESPACE) {
3978 if (cur->type == XML_NAMESPACE_DECL) {
3979#ifdef DEBUG_STEP
3980 n++;
3981#endif
3982 addNode(ret, cur);
3983 }
3984 } else {
3985 if ((cur->type == XML_ELEMENT_NODE) ||
3986 (cur->type == XML_DOCUMENT_NODE) ||
3987 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3988 if (prefix == NULL) {
3989#ifdef DEBUG_STEP
3990 n++;
3991#endif
3992 addNode(ret, cur);
3993 } else if ((cur->ns != NULL) &&
3994 (xmlStrEqual(prefix,
3995 cur->ns->href))) {
3996#ifdef DEBUG_STEP
3997 n++;
3998#endif
3999 addNode(ret, cur);
4000 }
4001 }
4002 }
4003 break;
4004 case NODE_TEST_NS: {
4005 TODO;
4006 break;
4007 }
4008 case NODE_TEST_NAME:
4009 switch (cur->type) {
4010 case XML_ELEMENT_NODE:
4011 if (xmlStrEqual(name, cur->name)) {
4012 if (prefix == NULL) {
4013 if ((cur->ns == NULL) ||
4014 (cur->ns->prefix == NULL)) {
4015#ifdef DEBUG_STEP
4016 n++;
4017#endif
4018 addNode(ret, cur);
4019 }
4020 } else {
4021 if ((cur->ns != NULL) &&
4022 (xmlStrEqual(prefix,
4023 cur->ns->href))) {
4024#ifdef DEBUG_STEP
4025 n++;
4026#endif
4027 addNode(ret, cur);
4028 }
4029 }
4030 }
4031 break;
4032 case XML_ATTRIBUTE_NODE: {
4033 xmlAttrPtr attr = (xmlAttrPtr) cur;
4034 if (xmlStrEqual(name, attr->name)) {
4035 if (prefix == NULL) {
4036 if ((attr->ns == NULL) ||
4037 (attr->ns->prefix == NULL)) {
4038#ifdef DEBUG_STEP
4039 n++;
4040#endif
4041 addNode(ret, (xmlNodePtr) attr);
4042 }
4043 } else {
4044 if ((attr->ns != NULL) &&
4045 (xmlStrEqual(prefix,
4046 attr->ns->href))) {
4047#ifdef DEBUG_STEP
4048 n++;
4049#endif
4050 addNode(ret, (xmlNodePtr) attr);
4051 }
4052 }
4053 }
4054 break;
4055 }
4056 case XML_NAMESPACE_DECL: {
4057 TODO;
4058 break;
4059 }
4060 default:
4061 break;
4062 }
4063 break;
4064 }
4065 } while (cur != NULL);
4066 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004067 ctxt->context->node = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004068#ifdef DEBUG_STEP
4069 xmlGenericError(xmlGenericErrorContext,
4070 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
4071#endif
4072 xmlXPathFreeObject(obj);
4073 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
4074}
4075
4076
4077/************************************************************************
4078 * *
4079 * Implicit tree core function library *
4080 * *
4081 ************************************************************************/
4082
4083/**
4084 * xmlXPathRoot:
4085 * @ctxt: the XPath Parser context
4086 *
4087 * Initialize the context to the root of the document
4088 */
4089void
4090xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
4091 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
4092 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4093}
4094
4095/************************************************************************
4096 * *
4097 * The explicit core function library *
4098 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
4099 * *
4100 ************************************************************************/
4101
4102
4103/**
4104 * xmlXPathLastFunction:
4105 * @ctxt: the XPath Parser context
4106 * @nargs: the number of arguments
4107 *
4108 * Implement the last() XPath function
4109 * number last()
4110 * The last function returns the number of nodes in the context node list.
4111 */
4112void
4113xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4114 CHECK_ARITY(0);
4115 if (ctxt->context->contextSize >= 0) {
4116 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
4117#ifdef DEBUG_EXPR
4118 xmlGenericError(xmlGenericErrorContext,
4119 "last() : %d\n", ctxt->context->contextSize);
4120#endif
4121 } else {
4122 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
4123 }
4124}
4125
4126/**
4127 * xmlXPathPositionFunction:
4128 * @ctxt: the XPath Parser context
4129 * @nargs: the number of arguments
4130 *
4131 * Implement the position() XPath function
4132 * number position()
4133 * The position function returns the position of the context node in the
4134 * context node list. The first position is 1, and so the last positionr
4135 * will be equal to last().
4136 */
4137void
4138xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4139 CHECK_ARITY(0);
4140 if (ctxt->context->proximityPosition >= 0) {
4141 valuePush(ctxt,
4142 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
4143#ifdef DEBUG_EXPR
4144 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
4145 ctxt->context->proximityPosition);
4146#endif
4147 } else {
4148 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
4149 }
4150}
4151
4152/**
4153 * xmlXPathCountFunction:
4154 * @ctxt: the XPath Parser context
4155 * @nargs: the number of arguments
4156 *
4157 * Implement the count() XPath function
4158 * number count(node-set)
4159 */
4160void
4161xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4162 xmlXPathObjectPtr cur;
4163
4164 CHECK_ARITY(1);
4165 if ((ctxt->value == NULL) ||
4166 ((ctxt->value->type != XPATH_NODESET) &&
4167 (ctxt->value->type != XPATH_XSLT_TREE)))
4168 XP_ERROR(XPATH_INVALID_TYPE);
4169 cur = valuePop(ctxt);
4170
4171 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
4172 xmlXPathFreeObject(cur);
4173}
4174
4175/**
4176 * xmlXPathIdFunction:
4177 * @ctxt: the XPath Parser context
4178 * @nargs: the number of arguments
4179 *
4180 * Implement the id() XPath function
4181 * node-set id(object)
4182 * The id function selects elements by their unique ID
4183 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
4184 * then the result is the union of the result of applying id to the
4185 * string value of each of the nodes in the argument node-set. When the
4186 * argument to id is of any other type, the argument is converted to a
4187 * string as if by a call to the string function; the string is split
4188 * into a whitespace-separated list of tokens (whitespace is any sequence
4189 * of characters matching the production S); the result is a node-set
4190 * containing the elements in the same document as the context node that
4191 * have a unique ID equal to any of the tokens in the list.
4192 */
4193void
4194xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4195 const xmlChar *tokens;
4196 const xmlChar *cur;
4197 xmlChar *ID;
4198 xmlAttrPtr attr;
4199 xmlNodePtr elem = NULL;
4200 xmlXPathObjectPtr ret, obj;
4201
4202 CHECK_ARITY(1);
4203 obj = valuePop(ctxt);
4204 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
4205 if (obj->type == XPATH_NODESET) {
4206 xmlXPathObjectPtr newobj;
4207 int i;
4208
4209 ret = xmlXPathNewNodeSet(NULL);
4210
4211 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
4212 valuePush(ctxt,
4213 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
4214 xmlXPathStringFunction(ctxt, 1);
4215 xmlXPathIdFunction(ctxt, 1);
4216 newobj = valuePop(ctxt);
4217 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
4218 newobj->nodesetval);
4219 xmlXPathFreeObject(newobj);
4220 }
4221
4222 xmlXPathFreeObject(obj);
4223 valuePush(ctxt, ret);
4224 return;
4225 }
4226 if (obj->type != XPATH_STRING) {
4227 valuePush(ctxt, obj);
4228 xmlXPathStringFunction(ctxt, 1);
4229 obj = valuePop(ctxt);
4230 if (obj->type != XPATH_STRING) {
4231 xmlXPathFreeObject(obj);
4232 return;
4233 }
4234 }
4235 tokens = obj->stringval;
4236
4237 ret = xmlXPathNewNodeSet(NULL);
4238 valuePush(ctxt, ret);
4239 if (tokens == NULL) {
4240 xmlXPathFreeObject(obj);
4241 return;
4242 }
4243
4244 cur = tokens;
4245
4246 while (IS_BLANK(*cur)) cur++;
4247 while (*cur != 0) {
4248 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
4249 (*cur == '.') || (*cur == '-') ||
4250 (*cur == '_') || (*cur == ':') ||
4251 (IS_COMBINING(*cur)) ||
4252 (IS_EXTENDER(*cur)))
4253 cur++;
4254
4255 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
4256
4257 ID = xmlStrndup(tokens, cur - tokens);
4258 attr = xmlGetID(ctxt->context->doc, ID);
4259 if (attr != NULL) {
4260 elem = attr->parent;
4261 xmlXPathNodeSetAdd(ret->nodesetval, elem);
4262 }
4263 if (ID != NULL)
4264 xmlFree(ID);
4265
4266 while (IS_BLANK(*cur)) cur++;
4267 tokens = cur;
4268 }
4269 xmlXPathFreeObject(obj);
4270 return;
4271}
4272
4273/**
4274 * xmlXPathLocalNameFunction:
4275 * @ctxt: the XPath Parser context
4276 * @nargs: the number of arguments
4277 *
4278 * Implement the local-name() XPath function
4279 * string local-name(node-set?)
4280 * The local-name function returns a string containing the local part
4281 * of the name of the node in the argument node-set that is first in
4282 * document order. If the node-set is empty or the first node has no
4283 * name, an empty string is returned. If the argument is omitted it
4284 * defaults to the context node.
4285 */
4286void
4287xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4288 xmlXPathObjectPtr cur;
4289
4290 if (nargs == 0) {
4291 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4292 nargs = 1;
4293 }
4294
4295 CHECK_ARITY(1);
4296 if ((ctxt->value == NULL) ||
4297 ((ctxt->value->type != XPATH_NODESET) &&
4298 (ctxt->value->type != XPATH_XSLT_TREE)))
4299 XP_ERROR(XPATH_INVALID_TYPE);
4300 cur = valuePop(ctxt);
4301
4302 if (cur->nodesetval->nodeNr == 0) {
4303 valuePush(ctxt, xmlXPathNewCString(""));
4304 } else {
4305 int i = 0; /* Should be first in document order !!!!! */
4306 switch (cur->nodesetval->nodeTab[i]->type) {
4307 case XML_ELEMENT_NODE:
4308 case XML_ATTRIBUTE_NODE:
4309 case XML_PI_NODE:
4310 valuePush(ctxt,
4311 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4312 break;
4313 case XML_NAMESPACE_DECL:
4314 valuePush(ctxt, xmlXPathNewString(
4315 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4316 break;
4317 default:
4318 valuePush(ctxt, xmlXPathNewCString(""));
4319 }
4320 }
4321 xmlXPathFreeObject(cur);
4322}
4323
4324/**
4325 * xmlXPathNamespaceURIFunction:
4326 * @ctxt: the XPath Parser context
4327 * @nargs: the number of arguments
4328 *
4329 * Implement the namespace-uri() XPath function
4330 * string namespace-uri(node-set?)
4331 * The namespace-uri function returns a string containing the
4332 * namespace URI of the expanded name of the node in the argument
4333 * node-set that is first in document order. If the node-set is empty,
4334 * the first node has no name, or the expanded name has no namespace
4335 * URI, an empty string is returned. If the argument is omitted it
4336 * defaults to the context node.
4337 */
4338void
4339xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4340 xmlXPathObjectPtr cur;
4341
4342 if (nargs == 0) {
4343 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4344 nargs = 1;
4345 }
4346 CHECK_ARITY(1);
4347 if ((ctxt->value == NULL) ||
4348 ((ctxt->value->type != XPATH_NODESET) &&
4349 (ctxt->value->type != XPATH_XSLT_TREE)))
4350 XP_ERROR(XPATH_INVALID_TYPE);
4351 cur = valuePop(ctxt);
4352
4353 if (cur->nodesetval->nodeNr == 0) {
4354 valuePush(ctxt, xmlXPathNewCString(""));
4355 } else {
4356 int i = 0; /* Should be first in document order !!!!! */
4357 switch (cur->nodesetval->nodeTab[i]->type) {
4358 case XML_ELEMENT_NODE:
4359 case XML_ATTRIBUTE_NODE:
4360 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4361 valuePush(ctxt, xmlXPathNewCString(""));
4362 else
4363 valuePush(ctxt, xmlXPathNewString(
4364 cur->nodesetval->nodeTab[i]->ns->href));
4365 break;
4366 default:
4367 valuePush(ctxt, xmlXPathNewCString(""));
4368 }
4369 }
4370 xmlXPathFreeObject(cur);
4371}
4372
4373/**
4374 * xmlXPathNameFunction:
4375 * @ctxt: the XPath Parser context
4376 * @nargs: the number of arguments
4377 *
4378 * Implement the name() XPath function
4379 * string name(node-set?)
4380 * The name function returns a string containing a QName representing
4381 * the name of the node in the argument node-set that is first in documenti
4382 * order. The QName must represent the name with respect to the namespace
4383 * declarations in effect on the node whose name is being represented.
4384 * Typically, this will be the form in which the name occurred in the XML
4385 * source. This need not be the case if there are namespace declarations
4386 * in effect on the node that associate multiple prefixes with the same
4387 * namespace. However, an implementation may include information about
4388 * the original prefix in its representation of nodes; in this case, an
4389 * implementation can ensure that the returned string is always the same
4390 * as the QName used in the XML source. If the argument it omitted it
4391 * defaults to the context node.
4392 * Libxml keep the original prefix so the "real qualified name" used is
4393 * returned.
4394 */
4395void
4396xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4397 xmlXPathObjectPtr cur;
4398
4399 if (nargs == 0) {
4400 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4401 nargs = 1;
4402 }
4403
4404 CHECK_ARITY(1);
4405 if ((ctxt->value == NULL) ||
4406 ((ctxt->value->type != XPATH_NODESET) &&
4407 (ctxt->value->type != XPATH_XSLT_TREE)))
4408 XP_ERROR(XPATH_INVALID_TYPE);
4409 cur = valuePop(ctxt);
4410
4411 if (cur->nodesetval->nodeNr == 0) {
4412 valuePush(ctxt, xmlXPathNewCString(""));
4413 } else {
4414 int i = 0; /* Should be first in document order !!!!! */
4415
4416 switch (cur->nodesetval->nodeTab[i]->type) {
4417 case XML_ELEMENT_NODE:
4418 case XML_ATTRIBUTE_NODE:
4419 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4420 valuePush(ctxt, xmlXPathNewString(
4421 cur->nodesetval->nodeTab[i]->name));
4422
4423 else {
4424 char name[2000];
4425#ifdef HAVE_SNPRINTF
4426 snprintf(name, sizeof(name), "%s:%s",
4427 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4428 (char *) cur->nodesetval->nodeTab[i]->name);
4429#else
4430 sprintf(name, "%s:%s",
4431 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4432 (char *) cur->nodesetval->nodeTab[i]->name);
4433#endif
4434 name[sizeof(name) - 1] = 0;
4435 valuePush(ctxt, xmlXPathNewCString(name));
4436 }
4437 break;
4438 default:
4439 valuePush(ctxt,
4440 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4441 xmlXPathLocalNameFunction(ctxt, 1);
4442 }
4443 }
4444 xmlXPathFreeObject(cur);
4445}
4446
4447/**
4448 * xmlXPathStringFunction:
4449 * @ctxt: the XPath Parser context
4450 * @nargs: the number of arguments
4451 *
4452 * Implement the string() XPath function
4453 * string string(object?)
4454 * he string function converts an object to a string as follows:
4455 * - A node-set is converted to a string by returning the value of
4456 * the node in the node-set that is first in document order.
4457 * If the node-set is empty, an empty string is returned.
4458 * - A number is converted to a string as follows
4459 * + NaN is converted to the string NaN
4460 * + positive zero is converted to the string 0
4461 * + negative zero is converted to the string 0
4462 * + positive infinity is converted to the string Infinity
4463 * + negative infinity is converted to the string -Infinity
4464 * + if the number is an integer, the number is represented in
4465 * decimal form as a Number with no decimal point and no leading
4466 * zeros, preceded by a minus sign (-) if the number is negative
4467 * + otherwise, the number is represented in decimal form as a
4468 * Number including a decimal point with at least one digit
4469 * before the decimal point and at least one digit after the
4470 * decimal point, preceded by a minus sign (-) if the number
4471 * is negative; there must be no leading zeros before the decimal
4472 * point apart possibly from the one required digit immediatelyi
4473 * before the decimal point; beyond the one required digit
4474 * after the decimal point there must be as many, but only as
4475 * many, more digits as are needed to uniquely distinguish the
4476 * number from all other IEEE 754 numeric values.
4477 * - The boolean false value is converted to the string false.
4478 * The boolean true value is converted to the string true.
4479 *
4480 * If the argument is omitted, it defaults to a node-set with the
4481 * context node as its only member.
4482 */
4483void
4484xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4485 xmlXPathObjectPtr cur;
4486
4487 if (nargs == 0) {
4488 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4489 nargs = 1;
4490 }
4491
4492 CHECK_ARITY(1);
4493 cur = valuePop(ctxt);
4494 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
4495 switch (cur->type) {
4496 case XPATH_UNDEFINED:
4497#ifdef DEBUG_EXPR
4498 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
4499#endif
4500 valuePush(ctxt, xmlXPathNewCString(""));
4501 break;
4502 case XPATH_XSLT_TREE:
4503 case XPATH_NODESET:
4504 if (cur->nodesetval == NULL)
4505 valuePush(ctxt, xmlXPathNewCString(""));
4506 else if (cur->nodesetval->nodeNr == 0) {
4507 valuePush(ctxt, xmlXPathNewCString(""));
4508 } else {
4509 xmlChar *res;
4510 int i = 0; /* Should be first in document order !!!!! */
4511 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
4512 valuePush(ctxt, xmlXPathNewString(res));
4513 if (res != NULL)
4514 xmlFree(res);
4515 }
4516 xmlXPathFreeObject(cur);
4517 return;
4518 case XPATH_STRING:
4519 valuePush(ctxt, cur);
4520 return;
4521 case XPATH_BOOLEAN:
4522 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
4523 else valuePush(ctxt, xmlXPathNewCString("false"));
4524 xmlXPathFreeObject(cur);
4525 return;
4526 case XPATH_NUMBER: {
4527 char buf[100];
4528
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004529 xmlXPathFormatNumber(cur->floatval, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00004530 valuePush(ctxt, xmlXPathNewCString(buf));
4531 xmlXPathFreeObject(cur);
4532 return;
4533 }
4534 case XPATH_USERS:
4535 case XPATH_POINT:
4536 case XPATH_RANGE:
4537 case XPATH_LOCATIONSET:
4538 TODO
4539 valuePush(ctxt, xmlXPathNewCString(""));
4540 break;
4541 }
4542 STRANGE
4543}
4544
4545/**
4546 * xmlXPathStringLengthFunction:
4547 * @ctxt: the XPath Parser context
4548 * @nargs: the number of arguments
4549 *
4550 * Implement the string-length() XPath function
4551 * number string-length(string?)
4552 * The string-length returns the number of characters in the string
4553 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4554 * the context node converted to a string, in other words the value
4555 * of the context node.
4556 */
4557void
4558xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4559 xmlXPathObjectPtr cur;
4560
4561 if (nargs == 0) {
4562 if (ctxt->context->node == NULL) {
4563 valuePush(ctxt, xmlXPathNewFloat(0));
4564 } else {
4565 xmlChar *content;
4566
4567 content = xmlNodeGetContent(ctxt->context->node);
4568 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
4569 xmlFree(content);
4570 }
4571 return;
4572 }
4573 CHECK_ARITY(1);
4574 CAST_TO_STRING;
4575 CHECK_TYPE(XPATH_STRING);
4576 cur = valuePop(ctxt);
4577 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
4578 xmlXPathFreeObject(cur);
4579}
4580
4581/**
4582 * xmlXPathConcatFunction:
4583 * @ctxt: the XPath Parser context
4584 * @nargs: the number of arguments
4585 *
4586 * Implement the concat() XPath function
4587 * string concat(string, string, string*)
4588 * The concat function returns the concatenation of its arguments.
4589 */
4590void
4591xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4592 xmlXPathObjectPtr cur, newobj;
4593 xmlChar *tmp;
4594
4595 if (nargs < 2) {
4596 CHECK_ARITY(2);
4597 }
4598
4599 CAST_TO_STRING;
4600 cur = valuePop(ctxt);
4601 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4602 xmlXPathFreeObject(cur);
4603 return;
4604 }
4605 nargs--;
4606
4607 while (nargs > 0) {
4608 CAST_TO_STRING;
4609 newobj = valuePop(ctxt);
4610 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4611 xmlXPathFreeObject(newobj);
4612 xmlXPathFreeObject(cur);
4613 XP_ERROR(XPATH_INVALID_TYPE);
4614 }
4615 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4616 newobj->stringval = cur->stringval;
4617 cur->stringval = tmp;
4618
4619 xmlXPathFreeObject(newobj);
4620 nargs--;
4621 }
4622 valuePush(ctxt, cur);
4623}
4624
4625/**
4626 * xmlXPathContainsFunction:
4627 * @ctxt: the XPath Parser context
4628 * @nargs: the number of arguments
4629 *
4630 * Implement the contains() XPath function
4631 * boolean contains(string, string)
4632 * The contains function returns true if the first argument string
4633 * contains the second argument string, and otherwise returns false.
4634 */
4635void
4636xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4637 xmlXPathObjectPtr hay, needle;
4638
4639 CHECK_ARITY(2);
4640 CAST_TO_STRING;
4641 CHECK_TYPE(XPATH_STRING);
4642 needle = valuePop(ctxt);
4643 CAST_TO_STRING;
4644 hay = valuePop(ctxt);
4645 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4646 xmlXPathFreeObject(hay);
4647 xmlXPathFreeObject(needle);
4648 XP_ERROR(XPATH_INVALID_TYPE);
4649 }
4650 if (xmlStrstr(hay->stringval, needle->stringval))
4651 valuePush(ctxt, xmlXPathNewBoolean(1));
4652 else
4653 valuePush(ctxt, xmlXPathNewBoolean(0));
4654 xmlXPathFreeObject(hay);
4655 xmlXPathFreeObject(needle);
4656}
4657
4658/**
4659 * xmlXPathStartsWithFunction:
4660 * @ctxt: the XPath Parser context
4661 * @nargs: the number of arguments
4662 *
4663 * Implement the starts-with() XPath function
4664 * boolean starts-with(string, string)
4665 * The starts-with function returns true if the first argument string
4666 * starts with the second argument string, and otherwise returns false.
4667 */
4668void
4669xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4670 xmlXPathObjectPtr hay, needle;
4671 int n;
4672
4673 CHECK_ARITY(2);
4674 CAST_TO_STRING;
4675 CHECK_TYPE(XPATH_STRING);
4676 needle = valuePop(ctxt);
4677 CAST_TO_STRING;
4678 hay = valuePop(ctxt);
4679 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4680 xmlXPathFreeObject(hay);
4681 xmlXPathFreeObject(needle);
4682 XP_ERROR(XPATH_INVALID_TYPE);
4683 }
4684 n = xmlStrlen(needle->stringval);
4685 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4686 valuePush(ctxt, xmlXPathNewBoolean(0));
4687 else
4688 valuePush(ctxt, xmlXPathNewBoolean(1));
4689 xmlXPathFreeObject(hay);
4690 xmlXPathFreeObject(needle);
4691}
4692
4693/**
4694 * xmlXPathSubstringFunction:
4695 * @ctxt: the XPath Parser context
4696 * @nargs: the number of arguments
4697 *
4698 * Implement the substring() XPath function
4699 * string substring(string, number, number?)
4700 * The substring function returns the substring of the first argument
4701 * starting at the position specified in the second argument with
4702 * length specified in the third argument. For example,
4703 * substring("12345",2,3) returns "234". If the third argument is not
4704 * specified, it returns the substring starting at the position specified
4705 * in the second argument and continuing to the end of the string. For
4706 * example, substring("12345",2) returns "2345". More precisely, each
4707 * character in the string (see [3.6 Strings]) is considered to have a
4708 * numeric position: the position of the first character is 1, the position
4709 * of the second character is 2 and so on. The returned substring contains
4710 * those characters for which the position of the character is greater than
4711 * or equal to the second argument and, if the third argument is specified,
4712 * less than the sum of the second and third arguments; the comparisons
4713 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4714 * - substring("12345", 1.5, 2.6) returns "234"
4715 * - substring("12345", 0, 3) returns "12"
4716 * - substring("12345", 0 div 0, 3) returns ""
4717 * - substring("12345", 1, 0 div 0) returns ""
4718 * - substring("12345", -42, 1 div 0) returns "12345"
4719 * - substring("12345", -1 div 0, 1 div 0) returns ""
4720 */
4721void
4722xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4723 xmlXPathObjectPtr str, start, len;
4724 double le, in;
4725 int i, l;
4726 xmlChar *ret;
4727
4728 /*
4729 * Conformance needs to be checked !!!!!
4730 */
4731 if (nargs < 2) {
4732 CHECK_ARITY(2);
4733 }
4734 if (nargs > 3) {
4735 CHECK_ARITY(3);
4736 }
4737 if (nargs == 3) {
4738 CAST_TO_NUMBER;
4739 CHECK_TYPE(XPATH_NUMBER);
4740 len = valuePop(ctxt);
4741 le = len->floatval;
4742 xmlXPathFreeObject(len);
4743 } else {
4744 le = 2000000000;
4745 }
4746 CAST_TO_NUMBER;
4747 CHECK_TYPE(XPATH_NUMBER);
4748 start = valuePop(ctxt);
4749 in = start->floatval;
4750 xmlXPathFreeObject(start);
4751 CAST_TO_STRING;
4752 CHECK_TYPE(XPATH_STRING);
4753 str = valuePop(ctxt);
4754 le += in;
4755
4756 /* integer index of the first char */
4757 i = (int) in;
4758 if (((double)i) != in) i++;
4759
4760 /* integer index of the last char */
4761 l = (int) le;
4762 if (((double)l) != le) l++;
4763
4764 /* back to a zero based len */
4765 i--;
4766 l--;
4767
4768 /* check against the string len */
4769 if (l > 1024) {
4770 l = xmlStrlen(str->stringval);
4771 }
4772 if (i < 0) {
4773 i = 0;
4774 }
4775
4776 /* number of chars to copy */
4777 l -= i;
4778
4779 ret = xmlStrsub(str->stringval, i, l);
4780 if (ret == NULL)
4781 valuePush(ctxt, xmlXPathNewCString(""));
4782 else {
4783 valuePush(ctxt, xmlXPathNewString(ret));
4784 xmlFree(ret);
4785 }
4786 xmlXPathFreeObject(str);
4787}
4788
4789/**
4790 * xmlXPathSubstringBeforeFunction:
4791 * @ctxt: the XPath Parser context
4792 * @nargs: the number of arguments
4793 *
4794 * Implement the substring-before() XPath function
4795 * string substring-before(string, string)
4796 * The substring-before function returns the substring of the first
4797 * argument string that precedes the first occurrence of the second
4798 * argument string in the first argument string, or the empty string
4799 * if the first argument string does not contain the second argument
4800 * string. For example, substring-before("1999/04/01","/") returns 1999.
4801 */
4802void
4803xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4804 xmlXPathObjectPtr str;
4805 xmlXPathObjectPtr find;
4806 xmlBufferPtr target;
4807 const xmlChar *point;
4808 int offset;
4809
4810 CHECK_ARITY(2);
4811 CAST_TO_STRING;
4812 find = valuePop(ctxt);
4813 CAST_TO_STRING;
4814 str = valuePop(ctxt);
4815
4816 target = xmlBufferCreate();
4817 if (target) {
4818 point = xmlStrstr(str->stringval, find->stringval);
4819 if (point) {
4820 offset = (int)(point - str->stringval);
4821 xmlBufferAdd(target, str->stringval, offset);
4822 }
4823 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4824 xmlBufferFree(target);
4825 }
4826
4827 xmlXPathFreeObject(str);
4828 xmlXPathFreeObject(find);
4829}
4830
4831/**
4832 * xmlXPathSubstringAfterFunction:
4833 * @ctxt: the XPath Parser context
4834 * @nargs: the number of arguments
4835 *
4836 * Implement the substring-after() XPath function
4837 * string substring-after(string, string)
4838 * The substring-after function returns the substring of the first
4839 * argument string that follows the first occurrence of the second
4840 * argument string in the first argument string, or the empty stringi
4841 * if the first argument string does not contain the second argument
4842 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4843 * and substring-after("1999/04/01","19") returns 99/04/01.
4844 */
4845void
4846xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4847 xmlXPathObjectPtr str;
4848 xmlXPathObjectPtr find;
4849 xmlBufferPtr target;
4850 const xmlChar *point;
4851 int offset;
4852
4853 CHECK_ARITY(2);
4854 CAST_TO_STRING;
4855 find = valuePop(ctxt);
4856 CAST_TO_STRING;
4857 str = valuePop(ctxt);
4858
4859 target = xmlBufferCreate();
4860 if (target) {
4861 point = xmlStrstr(str->stringval, find->stringval);
4862 if (point) {
4863 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4864 xmlBufferAdd(target, &str->stringval[offset],
4865 xmlStrlen(str->stringval) - offset);
4866 }
4867 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4868 xmlBufferFree(target);
4869 }
4870
4871 xmlXPathFreeObject(str);
4872 xmlXPathFreeObject(find);
4873}
4874
4875/**
4876 * xmlXPathNormalizeFunction:
4877 * @ctxt: the XPath Parser context
4878 * @nargs: the number of arguments
4879 *
4880 * Implement the normalize-space() XPath function
4881 * string normalize-space(string?)
4882 * The normalize-space function returns the argument string with white
4883 * space normalized by stripping leading and trailing whitespace
4884 * and replacing sequences of whitespace characters by a single
4885 * space. Whitespace characters are the same allowed by the S production
4886 * in XML. If the argument is omitted, it defaults to the context
4887 * node converted to a string, in other words the value of the context node.
4888 */
4889void
4890xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4891 xmlXPathObjectPtr obj = NULL;
4892 xmlChar *source = NULL;
4893 xmlBufferPtr target;
4894 xmlChar blank;
4895
4896 if (nargs == 0) {
4897 /* Use current context node */
4898 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4899 xmlXPathStringFunction(ctxt, 1);
4900 nargs = 1;
4901 }
4902
4903 CHECK_ARITY(1);
4904 CAST_TO_STRING;
4905 CHECK_TYPE(XPATH_STRING);
4906 obj = valuePop(ctxt);
4907 source = obj->stringval;
4908
4909 target = xmlBufferCreate();
4910 if (target && source) {
4911
4912 /* Skip leading whitespaces */
4913 while (IS_BLANK(*source))
4914 source++;
4915
4916 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4917 blank = 0;
4918 while (*source) {
4919 if (IS_BLANK(*source)) {
4920 blank = *source;
4921 } else {
4922 if (blank) {
4923 xmlBufferAdd(target, &blank, 1);
4924 blank = 0;
4925 }
4926 xmlBufferAdd(target, source, 1);
4927 }
4928 source++;
4929 }
4930
4931 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4932 xmlBufferFree(target);
4933 }
4934 xmlXPathFreeObject(obj);
4935}
4936
4937/**
4938 * xmlXPathTranslateFunction:
4939 * @ctxt: the XPath Parser context
4940 * @nargs: the number of arguments
4941 *
4942 * Implement the translate() XPath function
4943 * string translate(string, string, string)
4944 * The translate function returns the first argument string with
4945 * occurrences of characters in the second argument string replaced
4946 * by the character at the corresponding position in the third argument
4947 * string. For example, translate("bar","abc","ABC") returns the string
4948 * BAr. If there is a character in the second argument string with no
4949 * character at a corresponding position in the third argument string
4950 * (because the second argument string is longer than the third argument
4951 * string), then occurrences of that character in the first argument
4952 * string are removed. For example, translate("--aaa--","abc-","ABC")
4953 * returns "AAA". If a character occurs more than once in second
4954 * argument string, then the first occurrence determines the replacement
4955 * character. If the third argument string is longer than the second
4956 * argument string, then excess characters are ignored.
4957 */
4958void
4959xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4960 xmlXPathObjectPtr str;
4961 xmlXPathObjectPtr from;
4962 xmlXPathObjectPtr to;
4963 xmlBufferPtr target;
4964 int i, offset, max;
4965 xmlChar ch;
4966 const xmlChar *point;
4967
4968 CHECK_ARITY(3);
4969
4970 CAST_TO_STRING;
4971 to = valuePop(ctxt);
4972 CAST_TO_STRING;
4973 from = valuePop(ctxt);
4974 CAST_TO_STRING;
4975 str = valuePop(ctxt);
4976
4977 target = xmlBufferCreate();
4978 if (target) {
4979 max = xmlStrlen(to->stringval);
4980 for (i = 0; (ch = str->stringval[i]); i++) {
4981 point = xmlStrchr(from->stringval, ch);
4982 if (point) {
4983 /* Warning: This may not work with UTF-8 */
4984 offset = (int)(point - from->stringval);
4985 if (offset < max)
4986 xmlBufferAdd(target, &to->stringval[offset], 1);
4987 } else
4988 xmlBufferAdd(target, &ch, 1);
4989 }
4990 }
4991 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4992 xmlBufferFree(target);
4993 xmlXPathFreeObject(str);
4994 xmlXPathFreeObject(from);
4995 xmlXPathFreeObject(to);
4996}
4997
4998/**
4999 * xmlXPathBooleanFunction:
5000 * @ctxt: the XPath Parser context
5001 * @nargs: the number of arguments
5002 *
5003 * Implement the boolean() XPath function
5004 * boolean boolean(object)
5005 * he boolean function converts its argument to a boolean as follows:
5006 * - a number is true if and only if it is neither positive or
5007 * negative zero nor NaN
5008 * - a node-set is true if and only if it is non-empty
5009 * - a string is true if and only if its length is non-zero
5010 */
5011void
5012xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5013 xmlXPathObjectPtr cur;
5014 int res = 0;
5015
5016 CHECK_ARITY(1);
5017 cur = valuePop(ctxt);
5018 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5019 switch (cur->type) {
5020 case XPATH_NODESET:
5021 case XPATH_XSLT_TREE:
5022 if ((cur->nodesetval == NULL) ||
5023 (cur->nodesetval->nodeNr == 0)) res = 0;
5024 else
5025 res = 1;
5026 break;
5027 case XPATH_STRING:
5028 if ((cur->stringval == NULL) ||
5029 (cur->stringval[0] == 0)) res = 0;
5030 else
5031 res = 1;
5032 break;
5033 case XPATH_BOOLEAN:
5034 valuePush(ctxt, cur);
5035 return;
5036 case XPATH_NUMBER:
5037 if (cur->floatval) res = 1;
5038 break;
5039 default:
5040 STRANGE
5041 }
5042 xmlXPathFreeObject(cur);
5043 valuePush(ctxt, xmlXPathNewBoolean(res));
5044}
5045
5046/**
5047 * xmlXPathNotFunction:
5048 * @ctxt: the XPath Parser context
5049 * @nargs: the number of arguments
5050 *
5051 * Implement the not() XPath function
5052 * boolean not(boolean)
5053 * The not function returns true if its argument is false,
5054 * and false otherwise.
5055 */
5056void
5057xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5058 CHECK_ARITY(1);
5059 CAST_TO_BOOLEAN;
5060 CHECK_TYPE(XPATH_BOOLEAN);
5061 ctxt->value->boolval = ! ctxt->value->boolval;
5062}
5063
5064/**
5065 * xmlXPathTrueFunction:
5066 * @ctxt: the XPath Parser context
5067 * @nargs: the number of arguments
5068 *
5069 * Implement the true() XPath function
5070 * boolean true()
5071 */
5072void
5073xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5074 CHECK_ARITY(0);
5075 valuePush(ctxt, xmlXPathNewBoolean(1));
5076}
5077
5078/**
5079 * xmlXPathFalseFunction:
5080 * @ctxt: the XPath Parser context
5081 * @nargs: the number of arguments
5082 *
5083 * Implement the false() XPath function
5084 * boolean false()
5085 */
5086void
5087xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5088 CHECK_ARITY(0);
5089 valuePush(ctxt, xmlXPathNewBoolean(0));
5090}
5091
5092/**
5093 * xmlXPathLangFunction:
5094 * @ctxt: the XPath Parser context
5095 * @nargs: the number of arguments
5096 *
5097 * Implement the lang() XPath function
5098 * boolean lang(string)
5099 * The lang function returns true or false depending on whether the
5100 * language of the context node as specified by xml:lang attributes
5101 * is the same as or is a sublanguage of the language specified by
5102 * the argument string. The language of the context node is determined
5103 * by the value of the xml:lang attribute on the context node, or, if
5104 * the context node has no xml:lang attribute, by the value of the
5105 * xml:lang attribute on the nearest ancestor of the context node that
5106 * has an xml:lang attribute. If there is no such attribute, then lang
5107 * returns false. If there is such an attribute, then lang returns
5108 * true if the attribute value is equal to the argument ignoring case,
5109 * or if there is some suffix starting with - such that the attribute
5110 * value is equal to the argument ignoring that suffix of the attribute
5111 * value and ignoring case.
5112 */
5113void
5114xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5115 xmlXPathObjectPtr val;
5116 const xmlChar *theLang;
5117 const xmlChar *lang;
5118 int ret = 0;
5119 int i;
5120
5121 CHECK_ARITY(1);
5122 CAST_TO_STRING;
5123 CHECK_TYPE(XPATH_STRING);
5124 val = valuePop(ctxt);
5125 lang = val->stringval;
5126 theLang = xmlNodeGetLang(ctxt->context->node);
5127 if ((theLang != NULL) && (lang != NULL)) {
5128 for (i = 0;lang[i] != 0;i++)
5129 if (toupper(lang[i]) != toupper(theLang[i]))
5130 goto not_equal;
5131 ret = 1;
5132 }
5133not_equal:
5134 xmlXPathFreeObject(val);
5135 valuePush(ctxt, xmlXPathNewBoolean(ret));
5136}
5137
5138/**
5139 * xmlXPathNumberFunction:
5140 * @ctxt: the XPath Parser context
5141 * @nargs: the number of arguments
5142 *
5143 * Implement the number() XPath function
5144 * number number(object?)
5145 */
5146void
5147xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5148 xmlXPathObjectPtr cur;
5149 double res;
5150
5151 if (nargs == 0) {
5152 if (ctxt->context->node == NULL) {
5153 valuePush(ctxt, xmlXPathNewFloat(0.0));
5154 } else {
5155 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
5156
5157 res = xmlXPathStringEvalNumber(content);
5158 valuePush(ctxt, xmlXPathNewFloat(res));
5159 xmlFree(content);
5160 }
5161 return;
5162 }
5163
5164 CHECK_ARITY(1);
5165 cur = valuePop(ctxt);
5166 switch (cur->type) {
5167 case XPATH_UNDEFINED:
5168#ifdef DEBUG_EXPR
5169 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5170#endif
5171 valuePush(ctxt, xmlXPathNewFloat(0.0));
5172 break;
5173 case XPATH_XSLT_TREE:
5174 case XPATH_NODESET:
5175 valuePush(ctxt, cur);
5176 xmlXPathStringFunction(ctxt, 1);
5177 cur = valuePop(ctxt);
5178 case XPATH_STRING:
5179 res = xmlXPathStringEvalNumber(cur->stringval);
5180 valuePush(ctxt, xmlXPathNewFloat(res));
5181 xmlXPathFreeObject(cur);
5182 return;
5183 case XPATH_BOOLEAN:
5184 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
5185 else valuePush(ctxt, xmlXPathNewFloat(0.0));
5186 xmlXPathFreeObject(cur);
5187 return;
5188 case XPATH_NUMBER:
5189 valuePush(ctxt, cur);
5190 return;
5191 case XPATH_USERS:
5192 case XPATH_POINT:
5193 case XPATH_RANGE:
5194 case XPATH_LOCATIONSET:
5195 TODO
5196 valuePush(ctxt, xmlXPathNewFloat(0.0));
5197 break;
5198 }
5199 STRANGE
5200}
5201
5202/**
5203 * xmlXPathSumFunction:
5204 * @ctxt: the XPath Parser context
5205 * @nargs: the number of arguments
5206 *
5207 * Implement the sum() XPath function
5208 * number sum(node-set)
5209 * The sum function returns the sum of the values of the nodes in
5210 * the argument node-set.
5211 */
5212void
5213xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5214 xmlXPathObjectPtr cur;
5215 int i;
5216
5217 CHECK_ARITY(1);
5218 if ((ctxt->value == NULL) ||
5219 ((ctxt->value->type != XPATH_NODESET) &&
5220 (ctxt->value->type != XPATH_XSLT_TREE)))
5221 XP_ERROR(XPATH_INVALID_TYPE);
5222 cur = valuePop(ctxt);
5223
5224 if (cur->nodesetval->nodeNr == 0) {
5225 valuePush(ctxt, xmlXPathNewFloat(0.0));
5226 } else {
5227 valuePush(ctxt,
5228 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
5229 xmlXPathNumberFunction(ctxt, 1);
5230 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
5231 valuePush(ctxt,
5232 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5233 xmlXPathAddValues(ctxt);
5234 }
5235 }
5236 xmlXPathFreeObject(cur);
5237}
5238
5239/**
5240 * xmlXPathFloorFunction:
5241 * @ctxt: the XPath Parser context
5242 * @nargs: the number of arguments
5243 *
5244 * Implement the floor() XPath function
5245 * number floor(number)
5246 * The floor function returns the largest (closest to positive infinity)
5247 * number that is not greater than the argument and that is an integer.
5248 */
5249void
5250xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5251 CHECK_ARITY(1);
5252 CAST_TO_NUMBER;
5253 CHECK_TYPE(XPATH_NUMBER);
5254#if 0
5255 ctxt->value->floatval = floor(ctxt->value->floatval);
5256#else
5257 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5258 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5259#endif
5260}
5261
5262/**
5263 * xmlXPathCeilingFunction:
5264 * @ctxt: the XPath Parser context
5265 * @nargs: the number of arguments
5266 *
5267 * Implement the ceiling() XPath function
5268 * number ceiling(number)
5269 * The ceiling function returns the smallest (closest to negative infinity)
5270 * number that is not less than the argument and that is an integer.
5271 */
5272void
5273xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5274 double f;
5275
5276 CHECK_ARITY(1);
5277 CAST_TO_NUMBER;
5278 CHECK_TYPE(XPATH_NUMBER);
5279
5280#if 0
5281 ctxt->value->floatval = ceil(ctxt->value->floatval);
5282#else
5283 f = (double)((int) ctxt->value->floatval);
5284 if (f != ctxt->value->floatval)
5285 ctxt->value->floatval = f + 1;
5286#endif
5287}
5288
5289/**
5290 * xmlXPathRoundFunction:
5291 * @ctxt: the XPath Parser context
5292 * @nargs: the number of arguments
5293 *
5294 * Implement the round() XPath function
5295 * number round(number)
5296 * The round function returns the number that is closest to the
5297 * argument and that is an integer. If there are two such numbers,
5298 * then the one that is even is returned.
5299 */
5300void
5301xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5302 double f;
5303
5304 CHECK_ARITY(1);
5305 CAST_TO_NUMBER;
5306 CHECK_TYPE(XPATH_NUMBER);
5307
5308 if ((ctxt->value->floatval == xmlXPathNAN) ||
5309 (ctxt->value->floatval == xmlXPathPINF) ||
5310 (ctxt->value->floatval == xmlXPathNINF) ||
5311 (ctxt->value->floatval == 0.0))
5312 return;
5313
5314#if 0
5315 f = floor(ctxt->value->floatval);
5316#else
5317 f = (double)((int) ctxt->value->floatval);
5318#endif
5319 if (ctxt->value->floatval < f + 0.5)
5320 ctxt->value->floatval = f;
5321 else
5322 ctxt->value->floatval = f + 1;
5323}
5324
5325/************************************************************************
5326 * *
5327 * The Parser *
5328 * *
5329 ************************************************************************/
5330
5331/*
5332 * a couple of forward declarations since we use a recursive call based
5333 * implementation.
5334 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005335static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
5336static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt);
5337static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005338#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005339static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5340#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005341#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005342static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005343#endif
5344
5345/**
5346 * xmlXPathParseNCName:
5347 * @ctxt: the XPath Parser context
5348 *
5349 * parse an XML namespace non qualified name.
5350 *
5351 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5352 *
5353 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5354 * CombiningChar | Extender
5355 *
5356 * Returns the namespace name or NULL
5357 */
5358
5359xmlChar *
5360xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
5361 const xmlChar *q;
5362 xmlChar *ret = NULL;
5363
5364 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
5365 q = NEXT;
5366
5367 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
5368 (CUR == '.') || (CUR == '-') ||
5369 (CUR == '_') ||
5370 (IS_COMBINING(CUR)) ||
5371 (IS_EXTENDER(CUR)))
5372 NEXT;
5373
5374 ret = xmlStrndup(q, CUR_PTR - q);
5375
5376 return(ret);
5377}
5378
5379/**
5380 * xmlXPathParseQName:
5381 * @ctxt: the XPath Parser context
5382 * @prefix: a xmlChar **
5383 *
5384 * parse an XML qualified name
5385 *
5386 * [NS 5] QName ::= (Prefix ':')? LocalPart
5387 *
5388 * [NS 6] Prefix ::= NCName
5389 *
5390 * [NS 7] LocalPart ::= NCName
5391 *
5392 * Returns the function returns the local part, and prefix is updated
5393 * to get the Prefix if any.
5394 */
5395
5396xmlChar *
5397xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5398 xmlChar *ret = NULL;
5399
5400 *prefix = NULL;
5401 ret = xmlXPathParseNCName(ctxt);
5402 if (CUR == ':') {
5403 *prefix = ret;
5404 NEXT;
5405 ret = xmlXPathParseNCName(ctxt);
5406 }
5407 return(ret);
5408}
5409
5410/**
5411 * xmlXPathParseName:
5412 * @ctxt: the XPath Parser context
5413 *
5414 * parse an XML name
5415 *
5416 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5417 * CombiningChar | Extender
5418 *
5419 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5420 *
5421 * Returns the namespace name or NULL
5422 */
5423
5424xmlChar *
5425xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
5426 const xmlChar *q;
5427 xmlChar *ret = NULL;
5428
5429 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
5430 q = NEXT;
5431
5432 /* TODO Make this UTF8 compliant !!! */
5433 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
5434 (CUR == '.') || (CUR == '-') ||
5435 (CUR == '_') || (CUR == ':') ||
5436 (IS_COMBINING(CUR)) ||
5437 (IS_EXTENDER(CUR)))
5438 NEXT;
5439
5440 ret = xmlStrndup(q, CUR_PTR - q);
5441
5442 return(ret);
5443}
5444
5445/**
5446 * xmlXPathStringEvalNumber:
5447 * @str: A string to scan
5448 *
5449 * [30] Number ::= Digits ('.' Digits?)?
5450 * | '.' Digits
5451 * [31] Digits ::= [0-9]+
5452 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005453 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005454 * In complement of the Number expression, this function also handles
5455 * negative values : '-' Number.
5456 *
5457 * Returns the double value.
5458 */
5459double
5460xmlXPathStringEvalNumber(const xmlChar *str) {
5461 const xmlChar *cur = str;
5462 double ret = 0.0;
5463 double mult = 1;
5464 int ok = 0;
5465 int isneg = 0;
5466
5467 while (IS_BLANK(*cur)) cur++;
5468 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5469 return(xmlXPathNAN);
5470 }
5471 if (*cur == '-') {
5472 isneg = 1;
5473 cur++;
5474 }
5475 while ((*cur >= '0') && (*cur <= '9')) {
5476 ret = ret * 10 + (*cur - '0');
5477 ok = 1;
5478 cur++;
5479 }
5480 if (*cur == '.') {
5481 cur++;
5482 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5483 return(xmlXPathNAN);
5484 }
5485 while ((*cur >= '0') && (*cur <= '9')) {
5486 mult /= 10;
5487 ret = ret + (*cur - '0') * mult;
5488 cur++;
5489 }
5490 }
5491 while (IS_BLANK(*cur)) cur++;
5492 if (*cur != 0) return(xmlXPathNAN);
5493 if (isneg) ret = -ret;
5494 return(ret);
5495}
5496
5497/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005498 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005499 * @ctxt: the XPath Parser context
5500 *
5501 * [30] Number ::= Digits ('.' Digits?)?
5502 * | '.' Digits
5503 * [31] Digits ::= [0-9]+
5504 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005505 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005506 *
5507 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005508static void
5509xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005510 double ret = 0.0;
5511 double mult = 1;
5512 int ok = 0;
5513
5514 CHECK_ERROR;
5515 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5516 XP_ERROR(XPATH_NUMBER_ERROR);
5517 }
5518 while ((CUR >= '0') && (CUR <= '9')) {
5519 ret = ret * 10 + (CUR - '0');
5520 ok = 1;
5521 NEXT;
5522 }
5523 if (CUR == '.') {
5524 NEXT;
5525 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5526 XP_ERROR(XPATH_NUMBER_ERROR);
5527 }
5528 while ((CUR >= '0') && (CUR <= '9')) {
5529 mult /= 10;
5530 ret = ret + (CUR - '0') * mult;
5531 NEXT;
5532 }
5533 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005534 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5535 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005536}
5537
5538/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005539 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005540 * @ctxt: the XPath Parser context
5541 *
5542 * Parse a Literal and push it on the stack.
5543 *
5544 * [29] Literal ::= '"' [^"]* '"'
5545 * | "'" [^']* "'"
5546 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005547 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005548 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005549static void
5550xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005551 const xmlChar *q;
5552 xmlChar *ret = NULL;
5553
5554 if (CUR == '"') {
5555 NEXT;
5556 q = CUR_PTR;
5557 while ((IS_CHAR(CUR)) && (CUR != '"'))
5558 NEXT;
5559 if (!IS_CHAR(CUR)) {
5560 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5561 } else {
5562 ret = xmlStrndup(q, CUR_PTR - q);
5563 NEXT;
5564 }
5565 } else if (CUR == '\'') {
5566 NEXT;
5567 q = CUR_PTR;
5568 while ((IS_CHAR(CUR)) && (CUR != '\''))
5569 NEXT;
5570 if (!IS_CHAR(CUR)) {
5571 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5572 } else {
5573 ret = xmlStrndup(q, CUR_PTR - q);
5574 NEXT;
5575 }
5576 } else {
5577 XP_ERROR(XPATH_START_LITERAL_ERROR);
5578 }
5579 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005580 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5581 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005582 xmlFree(ret);
5583}
5584
5585/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005586 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005587 * @ctxt: the XPath Parser context
5588 *
5589 * Parse a VariableReference, evaluate it and push it on the stack.
5590 *
5591 * The variable bindings consist of a mapping from variable names
5592 * to variable values. The value of a variable is an object, which
5593 * of any of the types that are possible for the value of an expression,
5594 * and may also be of additional types not specified here.
5595 *
5596 * Early evaluation is possible since:
5597 * The variable bindings [...] used to evaluate a subexpression are
5598 * always the same as those used to evaluate the containing expression.
5599 *
5600 * [36] VariableReference ::= '$' QName
5601 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005602static void
5603xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005604 xmlChar *name;
5605 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005606
5607 SKIP_BLANKS;
5608 if (CUR != '$') {
5609 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5610 }
5611 NEXT;
5612 name = xmlXPathParseQName(ctxt, &prefix);
5613 if (name == NULL) {
5614 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5615 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005616 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5617 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005618 SKIP_BLANKS;
5619}
5620
5621/**
5622 * xmlXPathIsNodeType:
5623 * @ctxt: the XPath Parser context
5624 * @name: a name string
5625 *
5626 * Is the name given a NodeType one.
5627 *
5628 * [38] NodeType ::= 'comment'
5629 * | 'text'
5630 * | 'processing-instruction'
5631 * | 'node'
5632 *
5633 * Returns 1 if true 0 otherwise
5634 */
5635int
5636xmlXPathIsNodeType(const xmlChar *name) {
5637 if (name == NULL)
5638 return(0);
5639
5640 if (xmlStrEqual(name, BAD_CAST "comment"))
5641 return(1);
5642 if (xmlStrEqual(name, BAD_CAST "text"))
5643 return(1);
5644 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5645 return(1);
5646 if (xmlStrEqual(name, BAD_CAST "node"))
5647 return(1);
5648 return(0);
5649}
5650
5651/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005652 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005653 * @ctxt: the XPath Parser context
5654 *
5655 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5656 * [17] Argument ::= Expr
5657 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005658 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00005659 * pushed on the stack
5660 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005661static void
5662xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005663 xmlChar *name;
5664 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005665 int nbargs = 0;
5666
5667 name = xmlXPathParseQName(ctxt, &prefix);
5668 if (name == NULL) {
5669 XP_ERROR(XPATH_EXPR_ERROR);
5670 }
5671 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005672#ifdef DEBUG_EXPR
5673 if (prefix == NULL)
5674 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5675 name);
5676 else
5677 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5678 prefix, name);
5679#endif
5680
Owen Taylor3473f882001-02-23 17:55:21 +00005681 if (CUR != '(') {
5682 XP_ERROR(XPATH_EXPR_ERROR);
5683 }
5684 NEXT;
5685 SKIP_BLANKS;
5686
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005687 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005688 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005689 int op1 = ctxt->comp->last;
5690 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005691 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005692 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005693 nbargs++;
5694 if (CUR == ')') break;
5695 if (CUR != ',') {
5696 XP_ERROR(XPATH_EXPR_ERROR);
5697 }
5698 NEXT;
5699 SKIP_BLANKS;
5700 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005701 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
5702 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005703 NEXT;
5704 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005705}
5706
5707/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005708 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005709 * @ctxt: the XPath Parser context
5710 *
5711 * [15] PrimaryExpr ::= VariableReference
5712 * | '(' Expr ')'
5713 * | Literal
5714 * | Number
5715 * | FunctionCall
5716 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005717 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005718 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005719static void
5720xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005721 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005722 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005723 else if (CUR == '(') {
5724 NEXT;
5725 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005726 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005727 if (CUR != ')') {
5728 XP_ERROR(XPATH_EXPR_ERROR);
5729 }
5730 NEXT;
5731 SKIP_BLANKS;
5732 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005733 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005734 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005735 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005736 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005737 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005738 }
5739 SKIP_BLANKS;
5740}
5741
5742/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005743 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005744 * @ctxt: the XPath Parser context
5745 *
5746 * [20] FilterExpr ::= PrimaryExpr
5747 * | FilterExpr Predicate
5748 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005749 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005750 * Square brackets are used to filter expressions in the same way that
5751 * they are used in location paths. It is an error if the expression to
5752 * be filtered does not evaluate to a node-set. The context node list
5753 * used for evaluating the expression in square brackets is the node-set
5754 * to be filtered listed in document order.
5755 */
5756
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005757static void
5758xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
5759 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005760 CHECK_ERROR;
5761 SKIP_BLANKS;
5762
5763 while (CUR == '[') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005764 xmlXPathCompPredicate(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005765 SKIP_BLANKS;
5766 }
5767
5768
5769}
5770
5771/**
5772 * xmlXPathScanName:
5773 * @ctxt: the XPath Parser context
5774 *
5775 * Trickery: parse an XML name but without consuming the input flow
5776 * Needed to avoid insanity in the parser state.
5777 *
5778 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5779 * CombiningChar | Extender
5780 *
5781 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5782 *
5783 * [6] Names ::= Name (S Name)*
5784 *
5785 * Returns the Name parsed or NULL
5786 */
5787
5788xmlChar *
5789xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
5790 xmlChar buf[XML_MAX_NAMELEN];
5791 int len = 0;
5792
5793 SKIP_BLANKS;
5794 if (!IS_LETTER(CUR) && (CUR != '_') &&
5795 (CUR != ':')) {
5796 return(NULL);
5797 }
5798
5799 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5800 (NXT(len) == '.') || (NXT(len) == '-') ||
5801 (NXT(len) == '_') || (NXT(len) == ':') ||
5802 (IS_COMBINING(NXT(len))) ||
5803 (IS_EXTENDER(NXT(len)))) {
5804 buf[len] = NXT(len);
5805 len++;
5806 if (len >= XML_MAX_NAMELEN) {
5807 xmlGenericError(xmlGenericErrorContext,
5808 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5809 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5810 (NXT(len) == '.') || (NXT(len) == '-') ||
5811 (NXT(len) == '_') || (NXT(len) == ':') ||
5812 (IS_COMBINING(NXT(len))) ||
5813 (IS_EXTENDER(NXT(len))))
5814 len++;
5815 break;
5816 }
5817 }
5818 return(xmlStrndup(buf, len));
5819}
5820
5821/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005822 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005823 * @ctxt: the XPath Parser context
5824 *
5825 * [19] PathExpr ::= LocationPath
5826 * | FilterExpr
5827 * | FilterExpr '/' RelativeLocationPath
5828 * | FilterExpr '//' RelativeLocationPath
5829 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005830 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005831 * The / operator and // operators combine an arbitrary expression
5832 * and a relative location path. It is an error if the expression
5833 * does not evaluate to a node-set.
5834 * The / operator does composition in the same way as when / is
5835 * used in a location path. As in location paths, // is short for
5836 * /descendant-or-self::node()/.
5837 */
5838
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005839static void
5840xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005841 int lc = 1; /* Should we branch to LocationPath ? */
5842 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5843
5844 SKIP_BLANKS;
5845 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5846 (CUR == '\'') || (CUR == '"')) {
5847 lc = 0;
5848 } else if (CUR == '*') {
5849 /* relative or absolute location path */
5850 lc = 1;
5851 } else if (CUR == '/') {
5852 /* relative or absolute location path */
5853 lc = 1;
5854 } else if (CUR == '@') {
5855 /* relative abbreviated attribute location path */
5856 lc = 1;
5857 } else if (CUR == '.') {
5858 /* relative abbreviated attribute location path */
5859 lc = 1;
5860 } else {
5861 /*
5862 * Problem is finding if we have a name here whether it's:
5863 * - a nodetype
5864 * - a function call in which case it's followed by '('
5865 * - an axis in which case it's followed by ':'
5866 * - a element name
5867 * We do an a priori analysis here rather than having to
5868 * maintain parsed token content through the recursive function
5869 * calls. This looks uglier but makes the code quite easier to
5870 * read/write/debug.
5871 */
5872 SKIP_BLANKS;
5873 name = xmlXPathScanName(ctxt);
5874 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
5875#ifdef DEBUG_STEP
5876 xmlGenericError(xmlGenericErrorContext,
5877 "PathExpr: Axis\n");
5878#endif
5879 lc = 1;
5880 xmlFree(name);
5881 } else if (name != NULL) {
5882 int len =xmlStrlen(name);
5883 int blank = 0;
5884
5885
5886 while (NXT(len) != 0) {
5887 if (NXT(len) == '/') {
5888 /* element name */
5889#ifdef DEBUG_STEP
5890 xmlGenericError(xmlGenericErrorContext,
5891 "PathExpr: AbbrRelLocation\n");
5892#endif
5893 lc = 1;
5894 break;
5895 } else if (IS_BLANK(NXT(len))) {
5896 /* skip to next */
5897 blank = 1;
5898 } else if (NXT(len) == ':') {
5899#ifdef DEBUG_STEP
5900 xmlGenericError(xmlGenericErrorContext,
5901 "PathExpr: AbbrRelLocation\n");
5902#endif
5903 lc = 1;
5904 break;
5905 } else if ((NXT(len) == '(')) {
5906 /* Note Type or Function */
5907 if (xmlXPathIsNodeType(name)) {
5908#ifdef DEBUG_STEP
5909 xmlGenericError(xmlGenericErrorContext,
5910 "PathExpr: Type search\n");
5911#endif
5912 lc = 1;
5913 } else {
5914#ifdef DEBUG_STEP
5915 xmlGenericError(xmlGenericErrorContext,
5916 "PathExpr: function call\n");
5917#endif
5918 lc = 0;
5919 }
5920 break;
5921 } else if ((NXT(len) == '[')) {
5922 /* element name */
5923#ifdef DEBUG_STEP
5924 xmlGenericError(xmlGenericErrorContext,
5925 "PathExpr: AbbrRelLocation\n");
5926#endif
5927 lc = 1;
5928 break;
5929 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5930 (NXT(len) == '=')) {
5931 lc = 1;
5932 break;
5933 } else {
5934 lc = 1;
5935 break;
5936 }
5937 len++;
5938 }
5939 if (NXT(len) == 0) {
5940#ifdef DEBUG_STEP
5941 xmlGenericError(xmlGenericErrorContext,
5942 "PathExpr: AbbrRelLocation\n");
5943#endif
5944 /* element name */
5945 lc = 1;
5946 }
5947 xmlFree(name);
5948 } else {
5949 /* make sure all cases are covered explicitely */
5950 XP_ERROR(XPATH_EXPR_ERROR);
5951 }
5952 }
5953
5954 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005955 if (CUR == '/') {
5956 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
5957 } else {
5958 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005959 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005960 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005961 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005962 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005963 CHECK_ERROR;
5964 if ((CUR == '/') && (NXT(1) == '/')) {
5965 SKIP(2);
5966 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005967
5968 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
5969 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5970 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
5971
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005972 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005973 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005974 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005975 }
5976 }
5977 SKIP_BLANKS;
5978}
5979
5980/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005981 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005982 * @ctxt: the XPath Parser context
5983 *
5984 * [18] UnionExpr ::= PathExpr
5985 * | UnionExpr '|' PathExpr
5986 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005987 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005988 */
5989
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005990static void
5991xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
5992 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005993 CHECK_ERROR;
5994 SKIP_BLANKS;
5995 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005996 int op1 = ctxt->comp->last;
5997 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005998
5999 NEXT;
6000 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006001 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006002
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006003 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6004
Owen Taylor3473f882001-02-23 17:55:21 +00006005 SKIP_BLANKS;
6006 }
Owen Taylor3473f882001-02-23 17:55:21 +00006007}
6008
6009/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006010 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006011 * @ctxt: the XPath Parser context
6012 *
6013 * [27] UnaryExpr ::= UnionExpr
6014 * | '-' UnaryExpr
6015 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006016 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006017 */
6018
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006019static void
6020xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006021 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006022 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006023
6024 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006025 while (CUR == '-') {
6026 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006027 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006028 NEXT;
6029 SKIP_BLANKS;
6030 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006031
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006032 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006033 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006034 if (found) {
6035 if (minus)
6036 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6037 else
6038 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006039 }
6040}
6041
6042/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006043 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006044 * @ctxt: the XPath Parser context
6045 *
6046 * [26] MultiplicativeExpr ::= UnaryExpr
6047 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6048 * | MultiplicativeExpr 'div' UnaryExpr
6049 * | MultiplicativeExpr 'mod' UnaryExpr
6050 * [34] MultiplyOperator ::= '*'
6051 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006052 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006053 */
6054
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006055static void
6056xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6057 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006058 CHECK_ERROR;
6059 SKIP_BLANKS;
6060 while ((CUR == '*') ||
6061 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6062 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6063 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006064 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006065
6066 if (CUR == '*') {
6067 op = 0;
6068 NEXT;
6069 } else if (CUR == 'd') {
6070 op = 1;
6071 SKIP(3);
6072 } else if (CUR == 'm') {
6073 op = 2;
6074 SKIP(3);
6075 }
6076 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006077 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006078 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006079 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006080 SKIP_BLANKS;
6081 }
6082}
6083
6084/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006085 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006086 * @ctxt: the XPath Parser context
6087 *
6088 * [25] AdditiveExpr ::= MultiplicativeExpr
6089 * | AdditiveExpr '+' MultiplicativeExpr
6090 * | AdditiveExpr '-' MultiplicativeExpr
6091 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006092 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006093 */
6094
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006095static void
6096xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006097
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006098 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006099 CHECK_ERROR;
6100 SKIP_BLANKS;
6101 while ((CUR == '+') || (CUR == '-')) {
6102 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006103 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006104
6105 if (CUR == '+') plus = 1;
6106 else plus = 0;
6107 NEXT;
6108 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006109 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006110 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006111 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006112 SKIP_BLANKS;
6113 }
6114}
6115
6116/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006117 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006118 * @ctxt: the XPath Parser context
6119 *
6120 * [24] RelationalExpr ::= AdditiveExpr
6121 * | RelationalExpr '<' AdditiveExpr
6122 * | RelationalExpr '>' AdditiveExpr
6123 * | RelationalExpr '<=' AdditiveExpr
6124 * | RelationalExpr '>=' AdditiveExpr
6125 *
6126 * A <= B > C is allowed ? Answer from James, yes with
6127 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6128 * which is basically what got implemented.
6129 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006130 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006131 * on the stack
6132 */
6133
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006134static void
6135xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6136 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006137 CHECK_ERROR;
6138 SKIP_BLANKS;
6139 while ((CUR == '<') ||
6140 (CUR == '>') ||
6141 ((CUR == '<') && (NXT(1) == '=')) ||
6142 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006143 int inf, strict;
6144 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006145
6146 if (CUR == '<') inf = 1;
6147 else inf = 0;
6148 if (NXT(1) == '=') strict = 0;
6149 else strict = 1;
6150 NEXT;
6151 if (!strict) NEXT;
6152 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006153 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006154 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006155 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006156 SKIP_BLANKS;
6157 }
6158}
6159
6160/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006161 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006162 * @ctxt: the XPath Parser context
6163 *
6164 * [23] EqualityExpr ::= RelationalExpr
6165 * | EqualityExpr '=' RelationalExpr
6166 * | EqualityExpr '!=' RelationalExpr
6167 *
6168 * A != B != C is allowed ? Answer from James, yes with
6169 * (RelationalExpr = RelationalExpr) = RelationalExpr
6170 * (RelationalExpr != RelationalExpr) != RelationalExpr
6171 * which is basically what got implemented.
6172 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006173 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006174 *
6175 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006176static void
6177xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6178 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006179 CHECK_ERROR;
6180 SKIP_BLANKS;
6181 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006182 int eq;
6183 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006184
6185 if (CUR == '=') eq = 1;
6186 else eq = 0;
6187 NEXT;
6188 if (!eq) NEXT;
6189 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006190 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006191 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006192 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006193 SKIP_BLANKS;
6194 }
6195}
6196
6197/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006198 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006199 * @ctxt: the XPath Parser context
6200 *
6201 * [22] AndExpr ::= EqualityExpr
6202 * | AndExpr 'and' EqualityExpr
6203 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006204 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006205 *
6206 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006207static void
6208xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6209 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006210 CHECK_ERROR;
6211 SKIP_BLANKS;
6212 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006213 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006214 SKIP(3);
6215 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006216 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006217 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006218 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006219 SKIP_BLANKS;
6220 }
6221}
6222
6223/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006224 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006225 * @ctxt: the XPath Parser context
6226 *
6227 * [14] Expr ::= OrExpr
6228 * [21] OrExpr ::= AndExpr
6229 * | OrExpr 'or' AndExpr
6230 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006231 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006232 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006233static void
6234xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6235 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006236 CHECK_ERROR;
6237 SKIP_BLANKS;
6238 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006239 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006240 SKIP(2);
6241 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006242 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006243 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006244 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6245 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006246 SKIP_BLANKS;
6247 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006248 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6249 /* more ops could be optimized too */
6250 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6251 }
Owen Taylor3473f882001-02-23 17:55:21 +00006252}
6253
6254/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006255 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006256 * @ctxt: the XPath Parser context
6257 *
6258 * [8] Predicate ::= '[' PredicateExpr ']'
6259 * [9] PredicateExpr ::= Expr
6260 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006261 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006262 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006263static void
6264xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006265 int op1 = ctxt->comp->last;
6266
6267 SKIP_BLANKS;
6268 if (CUR != '[') {
6269 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6270 }
6271 NEXT;
6272 SKIP_BLANKS;
6273
6274 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006275 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006276 CHECK_ERROR;
6277
6278 if (CUR != ']') {
6279 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6280 }
6281
6282 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
6283
6284 NEXT;
6285 SKIP_BLANKS;
6286}
6287
6288/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006289 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006290 * @ctxt: the XPath Parser context
6291 * @test: pointer to a xmlXPathTestVal
6292 * @type: pointer to a xmlXPathTypeVal
6293 * @prefix: placeholder for a possible name prefix
6294 *
6295 * [7] NodeTest ::= NameTest
6296 * | NodeType '(' ')'
6297 * | 'processing-instruction' '(' Literal ')'
6298 *
6299 * [37] NameTest ::= '*'
6300 * | NCName ':' '*'
6301 * | QName
6302 * [38] NodeType ::= 'comment'
6303 * | 'text'
6304 * | 'processing-instruction'
6305 * | 'node'
6306 *
6307 * Returns the name found and update @test, @type and @prefix appropriately
6308 */
6309xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006310xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6311 xmlXPathTypeVal *type, const xmlChar **prefix,
6312 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006313 int blanks;
6314
6315 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6316 STRANGE;
6317 return(NULL);
6318 }
6319 *type = 0;
6320 *test = 0;
6321 *prefix = NULL;
6322 SKIP_BLANKS;
6323
6324 if ((name == NULL) && (CUR == '*')) {
6325 /*
6326 * All elements
6327 */
6328 NEXT;
6329 *test = NODE_TEST_ALL;
6330 return(NULL);
6331 }
6332
6333 if (name == NULL)
6334 name = xmlXPathParseNCName(ctxt);
6335 if (name == NULL) {
6336 XP_ERROR0(XPATH_EXPR_ERROR);
6337 }
6338
6339 blanks = IS_BLANK(CUR);
6340 SKIP_BLANKS;
6341 if (CUR == '(') {
6342 NEXT;
6343 /*
6344 * NodeType or PI search
6345 */
6346 if (xmlStrEqual(name, BAD_CAST "comment"))
6347 *type = NODE_TYPE_COMMENT;
6348 else if (xmlStrEqual(name, BAD_CAST "node"))
6349 *type = NODE_TYPE_NODE;
6350 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6351 *type = NODE_TYPE_PI;
6352 else if (xmlStrEqual(name, BAD_CAST "text"))
6353 *type = NODE_TYPE_TEXT;
6354 else {
6355 if (name != NULL)
6356 xmlFree(name);
6357 XP_ERROR0(XPATH_EXPR_ERROR);
6358 }
6359
6360 *test = NODE_TEST_TYPE;
6361
6362 SKIP_BLANKS;
6363 if (*type == NODE_TYPE_PI) {
6364 /*
6365 * Specific case: search a PI by name.
6366 */
6367 xmlXPathObjectPtr cur;
6368
6369 if (name != NULL)
6370 xmlFree(name);
6371
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006372 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006373 CHECK_ERROR 0;
6374 xmlXPathStringFunction(ctxt, 1);
6375 CHECK_ERROR0;
6376 cur = valuePop(ctxt);
6377 name = xmlStrdup(cur->stringval);
6378 xmlXPathFreeObject(cur);
6379 SKIP_BLANKS;
6380 }
6381 if (CUR != ')') {
6382 if (name != NULL)
6383 xmlFree(name);
6384 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6385 }
6386 NEXT;
6387 return(name);
6388 }
6389 *test = NODE_TEST_NAME;
6390 if ((!blanks) && (CUR == ':')) {
6391 NEXT;
6392
6393 /*
6394 * get the namespace name for this prefix
6395 */
6396 *prefix = xmlXPathNsLookup(ctxt->context, name);
6397 if (name != NULL)
6398 xmlFree(name);
6399 if (*prefix == NULL) {
6400 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6401 }
6402
6403 if (CUR == '*') {
6404 /*
6405 * All elements
6406 */
6407 NEXT;
6408 *test = NODE_TEST_ALL;
6409 return(NULL);
6410 }
6411
6412 name = xmlXPathParseNCName(ctxt);
6413 if (name == NULL) {
6414 XP_ERROR0(XPATH_EXPR_ERROR);
6415 }
6416 }
6417 return(name);
6418}
6419
6420/**
6421 * xmlXPathIsAxisName:
6422 * @name: a preparsed name token
6423 *
6424 * [6] AxisName ::= 'ancestor'
6425 * | 'ancestor-or-self'
6426 * | 'attribute'
6427 * | 'child'
6428 * | 'descendant'
6429 * | 'descendant-or-self'
6430 * | 'following'
6431 * | 'following-sibling'
6432 * | 'namespace'
6433 * | 'parent'
6434 * | 'preceding'
6435 * | 'preceding-sibling'
6436 * | 'self'
6437 *
6438 * Returns the axis or 0
6439 */
6440xmlXPathAxisVal
6441xmlXPathIsAxisName(const xmlChar *name) {
6442 xmlXPathAxisVal ret = 0;
6443 switch (name[0]) {
6444 case 'a':
6445 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6446 ret = AXIS_ANCESTOR;
6447 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6448 ret = AXIS_ANCESTOR_OR_SELF;
6449 if (xmlStrEqual(name, BAD_CAST "attribute"))
6450 ret = AXIS_ATTRIBUTE;
6451 break;
6452 case 'c':
6453 if (xmlStrEqual(name, BAD_CAST "child"))
6454 ret = AXIS_CHILD;
6455 break;
6456 case 'd':
6457 if (xmlStrEqual(name, BAD_CAST "descendant"))
6458 ret = AXIS_DESCENDANT;
6459 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6460 ret = AXIS_DESCENDANT_OR_SELF;
6461 break;
6462 case 'f':
6463 if (xmlStrEqual(name, BAD_CAST "following"))
6464 ret = AXIS_FOLLOWING;
6465 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6466 ret = AXIS_FOLLOWING_SIBLING;
6467 break;
6468 case 'n':
6469 if (xmlStrEqual(name, BAD_CAST "namespace"))
6470 ret = AXIS_NAMESPACE;
6471 break;
6472 case 'p':
6473 if (xmlStrEqual(name, BAD_CAST "parent"))
6474 ret = AXIS_PARENT;
6475 if (xmlStrEqual(name, BAD_CAST "preceding"))
6476 ret = AXIS_PRECEDING;
6477 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6478 ret = AXIS_PRECEDING_SIBLING;
6479 break;
6480 case 's':
6481 if (xmlStrEqual(name, BAD_CAST "self"))
6482 ret = AXIS_SELF;
6483 break;
6484 }
6485 return(ret);
6486}
6487
6488/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006489 * xmlXPathCompAxisSpecifier:
Owen Taylor3473f882001-02-23 17:55:21 +00006490 * @ctxt: the XPath Parser context
6491 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006492 * Parse an axis value
Owen Taylor3473f882001-02-23 17:55:21 +00006493 *
6494 * Returns the axis found
6495 */
6496xmlXPathAxisVal
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006497xmlXPathCompAxisSpecifier(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006498 xmlXPathAxisVal ret = AXIS_CHILD;
6499 int blank = 0;
6500 xmlChar *name;
6501
6502 if (CUR == '@') {
6503 NEXT;
6504 return(AXIS_ATTRIBUTE);
6505 } else {
6506 name = xmlXPathParseNCName(ctxt);
6507 if (name == NULL) {
6508 XP_ERROR0(XPATH_EXPR_ERROR);
6509 }
6510 if (IS_BLANK(CUR))
6511 blank = 1;
6512 SKIP_BLANKS;
6513 if ((CUR == ':') && (NXT(1) == ':')) {
6514 ret = xmlXPathIsAxisName(name);
6515 } else if ((blank) && (CUR == ':'))
6516 XP_ERROR0(XPATH_EXPR_ERROR);
6517
6518 xmlFree(name);
6519 }
6520 return(ret);
6521}
6522
6523/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006524 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006525 * @ctxt: the XPath Parser context
6526 *
6527 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6528 * | AbbreviatedStep
6529 *
6530 * [12] AbbreviatedStep ::= '.' | '..'
6531 *
6532 * [5] AxisSpecifier ::= AxisName '::'
6533 * | AbbreviatedAxisSpecifier
6534 *
6535 * [13] AbbreviatedAxisSpecifier ::= '@'?
6536 *
6537 * Modified for XPtr range support as:
6538 *
6539 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6540 * | AbbreviatedStep
6541 * | 'range-to' '(' Expr ')' Predicate*
6542 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006543 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006544 * A location step of . is short for self::node(). This is
6545 * particularly useful in conjunction with //. For example, the
6546 * location path .//para is short for
6547 * self::node()/descendant-or-self::node()/child::para
6548 * and so will select all para descendant elements of the context
6549 * node.
6550 * Similarly, a location step of .. is short for parent::node().
6551 * For example, ../title is short for parent::node()/child::title
6552 * and so will select the title children of the parent of the context
6553 * node.
6554 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006555static void
6556xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006557 SKIP_BLANKS;
6558 if ((CUR == '.') && (NXT(1) == '.')) {
6559 SKIP(2);
6560 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006561 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6562 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006563 } else if (CUR == '.') {
6564 NEXT;
6565 SKIP_BLANKS;
6566 } else {
6567 xmlChar *name = NULL;
6568 const xmlChar *prefix = NULL;
6569 xmlXPathTestVal test;
6570 xmlXPathAxisVal axis;
6571 xmlXPathTypeVal type;
6572
6573 /*
6574 * The modification needed for XPointer change to the production
6575 */
6576#ifdef LIBXML_XPTR_ENABLED
6577 if (ctxt->context->xptr) {
6578 name = xmlXPathParseNCName(ctxt);
6579 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006580 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006581 xmlFree(name);
6582 SKIP_BLANKS;
6583 if (CUR != '(') {
6584 XP_ERROR(XPATH_EXPR_ERROR);
6585 }
6586 NEXT;
6587 SKIP_BLANKS;
6588
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006589 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006590 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006591 CHECK_ERROR;
6592
6593 SKIP_BLANKS;
6594 if (CUR != ')') {
6595 XP_ERROR(XPATH_EXPR_ERROR);
6596 }
6597 NEXT;
6598 goto eval_predicates;
6599 }
6600 }
6601#endif
6602 if (name == NULL)
6603 name = xmlXPathParseNCName(ctxt);
6604 if (name != NULL) {
6605 axis = xmlXPathIsAxisName(name);
6606 if (axis != 0) {
6607 SKIP_BLANKS;
6608 if ((CUR == ':') && (NXT(1) == ':')) {
6609 SKIP(2);
6610 xmlFree(name);
6611 name = NULL;
6612 } else {
6613 /* an element name can conflict with an axis one :-\ */
6614 axis = AXIS_CHILD;
6615 }
6616 } else {
6617 axis = AXIS_CHILD;
6618 }
6619 } else if (CUR == '@') {
6620 NEXT;
6621 axis = AXIS_ATTRIBUTE;
6622 } else {
6623 axis = AXIS_CHILD;
6624 }
6625
6626 CHECK_ERROR;
6627
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006628 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006629 if (test == 0)
6630 return;
6631
6632#ifdef DEBUG_STEP
6633 xmlGenericError(xmlGenericErrorContext,
6634 "Basis : computing new set\n");
6635#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006636
6637 PUSH_LONG_EXPR(XPATH_OP_COLLECT, axis, test, type,
6638 (void *)prefix, (void *)name);
6639
Owen Taylor3473f882001-02-23 17:55:21 +00006640#ifdef DEBUG_STEP
6641 xmlGenericError(xmlGenericErrorContext, "Basis : ");
6642 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
6643#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006644
6645eval_predicates:
6646 SKIP_BLANKS;
6647 while (CUR == '[') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006648 xmlXPathCompPredicate(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006649 }
6650 }
6651#ifdef DEBUG_STEP
6652 xmlGenericError(xmlGenericErrorContext, "Step : ");
6653 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6654 ctxt->value->nodesetval);
6655#endif
6656}
6657
6658/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006659 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006660 * @ctxt: the XPath Parser context
6661 *
6662 * [3] RelativeLocationPath ::= Step
6663 * | RelativeLocationPath '/' Step
6664 * | AbbreviatedRelativeLocationPath
6665 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6666 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006667 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00006668 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006669static void
Owen Taylor3473f882001-02-23 17:55:21 +00006670#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006671xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006672#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006673xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006674#endif
6675(xmlXPathParserContextPtr ctxt) {
6676 SKIP_BLANKS;
6677 if ((CUR == '/') && (NXT(1) == '/')) {
6678 SKIP(2);
6679 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006680 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6681 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006682 } else if (CUR == '/') {
6683 NEXT;
6684 SKIP_BLANKS;
6685 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006686 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006687 SKIP_BLANKS;
6688 while (CUR == '/') {
6689 if ((CUR == '/') && (NXT(1) == '/')) {
6690 SKIP(2);
6691 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006692 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00006693 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006694 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006695 } else if (CUR == '/') {
6696 NEXT;
6697 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006698 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006699 }
6700 SKIP_BLANKS;
6701 }
6702}
6703
6704/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006705 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006706 * @ctxt: the XPath Parser context
6707 *
6708 * [1] LocationPath ::= RelativeLocationPath
6709 * | AbsoluteLocationPath
6710 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6711 * | AbbreviatedAbsoluteLocationPath
6712 * [10] AbbreviatedAbsoluteLocationPath ::=
6713 * '//' RelativeLocationPath
6714 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006715 * Compile a location path
6716 *
Owen Taylor3473f882001-02-23 17:55:21 +00006717 * // is short for /descendant-or-self::node()/. For example,
6718 * //para is short for /descendant-or-self::node()/child::para and
6719 * so will select any para element in the document (even a para element
6720 * that is a document element will be selected by //para since the
6721 * document element node is a child of the root node); div//para is
6722 * short for div/descendant-or-self::node()/child::para and so will
6723 * select all para descendants of div children.
6724 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006725static void
6726xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006727 SKIP_BLANKS;
6728 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006729 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006730 } else {
6731 while (CUR == '/') {
6732 if ((CUR == '/') && (NXT(1) == '/')) {
6733 SKIP(2);
6734 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006735 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6736 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006737 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006738 } else if (CUR == '/') {
6739 NEXT;
6740 SKIP_BLANKS;
6741 if (CUR != 0)
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006742 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006743 }
6744 }
6745 }
6746}
6747
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006748/************************************************************************
6749 * *
6750 * XPath precompiled expression evaluation *
6751 * *
6752 ************************************************************************/
6753
Owen Taylor3473f882001-02-23 17:55:21 +00006754/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006755 * xmlXPathCompOpEval:
6756 * @ctxt: the XPath parser context with the compiled expression
6757 * @op: an XPath compiled operation
6758 *
6759 * Evaluate the Precompiled XPath operation
6760 */
6761void
6762xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
6763 int equal, ret;
6764 xmlXPathCompExprPtr comp;
6765 xmlXPathObjectPtr arg1, arg2;
6766
6767 comp = ctxt->comp;
6768 switch (op->op) {
6769 case XPATH_OP_END:
6770 return;
6771 case XPATH_OP_AND:
6772 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6773 xmlXPathBooleanFunction(ctxt, 1);
6774 if (ctxt->value->boolval == 0)
6775 return;
6776 arg2 = valuePop(ctxt);
6777 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6778 xmlXPathBooleanFunction(ctxt, 1);
6779 arg1 = valuePop(ctxt);
6780 arg1->boolval &= arg2->boolval;
6781 valuePush(ctxt, arg1);
6782 xmlXPathFreeObject(arg2);
6783 return;
6784 case XPATH_OP_OR:
6785 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6786 xmlXPathBooleanFunction(ctxt, 1);
6787 if (ctxt->value->boolval == 1)
6788 return;
6789 arg2 = valuePop(ctxt);
6790 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6791 xmlXPathBooleanFunction(ctxt, 1);
6792 arg1 = valuePop(ctxt);
6793 arg1->boolval |= arg2->boolval;
6794 valuePush(ctxt, arg1);
6795 xmlXPathFreeObject(arg2);
6796 return;
6797 case XPATH_OP_EQUAL:
6798 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6799 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6800 equal = xmlXPathEqualValues(ctxt);
6801 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
6802 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
6803 return;
6804 case XPATH_OP_CMP:
6805 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6806 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6807 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
6808 valuePush(ctxt, xmlXPathNewBoolean(ret));
6809 return;
6810 case XPATH_OP_PLUS:
6811 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6812 if (op->ch2 != -1)
6813 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6814 if (op->value == 0) xmlXPathSubValues(ctxt);
6815 else if (op->value == 1) xmlXPathAddValues(ctxt);
6816 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
6817 else if (op->value == 3) {
6818 xmlXPathObjectPtr arg;
6819
6820 POP_FLOAT
6821 valuePush(ctxt, arg);
6822 }
6823 return;
6824 case XPATH_OP_MULT:
6825 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6826 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6827 if (op->value == 0) xmlXPathMultValues(ctxt);
6828 else if (op->value == 1) xmlXPathDivValues(ctxt);
6829 else if (op->value == 2) xmlXPathModValues(ctxt);
6830 return;
6831 case XPATH_OP_UNION:
6832 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6833 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6834 CHECK_TYPE(XPATH_NODESET);
6835 arg2 = valuePop(ctxt);
6836
6837 CHECK_TYPE(XPATH_NODESET);
6838 arg1 = valuePop(ctxt);
6839
6840 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
6841 arg2->nodesetval);
6842 valuePush(ctxt, arg1);
6843 xmlXPathFreeObject(arg2);
6844 return;
6845 case XPATH_OP_ROOT:
6846 xmlXPathRoot(ctxt);
6847 return;
6848 case XPATH_OP_NODE:
6849 if (op->ch1 != -1)
6850 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6851 if (op->ch2 != -1)
6852 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6853 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6854 return;
6855 case XPATH_OP_RESET:
6856 if (op->ch1 != -1)
6857 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6858 if (op->ch2 != -1)
6859 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6860 ctxt->context->node = NULL;
6861 return;
6862 case XPATH_OP_COLLECT:
6863 if (op->ch1 != -1)
6864 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6865 xmlXPathNodeCollectAndTest(ctxt, op->value, op->value2,
6866 op->value3, op->value4, op->value5);
6867 return;
6868 case XPATH_OP_VALUE:
6869 valuePush(ctxt,
6870 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
6871 return;
6872 case XPATH_OP_VARIABLE: {
6873 if (op->ch1 != -1)
6874 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6875 if (op->value5 == NULL)
6876 valuePush(ctxt,
6877 xmlXPathVariableLookup(ctxt->context, op->value4));
6878 else {
6879 const xmlChar *URI;
6880 URI = xmlXPathNsLookup(ctxt->context, op->value5);
6881 if (URI == NULL) {
6882 xmlGenericError(xmlGenericErrorContext,
6883 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
6884 op->value4, op->value5);
6885 return;
6886 }
6887 valuePush(ctxt,
6888 xmlXPathVariableLookupNS(ctxt->context,
6889 op->value4, URI));
6890 }
6891 return;
6892 }
6893 case XPATH_OP_FUNCTION: {
6894 xmlXPathFunction func;
6895
6896 if (op->ch1 != -1)
6897 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6898 if (op->value5 == NULL)
6899 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
6900 else {
6901 const xmlChar *URI;
6902 URI = xmlXPathNsLookup(ctxt->context, op->value5);
6903 if (URI == NULL) {
6904 xmlGenericError(xmlGenericErrorContext,
6905 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
6906 op->value4, op->value5);
6907 return;
6908 }
6909 func = xmlXPathFunctionLookupNS(ctxt->context,
6910 op->value4, URI);
6911 }
6912 if (func == NULL) {
6913 xmlGenericError(xmlGenericErrorContext,
6914 "xmlXPathRunEval: function %s not found\n",
6915 op->value4);
6916 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
6917 return;
6918 }
6919 func(ctxt, op->value);
6920 return;
6921 }
6922 case XPATH_OP_ARG:
6923 if (op->ch1 != -1)
6924 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6925 if (op->ch2 != -1)
6926 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6927 return;
6928 case XPATH_OP_PREDICATE: {
6929 xmlXPathObjectPtr res;
6930 xmlXPathObjectPtr obj, tmp;
6931 xmlNodeSetPtr newset = NULL;
6932 xmlNodeSetPtr oldset;
6933 xmlNodePtr oldnode;
6934 int i;
6935
6936 if (op->ch1 != -1)
6937 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6938 if (op->ch2 == -1)
6939 return;
6940
6941 oldnode = ctxt->context->node;
6942
6943#ifdef LIBXML_XPTR_ENABLED
6944 /*
6945 * Hum are we filtering the result of an XPointer expression
6946 */
6947 if (ctxt->value->type == XPATH_LOCATIONSET) {
6948 xmlLocationSetPtr newset = NULL;
6949 xmlLocationSetPtr oldset;
6950
6951 /*
6952 * Extract the old set, and then evaluate the result of the
6953 * expression for all the element in the set. use it to grow
6954 * up a new set.
6955 */
6956 CHECK_TYPE(XPATH_LOCATIONSET);
6957 obj = valuePop(ctxt);
6958 oldset = obj->user;
6959 ctxt->context->node = NULL;
6960
6961 if ((oldset == NULL) || (oldset->locNr == 0)) {
6962 ctxt->context->contextSize = 0;
6963 ctxt->context->proximityPosition = 0;
6964 if (op->ch2 != -1)
6965 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6966 res = valuePop(ctxt);
6967 if (res != NULL)
6968 xmlXPathFreeObject(res);
6969 valuePush(ctxt, obj);
6970 CHECK_ERROR;
6971 return;
6972 }
6973 newset = xmlXPtrLocationSetCreate(NULL);
6974
6975 for (i = 0; i < oldset->locNr; i++) {
6976 /*
6977 * Run the evaluation with a node list made of a
6978 * single item in the nodeset.
6979 */
6980 ctxt->context->node = oldset->locTab[i]->user;
6981 tmp = xmlXPathNewNodeSet(ctxt->context->node);
6982 valuePush(ctxt, tmp);
6983 ctxt->context->contextSize = oldset->locNr;
6984 ctxt->context->proximityPosition = i + 1;
6985
6986 if (op->ch2 != -1)
6987 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6988 CHECK_ERROR;
6989
6990 /*
6991 * The result of the evaluation need to be tested to
6992 * decided whether the filter succeeded or not
6993 */
6994 res = valuePop(ctxt);
6995 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
6996 xmlXPtrLocationSetAdd(newset,
6997 xmlXPathObjectCopy(oldset->locTab[i]));
6998 }
6999
7000 /*
7001 * Cleanup
7002 */
7003 if (res != NULL)
7004 xmlXPathFreeObject(res);
7005 if (ctxt->value == tmp) {
7006 res = valuePop(ctxt);
7007 xmlXPathFreeObject(res);
7008 }
7009
7010 ctxt->context->node = NULL;
7011 }
7012
7013 /*
7014 * The result is used as the new evaluation set.
7015 */
7016 xmlXPathFreeObject(obj);
7017 ctxt->context->node = NULL;
7018 ctxt->context->contextSize = -1;
7019 ctxt->context->proximityPosition = -1;
7020 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7021 ctxt->context->node = oldnode;
7022 return;
7023 }
7024#endif /* LIBXML_XPTR_ENABLED */
7025
7026 /*
7027 * Extract the old set, and then evaluate the result of the
7028 * expression for all the element in the set. use it to grow
7029 * up a new set.
7030 */
7031 CHECK_TYPE(XPATH_NODESET);
7032 obj = valuePop(ctxt);
7033 oldset = obj->nodesetval;
7034 oldnode = ctxt->context->node;
7035 ctxt->context->node = NULL;
7036
7037 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7038 ctxt->context->contextSize = 0;
7039 ctxt->context->proximityPosition = 0;
7040 if (op->ch2 != -1)
7041 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7042 res = valuePop(ctxt);
7043 if (res != NULL)
7044 xmlXPathFreeObject(res);
7045 valuePush(ctxt, obj);
7046 CHECK_ERROR;
7047 } else {
7048 /*
7049 * Initialize the new set.
7050 */
7051 newset = xmlXPathNodeSetCreate(NULL);
7052
7053 for (i = 0; i < oldset->nodeNr; i++) {
7054 /*
7055 * Run the evaluation with a node list made of
7056 * a single item in the nodeset.
7057 */
7058 ctxt->context->node = oldset->nodeTab[i];
7059 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7060 valuePush(ctxt, tmp);
7061 ctxt->context->contextSize = oldset->nodeNr;
7062 ctxt->context->proximityPosition = i + 1;
7063
7064 if (op->ch2 != -1)
7065 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7066 CHECK_ERROR;
7067
7068 /*
7069 * The result of the evaluation need to be tested to
7070 * decided whether the filter succeeded or not
7071 */
7072 res = valuePop(ctxt);
7073 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7074 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7075 }
7076
7077 /*
7078 * Cleanup
7079 */
7080 if (res != NULL)
7081 xmlXPathFreeObject(res);
7082 if (ctxt->value == tmp) {
7083 res = valuePop(ctxt);
7084 xmlXPathFreeObject(res);
7085 }
7086
7087 ctxt->context->node = NULL;
7088 }
7089
7090 /*
7091 * The result is used as the new evaluation set.
7092 */
7093 xmlXPathFreeObject(obj);
7094 ctxt->context->node = NULL;
7095 ctxt->context->contextSize = -1;
7096 ctxt->context->proximityPosition = -1;
7097 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7098 }
7099 ctxt->context->node = oldnode;
7100 return;
7101 }
7102 case XPATH_OP_SORT:
7103 if (op->ch1 != -1)
7104 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7105 if ((ctxt->value != NULL) &&
7106 (ctxt->value->type == XPATH_NODESET) &&
7107 (ctxt->value->nodesetval != NULL))
7108 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7109 return;
7110#ifdef LIBXML_XPTR_ENABLED
7111 case XPATH_OP_RANGETO: {
7112 xmlXPathObjectPtr range;
7113 xmlXPathObjectPtr res, obj;
7114 xmlXPathObjectPtr tmp;
7115 xmlLocationSetPtr newset = NULL;
7116 xmlNodeSetPtr oldset;
7117 int i;
7118
7119 if (op->ch1 != -1)
7120 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7121 if (op->ch2 == -1)
7122 return;
7123
7124 CHECK_TYPE(XPATH_NODESET);
7125 obj = valuePop(ctxt);
7126 oldset = obj->nodesetval;
7127 ctxt->context->node = NULL;
7128
7129 newset = xmlXPtrLocationSetCreate(NULL);
7130
7131 for (i = 0; i < oldset->nodeNr; i++) {
7132 /*
7133 * Run the evaluation with a node list made of a single item
7134 * in the nodeset.
7135 */
7136 ctxt->context->node = oldset->nodeTab[i];
7137 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7138 valuePush(ctxt, tmp);
7139
7140 if (op->ch2 != -1)
7141 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7142 CHECK_ERROR;
7143
7144 /*
7145 * The result of the evaluation need to be tested to
7146 * decided whether the filter succeeded or not
7147 */
7148 res = valuePop(ctxt);
7149 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7150 if (range != NULL) {
7151 xmlXPtrLocationSetAdd(newset, range);
7152 }
7153
7154 /*
7155 * Cleanup
7156 */
7157 if (res != NULL)
7158 xmlXPathFreeObject(res);
7159 if (ctxt->value == tmp) {
7160 res = valuePop(ctxt);
7161 xmlXPathFreeObject(res);
7162 }
7163
7164 ctxt->context->node = NULL;
7165 }
7166
7167 /*
7168 * The result is used as the new evaluation set.
7169 */
7170 xmlXPathFreeObject(obj);
7171 ctxt->context->node = NULL;
7172 ctxt->context->contextSize = -1;
7173 ctxt->context->proximityPosition = -1;
7174 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7175 return;
7176 }
7177#endif /* LIBXML_XPTR_ENABLED */
7178 }
7179 xmlGenericError(xmlGenericErrorContext,
7180 "XPath: unknown precompiled operation %d\n",
7181 op->op);
7182 return;
7183}
7184
7185/**
7186 * xmlXPathRunEval:
7187 * @ctxt: the XPath parser context with the compiled expression
7188 *
7189 * Evaluate the Precompiled XPath expression in the given context.
7190 */
7191void
7192xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7193 xmlXPathCompExprPtr comp;
7194
7195 if ((ctxt == NULL) || (ctxt->comp == NULL))
7196 return;
7197
7198 if (ctxt->valueTab == NULL) {
7199 /* Allocate the value stack */
7200 ctxt->valueTab = (xmlXPathObjectPtr *)
7201 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7202 if (ctxt->valueTab == NULL) {
7203 xmlFree(ctxt);
7204 xmlGenericError(xmlGenericErrorContext,
7205 "xmlXPathRunEval: out of memory\n");
7206 return;
7207 }
7208 ctxt->valueNr = 0;
7209 ctxt->valueMax = 10;
7210 ctxt->value = NULL;
7211 }
7212 comp = ctxt->comp;
7213 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7214}
7215
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007216/************************************************************************
7217 * *
7218 * Public interfaces *
7219 * *
7220 ************************************************************************/
7221
7222/**
7223 * xmlXPathEvaluatePredicateResult:
7224 * @ctxt: the XPath Parser context
7225 * @res: the Predicate Expression evaluation result
7226 *
7227 * Evaluate a predicate result for the current node.
7228 * A PredicateExpr is evaluated by evaluating the Expr and converting
7229 * the result to a boolean. If the result is a number, the result will
7230 * be converted to true if the number is equal to the position of the
7231 * context node in the context node list (as returned by the position
7232 * function) and will be converted to false otherwise; if the result
7233 * is not a number, then the result will be converted as if by a call
7234 * to the boolean function.
7235 *
7236 * Return 1 if predicate is true, 0 otherwise
7237 */
7238int
7239xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
7240 xmlXPathObjectPtr res) {
7241 if (res == NULL) return(0);
7242 switch (res->type) {
7243 case XPATH_BOOLEAN:
7244 return(res->boolval);
7245 case XPATH_NUMBER:
7246 return(res->floatval == ctxt->context->proximityPosition);
7247 case XPATH_NODESET:
7248 case XPATH_XSLT_TREE:
7249 return(res->nodesetval->nodeNr != 0);
7250 case XPATH_STRING:
7251 return((res->stringval != NULL) &&
7252 (xmlStrlen(res->stringval) != 0));
7253 default:
7254 STRANGE
7255 }
7256 return(0);
7257}
7258
7259/**
7260 * xmlXPathCompile:
7261 * @str: the XPath expression
7262 *
7263 * Compile an XPath expression
7264 *
7265 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7266 * the caller has to free the object.
7267 */
7268xmlXPathCompExprPtr
7269xmlXPathCompile(const xmlChar *str) {
7270 xmlXPathParserContextPtr ctxt;
7271 xmlXPathCompExprPtr comp;
7272
7273 xmlXPathInit();
7274
7275 ctxt = xmlXPathNewParserContext(str, NULL);
7276 xmlXPathCompileExpr(ctxt);
7277
7278 comp = ctxt->comp;
7279 ctxt->comp = NULL;
7280 xmlXPathFreeParserContext(ctxt);
7281 return(comp);
7282}
7283
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007284/**
7285 * xmlXPathCompiledEval:
7286 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00007287 * @ctx: the XPath context
7288 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007289 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00007290 *
7291 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7292 * the caller has to free the object.
7293 */
7294xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007295xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00007296 xmlXPathParserContextPtr ctxt;
7297 xmlXPathObjectPtr res, tmp, init = NULL;
7298 int stack = 0;
7299
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007300 if ((comp == NULL) || (ctx == NULL))
7301 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007302 xmlXPathInit();
7303
7304 CHECK_CONTEXT(ctx)
7305
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007306 ctxt = xmlXPathCompParserContext(comp, ctx);
7307 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007308
7309 if (ctxt->value == NULL) {
7310 xmlGenericError(xmlGenericErrorContext,
7311 "xmlXPathEval: evaluation failed\n");
7312 res = NULL;
7313 } else if (*ctxt->cur != 0) {
7314 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7315 res = NULL;
7316 } else {
7317 res = valuePop(ctxt);
7318 }
7319
7320 do {
7321 tmp = valuePop(ctxt);
7322 if (tmp != NULL) {
7323 if (tmp != init)
7324 stack++;
7325 xmlXPathFreeObject(tmp);
7326 }
7327 } while (tmp != NULL);
7328 if ((stack != 0) && (res != NULL)) {
7329 xmlGenericError(xmlGenericErrorContext,
7330 "xmlXPathEval: %d object left on the stack\n",
7331 stack);
7332 }
7333 if (ctxt->error != XPATH_EXPRESSION_OK) {
7334 xmlXPathFreeObject(res);
7335 res = NULL;
7336 }
7337
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007338 xmlXPathDebugDumpCompExpr(stdout, ctxt->comp, 0);
7339
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007340 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007341 xmlXPathFreeParserContext(ctxt);
7342 return(res);
7343}
7344
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007345/**
7346 * xmlXPathEvalExpr:
7347 * @ctxt: the XPath Parser context
7348 *
7349 * Parse and evaluate an XPath expression in the given context,
7350 * then push the result on the context stack
7351 */
7352void
7353xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
7354 xmlXPathCompileExpr(ctxt);
7355 xmlXPathRunEval(ctxt);
7356}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007357
7358/**
7359 * xmlXPathEval:
7360 * @str: the XPath expression
7361 * @ctx: the XPath context
7362 *
7363 * Evaluate the XPath Location Path in the given context.
7364 *
7365 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7366 * the caller has to free the object.
7367 */
7368xmlXPathObjectPtr
7369xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
7370 xmlXPathParserContextPtr ctxt;
7371 xmlXPathObjectPtr res, tmp, init = NULL;
7372 int stack = 0;
7373
7374 xmlXPathInit();
7375
7376 CHECK_CONTEXT(ctx)
7377
7378 ctxt = xmlXPathNewParserContext(str, ctx);
7379 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007380
7381 if (ctxt->value == NULL) {
7382 xmlGenericError(xmlGenericErrorContext,
7383 "xmlXPathEval: evaluation failed\n");
7384 res = NULL;
7385 } else if (*ctxt->cur != 0) {
7386 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7387 res = NULL;
7388 } else {
7389 res = valuePop(ctxt);
7390 }
7391
7392 do {
7393 tmp = valuePop(ctxt);
7394 if (tmp != NULL) {
7395 if (tmp != init)
7396 stack++;
7397 xmlXPathFreeObject(tmp);
7398 }
7399 } while (tmp != NULL);
7400 if ((stack != 0) && (res != NULL)) {
7401 xmlGenericError(xmlGenericErrorContext,
7402 "xmlXPathEval: %d object left on the stack\n",
7403 stack);
7404 }
7405 if (ctxt->error != XPATH_EXPRESSION_OK) {
7406 xmlXPathFreeObject(res);
7407 res = NULL;
7408 }
7409
Owen Taylor3473f882001-02-23 17:55:21 +00007410 xmlXPathFreeParserContext(ctxt);
7411 return(res);
7412}
7413
7414/**
7415 * xmlXPathEvalExpression:
7416 * @str: the XPath expression
7417 * @ctxt: the XPath context
7418 *
7419 * Evaluate the XPath expression in the given context.
7420 *
7421 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
7422 * the caller has to free the object.
7423 */
7424xmlXPathObjectPtr
7425xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
7426 xmlXPathParserContextPtr pctxt;
7427 xmlXPathObjectPtr res, tmp;
7428 int stack = 0;
7429
7430 xmlXPathInit();
7431
7432 CHECK_CONTEXT(ctxt)
7433
7434 pctxt = xmlXPathNewParserContext(str, ctxt);
7435 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007436
7437 if (*pctxt->cur != 0) {
7438 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7439 res = NULL;
7440 } else {
7441 res = valuePop(pctxt);
7442 }
7443 do {
7444 tmp = valuePop(pctxt);
7445 if (tmp != NULL) {
7446 xmlXPathFreeObject(tmp);
7447 stack++;
7448 }
7449 } while (tmp != NULL);
7450 if ((stack != 0) && (res != NULL)) {
7451 xmlGenericError(xmlGenericErrorContext,
7452 "xmlXPathEvalExpression: %d object left on the stack\n",
7453 stack);
7454 }
7455 xmlXPathFreeParserContext(pctxt);
7456 return(res);
7457}
7458
7459/**
7460 * xmlXPathRegisterAllFunctions:
7461 * @ctxt: the XPath context
7462 *
7463 * Registers all default XPath functions in this context
7464 */
7465void
7466xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
7467{
7468 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
7469 xmlXPathBooleanFunction);
7470 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
7471 xmlXPathCeilingFunction);
7472 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
7473 xmlXPathCountFunction);
7474 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
7475 xmlXPathConcatFunction);
7476 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
7477 xmlXPathContainsFunction);
7478 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
7479 xmlXPathIdFunction);
7480 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
7481 xmlXPathFalseFunction);
7482 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
7483 xmlXPathFloorFunction);
7484 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
7485 xmlXPathLastFunction);
7486 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
7487 xmlXPathLangFunction);
7488 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
7489 xmlXPathLocalNameFunction);
7490 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
7491 xmlXPathNotFunction);
7492 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
7493 xmlXPathNameFunction);
7494 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
7495 xmlXPathNamespaceURIFunction);
7496 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
7497 xmlXPathNormalizeFunction);
7498 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
7499 xmlXPathNumberFunction);
7500 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
7501 xmlXPathPositionFunction);
7502 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
7503 xmlXPathRoundFunction);
7504 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
7505 xmlXPathStringFunction);
7506 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
7507 xmlXPathStringLengthFunction);
7508 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
7509 xmlXPathStartsWithFunction);
7510 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
7511 xmlXPathSubstringFunction);
7512 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
7513 xmlXPathSubstringBeforeFunction);
7514 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
7515 xmlXPathSubstringAfterFunction);
7516 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
7517 xmlXPathSumFunction);
7518 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
7519 xmlXPathTrueFunction);
7520 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
7521 xmlXPathTranslateFunction);
7522}
7523
7524#endif /* LIBXML_XPATH_ENABLED */