blob: 439ca3d9503c37cf655cdd5f9e9e4af8167d2c36 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020#ifdef LIBXML_XPATH_ENABLED
21
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_MATH_H
28#include <math.h>
29#endif
30#ifdef HAVE_FLOAT_H
31#include <float.h>
32#endif
33#ifdef HAVE_IEEEFP_H
34#include <ieeefp.h>
35#endif
36#ifdef HAVE_NAN_H
37#include <nan.h>
38#endif
39#ifdef HAVE_CTYPE_H
40#include <ctype.h>
41#endif
42
43#include <libxml/xmlmemory.h>
44#include <libxml/tree.h>
45#include <libxml/valid.h>
46#include <libxml/xpath.h>
47#include <libxml/xpathInternals.h>
48#include <libxml/parserInternals.h>
49#include <libxml/hash.h>
50#ifdef LIBXML_XPTR_ENABLED
51#include <libxml/xpointer.h>
52#endif
53#ifdef LIBXML_DEBUG_ENABLED
54#include <libxml/debugXML.h>
55#endif
56#include <libxml/xmlerror.h>
57
58/* #define DEBUG */
59/* #define DEBUG_STEP */
60/* #define DEBUG_EXPR */
61
62void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
63double xmlXPathStringEvalNumber(const xmlChar *str);
64
Daniel Veillard9e7160d2001-03-18 23:17:47 +000065/************************************************************************
66 * *
67 * Floating point stuff *
68 * *
69 ************************************************************************/
70
Owen Taylor3473f882001-02-23 17:55:21 +000071/*
Owen Taylor3473f882001-02-23 17:55:21 +000072 * The lack of portability of this section of the libc is annoying !
73 */
74double xmlXPathNAN = 0;
75double xmlXPathPINF = 1;
76double xmlXPathNINF = -1;
77
78#ifndef isinf
79#ifndef HAVE_ISINF
80
81#if HAVE_FPCLASS
82
83int isinf(double d) {
84 fpclass_t type = fpclass(d);
85 switch (type) {
86 case FP_NINF:
87 return(-1);
88 case FP_PINF:
89 return(1);
90 }
91 return(0);
92}
93
94#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
95
96#if HAVE_FP_CLASS_H
97#include <fp_class.h>
98#endif
99
100int isinf(double d) {
101#if HAVE_FP_CLASS
102 int fpclass = fp_class(d);
103#else
104 int fpclass = fp_class_d(d);
105#endif
106 if (fpclass == FP_POS_INF)
107 return(1);
108 if (fpclass == FP_NEG_INF)
109 return(-1);
110 return(0);
111}
112
113#elif defined(HAVE_CLASS)
114
115int isinf(double d) {
116 int fpclass = class(d);
117 if (fpclass == FP_PLUS_INF)
118 return(1);
119 if (fpclass == FP_MINUS_INF)
120 return(-1);
121 return(0);
122}
123#elif defined(finite) || defined(HAVE_FINITE)
124int isinf(double x) { return !finite(x) && x==x; }
125#elif defined(HUGE_VAL)
126int isinf(double x)
127{
128 if (x == HUGE_VAL)
129 return(1);
130 if (x == -HUGE_VAL)
131 return(-1);
132 return(0);
133}
134#endif
135
136#endif /* ! HAVE_ISINF */
137#endif /* ! defined(isinf) */
138
139#ifndef isnan
140#ifndef HAVE_ISNAN
141
142#ifdef HAVE_ISNAND
143#define isnan(f) isnand(f)
144#endif /* HAVE_iSNAND */
145
146#endif /* ! HAVE_iSNAN */
147#endif /* ! defined(isnan) */
148
149/**
150 * xmlXPathInit:
151 *
152 * Initialize the XPath environment
153 */
154void
155xmlXPathInit(void) {
156 static int initialized = 0;
157
158 if (initialized) return;
159
Daniel Veillard1731d6a2001-04-10 16:38:06 +0000160 xmlXPathNAN = 0.0 / 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +0000161
Daniel Veillard1731d6a2001-04-10 16:38:06 +0000162 xmlXPathPINF = 1 / 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +0000163
Daniel Veillard1731d6a2001-04-10 16:38:06 +0000164 xmlXPathNINF = -1 / 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +0000165
166 initialized = 1;
167}
168
169/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000170 * *
171 * Parser Types *
172 * *
173 ************************************************************************/
174
175/*
176 * Types are private:
177 */
178
179typedef enum {
180 XPATH_OP_END=0,
181 XPATH_OP_AND,
182 XPATH_OP_OR,
183 XPATH_OP_EQUAL,
184 XPATH_OP_CMP,
185 XPATH_OP_PLUS,
186 XPATH_OP_MULT,
187 XPATH_OP_UNION,
188 XPATH_OP_ROOT,
189 XPATH_OP_NODE,
190 XPATH_OP_RESET,
191 XPATH_OP_COLLECT,
192 XPATH_OP_VALUE,
193 XPATH_OP_VARIABLE,
194 XPATH_OP_FUNCTION,
195 XPATH_OP_ARG,
196 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000197 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000198 XPATH_OP_SORT
199#ifdef LIBXML_XPTR_ENABLED
200 ,XPATH_OP_RANGETO
201#endif
202} xmlXPathOp;
203
204typedef enum {
205 AXIS_ANCESTOR = 1,
206 AXIS_ANCESTOR_OR_SELF,
207 AXIS_ATTRIBUTE,
208 AXIS_CHILD,
209 AXIS_DESCENDANT,
210 AXIS_DESCENDANT_OR_SELF,
211 AXIS_FOLLOWING,
212 AXIS_FOLLOWING_SIBLING,
213 AXIS_NAMESPACE,
214 AXIS_PARENT,
215 AXIS_PRECEDING,
216 AXIS_PRECEDING_SIBLING,
217 AXIS_SELF
218} xmlXPathAxisVal;
219
220typedef enum {
221 NODE_TEST_NONE = 0,
222 NODE_TEST_TYPE = 1,
223 NODE_TEST_PI = 2,
224 NODE_TEST_ALL = 3,
225 NODE_TEST_NS = 4,
226 NODE_TEST_NAME = 5
227} xmlXPathTestVal;
228
229typedef enum {
230 NODE_TYPE_NODE = 0,
231 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
232 NODE_TYPE_TEXT = XML_TEXT_NODE,
233 NODE_TYPE_PI = XML_PI_NODE
234} xmlXPathTypeVal;
235
236
237typedef struct _xmlXPathStepOp xmlXPathStepOp;
238typedef xmlXPathStepOp *xmlXPathStepOpPtr;
239struct _xmlXPathStepOp {
240 xmlXPathOp op;
241 int ch1;
242 int ch2;
243 int value;
244 int value2;
245 int value3;
246 void *value4;
247 void *value5;
248};
249
250struct _xmlXPathCompExpr {
251 int nbStep;
252 int maxStep;
253 xmlXPathStepOp *steps; /* ops for computation */
254 int last;
255};
256
257/************************************************************************
258 * *
259 * Parser Type functions *
260 * *
261 ************************************************************************/
262
263/**
264 * xmlXPathNewCompExpr:
265 *
266 * Create a new Xpath component
267 *
268 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
269 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000270static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000271xmlXPathNewCompExpr(void) {
272 xmlXPathCompExprPtr cur;
273
274 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
275 if (cur == NULL) {
276 xmlGenericError(xmlGenericErrorContext,
277 "xmlXPathNewCompExpr : malloc failed\n");
278 return(NULL);
279 }
280 memset(cur, 0, sizeof(xmlXPathCompExpr));
281 cur->maxStep = 10;
282 cur->nbStep = 0;
283 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
284 sizeof(xmlXPathStepOp));
285 if (cur->steps == NULL) {
286 xmlGenericError(xmlGenericErrorContext,
287 "xmlXPathNewCompExpr : malloc failed\n");
288 xmlFree(cur);
289 return(NULL);
290 }
291 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
292 cur->last = -1;
293 return(cur);
294}
295
296/**
297 * xmlXPathFreeCompExpr:
298 * @comp: an XPATH comp
299 *
300 * Free up the memory allocated by @comp
301 */
302void
303xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) {
304 xmlXPathStepOpPtr op;
305 int i;
306
307 if (comp == NULL)
308 return;
309 for (i = 0;i < comp->nbStep;i++) {
310 op = &comp->steps[i];
311 if (op->value4 != NULL) {
312 if (op->op == XPATH_OP_VALUE)
313 xmlXPathFreeObject(op->value4);
314 else
315 xmlFree(op->value4);
316 }
317 if (op->value5 != NULL)
318 xmlFree(op->value5);
319 }
320 if (comp->steps != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000321 xmlFree(comp->steps);
322 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000323 xmlFree(comp);
324}
325
326/**
327 * xmlXPathCompExprAdd:
328 * @comp: the compiled expression
329 * @ch1: first child index
330 * @ch2: second child index
331 * @op: an op
332 * @value: the first int value
333 * @value2: the second int value
334 * @value3: the third int value
335 * @value4: the first string value
336 * @value5: the second string value
337 *
338 * Add an step to an XPath Compiled Expression
339 *
340 * Returns -1 in case of failure, the index otherwise
341 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000342static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000343xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
344 xmlXPathOp op, int value,
345 int value2, int value3, void *value4, void *value5) {
346 if (comp->nbStep >= comp->maxStep) {
347 xmlXPathStepOp *real;
348
349 comp->maxStep *= 2;
350 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
351 comp->maxStep * sizeof(xmlXPathStepOp));
352 if (real == NULL) {
353 comp->maxStep /= 2;
354 xmlGenericError(xmlGenericErrorContext,
355 "xmlXPathCompExprAdd : realloc failed\n");
356 return(-1);
357 }
358 comp->steps = real;
359 }
360 comp->last = comp->nbStep;
361 comp->steps[comp->nbStep].ch1 = ch1;
362 comp->steps[comp->nbStep].ch2 = ch2;
363 comp->steps[comp->nbStep].op = op;
364 comp->steps[comp->nbStep].value = value;
365 comp->steps[comp->nbStep].value2 = value2;
366 comp->steps[comp->nbStep].value3 = value3;
367 comp->steps[comp->nbStep].value4 = value4;
368 comp->steps[comp->nbStep].value5 = value5;
369 return(comp->nbStep++);
370}
371
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000372#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
373 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
374 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000375#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
376 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
377 (op), (val), (val2), (val3), (val4), (val5))
378
379#define PUSH_LEAVE_EXPR(op, val, val2) \
380xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
381
382#define PUSH_UNARY_EXPR(op, ch, val, val2) \
383xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
384
385#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
386xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
387
388/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000389 * *
390 * Debugging related functions *
391 * *
392 ************************************************************************/
393
394#define TODO \
395 xmlGenericError(xmlGenericErrorContext, \
396 "Unimplemented block at %s:%d\n", \
397 __FILE__, __LINE__);
398
399#define STRANGE \
400 xmlGenericError(xmlGenericErrorContext, \
401 "Internal error at %s:%d\n", \
402 __FILE__, __LINE__);
403
404#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000405static void
406xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000407 int i;
408 char shift[100];
409
410 for (i = 0;((i < depth) && (i < 25));i++)
411 shift[2 * i] = shift[2 * i + 1] = ' ';
412 shift[2 * i] = shift[2 * i + 1] = 0;
413 if (cur == NULL) {
414 fprintf(output, shift);
415 fprintf(output, "Node is NULL !\n");
416 return;
417
418 }
419
420 if ((cur->type == XML_DOCUMENT_NODE) ||
421 (cur->type == XML_HTML_DOCUMENT_NODE)) {
422 fprintf(output, shift);
423 fprintf(output, " /\n");
424 } else if (cur->type == XML_ATTRIBUTE_NODE)
425 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
426 else
427 xmlDebugDumpOneNode(output, cur, depth);
428}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000429static void
430xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000431 xmlNodePtr tmp;
432 int i;
433 char shift[100];
434
435 for (i = 0;((i < depth) && (i < 25));i++)
436 shift[2 * i] = shift[2 * i + 1] = ' ';
437 shift[2 * i] = shift[2 * i + 1] = 0;
438 if (cur == NULL) {
439 fprintf(output, shift);
440 fprintf(output, "Node is NULL !\n");
441 return;
442
443 }
444
445 while (cur != NULL) {
446 tmp = cur;
447 cur = cur->next;
448 xmlDebugDumpOneNode(output, tmp, depth);
449 }
450}
Owen Taylor3473f882001-02-23 17:55:21 +0000451
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000452static void
453xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000454 int i;
455 char shift[100];
456
457 for (i = 0;((i < depth) && (i < 25));i++)
458 shift[2 * i] = shift[2 * i + 1] = ' ';
459 shift[2 * i] = shift[2 * i + 1] = 0;
460
461 if (cur == NULL) {
462 fprintf(output, shift);
463 fprintf(output, "NodeSet is NULL !\n");
464 return;
465
466 }
467
Daniel Veillard911f49a2001-04-07 15:39:35 +0000468 if (cur != NULL) {
469 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
470 for (i = 0;i < cur->nodeNr;i++) {
471 fprintf(output, shift);
472 fprintf(output, "%d", i + 1);
473 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
474 }
Owen Taylor3473f882001-02-23 17:55:21 +0000475 }
476}
477
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000478static void
479xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000480 int i;
481 char shift[100];
482
483 for (i = 0;((i < depth) && (i < 25));i++)
484 shift[2 * i] = shift[2 * i + 1] = ' ';
485 shift[2 * i] = shift[2 * i + 1] = 0;
486
487 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
488 fprintf(output, shift);
489 fprintf(output, "Value Tree is NULL !\n");
490 return;
491
492 }
493
494 fprintf(output, shift);
495 fprintf(output, "%d", i + 1);
496 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
497}
Owen Taylor3473f882001-02-23 17:55:21 +0000498#if defined(LIBXML_XPTR_ENABLED)
499void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000500static void
501xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000502 int i;
503 char shift[100];
504
505 for (i = 0;((i < depth) && (i < 25));i++)
506 shift[2 * i] = shift[2 * i + 1] = ' ';
507 shift[2 * i] = shift[2 * i + 1] = 0;
508
509 if (cur == NULL) {
510 fprintf(output, shift);
511 fprintf(output, "LocationSet is NULL !\n");
512 return;
513
514 }
515
516 for (i = 0;i < cur->locNr;i++) {
517 fprintf(output, shift);
518 fprintf(output, "%d : ", i + 1);
519 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
520 }
521}
522#endif
523
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000524/**
525 * xmlXPathDebugDumpObject:
526 * @output: the FILE * to dump the output
527 * @cur: the object to inspect
528 * @depth: indentation level
529 *
530 * Dump the content of the object for debugging purposes
531 */
532void
533xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000534 int i;
535 char shift[100];
536
537 for (i = 0;((i < depth) && (i < 25));i++)
538 shift[2 * i] = shift[2 * i + 1] = ' ';
539 shift[2 * i] = shift[2 * i + 1] = 0;
540
541 fprintf(output, shift);
542
543 if (cur == NULL) {
544 fprintf(output, "Object is empty (NULL)\n");
545 return;
546 }
547 switch(cur->type) {
548 case XPATH_UNDEFINED:
549 fprintf(output, "Object is uninitialized\n");
550 break;
551 case XPATH_NODESET:
552 fprintf(output, "Object is a Node Set :\n");
553 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
554 break;
555 case XPATH_XSLT_TREE:
556 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000557 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000558 break;
559 case XPATH_BOOLEAN:
560 fprintf(output, "Object is a Boolean : ");
561 if (cur->boolval) fprintf(output, "true\n");
562 else fprintf(output, "false\n");
563 break;
564 case XPATH_NUMBER:
565 fprintf(output, "Object is a number : %0g\n", cur->floatval);
566 break;
567 case XPATH_STRING:
568 fprintf(output, "Object is a string : ");
569 xmlDebugDumpString(output, cur->stringval);
570 fprintf(output, "\n");
571 break;
572 case XPATH_POINT:
573 fprintf(output, "Object is a point : index %d in node", cur->index);
574 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
575 fprintf(output, "\n");
576 break;
577 case XPATH_RANGE:
578 if ((cur->user2 == NULL) ||
579 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
580 fprintf(output, "Object is a collapsed range :\n");
581 fprintf(output, shift);
582 if (cur->index >= 0)
583 fprintf(output, "index %d in ", cur->index);
584 fprintf(output, "node\n");
585 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
586 depth + 1);
587 } else {
588 fprintf(output, "Object is a range :\n");
589 fprintf(output, shift);
590 fprintf(output, "From ");
591 if (cur->index >= 0)
592 fprintf(output, "index %d in ", cur->index);
593 fprintf(output, "node\n");
594 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
595 depth + 1);
596 fprintf(output, shift);
597 fprintf(output, "To ");
598 if (cur->index2 >= 0)
599 fprintf(output, "index %d in ", cur->index2);
600 fprintf(output, "node\n");
601 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
602 depth + 1);
603 fprintf(output, "\n");
604 }
605 break;
606 case XPATH_LOCATIONSET:
607#if defined(LIBXML_XPTR_ENABLED)
608 fprintf(output, "Object is a Location Set:\n");
609 xmlXPathDebugDumpLocationSet(output,
610 (xmlLocationSetPtr) cur->user, depth);
611#endif
612 break;
613 case XPATH_USERS:
614 fprintf(output, "Object is user defined\n");
615 break;
616 }
617}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000618
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000619static void
620xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000621 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;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000781 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000782#ifdef LIBXML_XPTR_ENABLED
783 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
784#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000785 default:
786 fprintf(output, "UNKNOWN %d\n", op->op); return;
787 }
788 fprintf(output, "\n");
789finish:
790 if (op->ch1 >= 0)
791 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
792 if (op->ch2 >= 0)
793 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
794}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000795
796void
797xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
798 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000799 int i;
800 char shift[100];
801
802 for (i = 0;((i < depth) && (i < 25));i++)
803 shift[2 * i] = shift[2 * i + 1] = ' ';
804 shift[2 * i] = shift[2 * i + 1] = 0;
805
806 fprintf(output, shift);
807
808 if (comp == NULL) {
809 fprintf(output, "Compiled Expression is NULL\n");
810 return;
811 }
812 fprintf(output, "Compiled Expression : %d elements\n",
813 comp->nbStep);
814 i = comp->last;
815 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
816}
Owen Taylor3473f882001-02-23 17:55:21 +0000817#endif
818
819/************************************************************************
820 * *
821 * Parser stacks related functions and macros *
822 * *
823 ************************************************************************/
824
825/*
826 * Generic function for accessing stacks in the Parser Context
827 */
828
829#define PUSH_AND_POP(type, name) \
830extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
831 if (ctxt->name##Nr >= ctxt->name##Max) { \
832 ctxt->name##Max *= 2; \
833 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
834 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
835 if (ctxt->name##Tab == NULL) { \
836 xmlGenericError(xmlGenericErrorContext, \
837 "realloc failed !\n"); \
838 return(0); \
839 } \
840 } \
841 ctxt->name##Tab[ctxt->name##Nr] = value; \
842 ctxt->name = value; \
843 return(ctxt->name##Nr++); \
844} \
845extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
846 type ret; \
847 if (ctxt->name##Nr <= 0) return(0); \
848 ctxt->name##Nr--; \
849 if (ctxt->name##Nr > 0) \
850 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
851 else \
852 ctxt->name = NULL; \
853 ret = ctxt->name##Tab[ctxt->name##Nr]; \
854 ctxt->name##Tab[ctxt->name##Nr] = 0; \
855 return(ret); \
856} \
857
858PUSH_AND_POP(xmlXPathObjectPtr, value)
859
860/*
861 * Macros for accessing the content. Those should be used only by the parser,
862 * and not exported.
863 *
864 * Dirty macros, i.e. one need to make assumption on the context to use them
865 *
866 * CUR_PTR return the current pointer to the xmlChar to be parsed.
867 * CUR returns the current xmlChar value, i.e. a 8 bit value
868 * in ISO-Latin or UTF-8.
869 * This should be used internally by the parser
870 * only to compare to ASCII values otherwise it would break when
871 * running with UTF-8 encoding.
872 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
873 * to compare on ASCII based substring.
874 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
875 * strings within the parser.
876 * CURRENT Returns the current char value, with the full decoding of
877 * UTF-8 if we are using this mode. It returns an int.
878 * NEXT Skip to the next character, this does the proper decoding
879 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
880 * It returns the pointer to the current xmlChar.
881 */
882
883#define CUR (*ctxt->cur)
884#define SKIP(val) ctxt->cur += (val)
885#define NXT(val) ctxt->cur[(val)]
886#define CUR_PTR ctxt->cur
887
888#define SKIP_BLANKS \
889 while (IS_BLANK(*(ctxt->cur))) NEXT
890
891#define CURRENT (*ctxt->cur)
892#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
893
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000894
895#ifndef DBL_DIG
896#define DBL_DIG 16
897#endif
898#ifndef DBL_EPSILON
899#define DBL_EPSILON 1E-9
900#endif
901
902#define UPPER_DOUBLE 1E9
903#define LOWER_DOUBLE 1E-5
904
905#define INTEGER_DIGITS DBL_DIG
906#define FRACTION_DIGITS (DBL_DIG + 1)
907#define EXPONENT_DIGITS (3 + 2)
908
909/**
910 * xmlXPathFormatNumber:
911 * @number: number to format
912 * @buffer: output buffer
913 * @buffersize: size of output buffer
914 *
915 * Convert the number into a string representation.
916 */
917static void
918xmlXPathFormatNumber(double number, char buffer[], int buffersize)
919{
920 switch (isinf(number)) {
921 case 1:
922 if (buffersize > (int)sizeof("+Infinity"))
923 sprintf(buffer, "+Infinity");
924 break;
925 case -1:
926 if (buffersize > (int)sizeof("-Infinity"))
927 sprintf(buffer, "-Infinity");
928 break;
929 default:
930 if (isnan(number)) {
931 if (buffersize > (int)sizeof("NaN"))
932 sprintf(buffer, "NaN");
933 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000934 /* 3 is sign, decimal point, and terminating zero */
935 char work[DBL_DIG + EXPONENT_DIGITS + 3];
936 int integer_place, fraction_place;
937 char *ptr;
938 char *after_fraction;
939 double absolute_value;
940 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000941
Bjorn Reese70a9da52001-04-21 16:57:29 +0000942 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000943
Bjorn Reese70a9da52001-04-21 16:57:29 +0000944 /*
945 * First choose format - scientific or regular floating point.
946 * In either case, result is in work, and after_fraction points
947 * just past the fractional part.
948 */
949 if ( ((absolute_value > UPPER_DOUBLE) ||
950 (absolute_value < LOWER_DOUBLE)) &&
951 (absolute_value != 0.0) ) {
952 /* Use scientific notation */
953 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
954 fraction_place = DBL_DIG - 1;
955 snprintf(work, sizeof(work),"%*.*e",
956 integer_place, fraction_place, number);
957 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000958 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000959 else {
960 /* Use regular notation */
961 integer_place = 1 + (int)log10(absolute_value);
962 fraction_place = (integer_place > 0)
963 ? DBL_DIG - integer_place
964 : DBL_DIG;
965 size = snprintf(work, sizeof(work), "%0.*f",
966 fraction_place, number);
967 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000968 }
969
Bjorn Reese70a9da52001-04-21 16:57:29 +0000970 /* Remove fractional trailing zeroes */
971 ptr = after_fraction;
972 while (*(--ptr) == '0')
973 ;
974 if (*ptr != '.')
975 ptr++;
976 strcpy(ptr, after_fraction);
977
978 /* Finally copy result back to caller */
979 size = strlen(work) + 1;
980 if (size > buffersize) {
981 work[buffersize - 1] = 0;
982 size = buffersize;
983 }
984 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000985 }
986 break;
987 }
988}
989
Owen Taylor3473f882001-02-23 17:55:21 +0000990/************************************************************************
991 * *
992 * Error handling routines *
993 * *
994 ************************************************************************/
995
996
997const char *xmlXPathErrorMessages[] = {
998 "Ok",
999 "Number encoding",
1000 "Unfinished litteral",
1001 "Start of litteral",
1002 "Expected $ for variable reference",
1003 "Undefined variable",
1004 "Invalid predicate",
1005 "Invalid expression",
1006 "Missing closing curly brace",
1007 "Unregistered function",
1008 "Invalid operand",
1009 "Invalid type",
1010 "Invalid number of arguments",
1011 "Invalid context size",
1012 "Invalid context position",
1013 "Memory allocation error",
1014 "Syntax error",
1015 "Resource error",
1016 "Sub resource error",
1017 "Undefined namespace prefix"
1018};
1019
1020/**
1021 * xmlXPathError:
1022 * @ctxt: the XPath Parser context
1023 * @file: the file name
1024 * @line: the line number
1025 * @no: the error number
1026 *
1027 * Create a new xmlNodeSetPtr of type double and of value @val
1028 *
1029 * Returns the newly created object.
1030 */
1031void
1032xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1033 int line, int no) {
1034 int n;
1035 const xmlChar *cur;
1036 const xmlChar *base;
1037
1038 xmlGenericError(xmlGenericErrorContext,
1039 "Error %s:%d: %s\n", file, line,
1040 xmlXPathErrorMessages[no]);
1041
1042 cur = ctxt->cur;
1043 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001044 if ((cur == NULL) || (base == NULL))
1045 return;
1046
Owen Taylor3473f882001-02-23 17:55:21 +00001047 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1048 cur--;
1049 }
1050 n = 0;
1051 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1052 cur--;
1053 if ((*cur == '\n') || (*cur == '\r')) cur++;
1054 base = cur;
1055 n = 0;
1056 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1057 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1058 n++;
1059 }
1060 xmlGenericError(xmlGenericErrorContext, "\n");
1061 cur = ctxt->cur;
1062 while ((*cur == '\n') || (*cur == '\r'))
1063 cur--;
1064 n = 0;
1065 while ((cur != base) && (n++ < 80)) {
1066 xmlGenericError(xmlGenericErrorContext, " ");
1067 base++;
1068 }
1069 xmlGenericError(xmlGenericErrorContext,"^\n");
1070}
1071
1072
1073/************************************************************************
1074 * *
1075 * Routines to handle NodeSets *
1076 * *
1077 ************************************************************************/
1078
1079/**
1080 * xmlXPathCmpNodes:
1081 * @node1: the first node
1082 * @node2: the second node
1083 *
1084 * Compare two nodes w.r.t document order
1085 *
1086 * Returns -2 in case of error 1 if first point < second point, 0 if
1087 * that's the same node, -1 otherwise
1088 */
1089int
1090xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1091 int depth1, depth2;
1092 xmlNodePtr cur, root;
1093
1094 if ((node1 == NULL) || (node2 == NULL))
1095 return(-2);
1096 /*
1097 * a couple of optimizations which will avoid computations in most cases
1098 */
1099 if (node1 == node2)
1100 return(0);
1101 if (node1 == node2->prev)
1102 return(1);
1103 if (node1 == node2->next)
1104 return(-1);
1105
1106 /*
1107 * compute depth to root
1108 */
1109 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1110 if (cur == node1)
1111 return(1);
1112 depth2++;
1113 }
1114 root = cur;
1115 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1116 if (cur == node2)
1117 return(-1);
1118 depth1++;
1119 }
1120 /*
1121 * Distinct document (or distinct entities :-( ) case.
1122 */
1123 if (root != cur) {
1124 return(-2);
1125 }
1126 /*
1127 * get the nearest common ancestor.
1128 */
1129 while (depth1 > depth2) {
1130 depth1--;
1131 node1 = node1->parent;
1132 }
1133 while (depth2 > depth1) {
1134 depth2--;
1135 node2 = node2->parent;
1136 }
1137 while (node1->parent != node2->parent) {
1138 node1 = node1->parent;
1139 node2 = node2->parent;
1140 /* should not happen but just in case ... */
1141 if ((node1 == NULL) || (node2 == NULL))
1142 return(-2);
1143 }
1144 /*
1145 * Find who's first.
1146 */
1147 if (node1 == node2->next)
1148 return(-1);
1149 for (cur = node1->next;cur != NULL;cur = cur->next)
1150 if (cur == node2)
1151 return(1);
1152 return(-1); /* assume there is no sibling list corruption */
1153}
1154
1155/**
1156 * xmlXPathNodeSetSort:
1157 * @set: the node set
1158 *
1159 * Sort the node set in document order
1160 */
1161void
1162xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001163 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001164 xmlNodePtr tmp;
1165
1166 if (set == NULL)
1167 return;
1168
1169 /* Use Shell's sort to sort the node-set */
1170 len = set->nodeNr;
1171 for (incr = len / 2; incr > 0; incr /= 2) {
1172 for (i = incr; i < len; i++) {
1173 j = i - incr;
1174 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001175 if (xmlXPathCmpNodes(set->nodeTab[j],
1176 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001177 tmp = set->nodeTab[j];
1178 set->nodeTab[j] = set->nodeTab[j + incr];
1179 set->nodeTab[j + incr] = tmp;
1180 j -= incr;
1181 } else
1182 break;
1183 }
1184 }
1185 }
1186}
1187
1188#define XML_NODESET_DEFAULT 10
1189/**
1190 * xmlXPathNodeSetCreate:
1191 * @val: an initial xmlNodePtr, or NULL
1192 *
1193 * Create a new xmlNodeSetPtr of type double and of value @val
1194 *
1195 * Returns the newly created object.
1196 */
1197xmlNodeSetPtr
1198xmlXPathNodeSetCreate(xmlNodePtr val) {
1199 xmlNodeSetPtr ret;
1200
1201 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1202 if (ret == NULL) {
1203 xmlGenericError(xmlGenericErrorContext,
1204 "xmlXPathNewNodeSet: out of memory\n");
1205 return(NULL);
1206 }
1207 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1208 if (val != NULL) {
1209 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1210 sizeof(xmlNodePtr));
1211 if (ret->nodeTab == NULL) {
1212 xmlGenericError(xmlGenericErrorContext,
1213 "xmlXPathNewNodeSet: out of memory\n");
1214 return(NULL);
1215 }
1216 memset(ret->nodeTab, 0 ,
1217 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1218 ret->nodeMax = XML_NODESET_DEFAULT;
1219 ret->nodeTab[ret->nodeNr++] = val;
1220 }
1221 return(ret);
1222}
1223
1224/**
1225 * xmlXPathNodeSetAdd:
1226 * @cur: the initial node set
1227 * @val: a new xmlNodePtr
1228 *
1229 * add a new xmlNodePtr ot an existing NodeSet
1230 */
1231void
1232xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1233 int i;
1234
1235 if (val == NULL) return;
1236
1237 /*
1238 * check against doublons
1239 */
1240 for (i = 0;i < cur->nodeNr;i++)
1241 if (cur->nodeTab[i] == val) return;
1242
1243 /*
1244 * grow the nodeTab if needed
1245 */
1246 if (cur->nodeMax == 0) {
1247 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1248 sizeof(xmlNodePtr));
1249 if (cur->nodeTab == NULL) {
1250 xmlGenericError(xmlGenericErrorContext,
1251 "xmlXPathNodeSetAdd: out of memory\n");
1252 return;
1253 }
1254 memset(cur->nodeTab, 0 ,
1255 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1256 cur->nodeMax = XML_NODESET_DEFAULT;
1257 } else if (cur->nodeNr == cur->nodeMax) {
1258 xmlNodePtr *temp;
1259
1260 cur->nodeMax *= 2;
1261 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1262 sizeof(xmlNodePtr));
1263 if (temp == NULL) {
1264 xmlGenericError(xmlGenericErrorContext,
1265 "xmlXPathNodeSetAdd: out of memory\n");
1266 return;
1267 }
1268 cur->nodeTab = temp;
1269 }
1270 cur->nodeTab[cur->nodeNr++] = val;
1271}
1272
1273/**
1274 * xmlXPathNodeSetAddUnique:
1275 * @cur: the initial node set
1276 * @val: a new xmlNodePtr
1277 *
1278 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1279 * when we are sure the node is not already in the set.
1280 */
1281void
1282xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1283 if (val == NULL) return;
1284
1285 /*
1286 * grow the nodeTab if needed
1287 */
1288 if (cur->nodeMax == 0) {
1289 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1290 sizeof(xmlNodePtr));
1291 if (cur->nodeTab == NULL) {
1292 xmlGenericError(xmlGenericErrorContext,
1293 "xmlXPathNodeSetAddUnique: out of memory\n");
1294 return;
1295 }
1296 memset(cur->nodeTab, 0 ,
1297 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1298 cur->nodeMax = XML_NODESET_DEFAULT;
1299 } else if (cur->nodeNr == cur->nodeMax) {
1300 xmlNodePtr *temp;
1301
1302 cur->nodeMax *= 2;
1303 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1304 sizeof(xmlNodePtr));
1305 if (temp == NULL) {
1306 xmlGenericError(xmlGenericErrorContext,
1307 "xmlXPathNodeSetAddUnique: out of memory\n");
1308 return;
1309 }
1310 cur->nodeTab = temp;
1311 }
1312 cur->nodeTab[cur->nodeNr++] = val;
1313}
1314
1315/**
1316 * xmlXPathNodeSetMerge:
1317 * @val1: the first NodeSet or NULL
1318 * @val2: the second NodeSet
1319 *
1320 * Merges two nodesets, all nodes from @val2 are added to @val1
1321 * if @val1 is NULL, a new set is created and copied from @val2
1322 *
1323 * Returns val1 once extended or NULL in case of error.
1324 */
1325xmlNodeSetPtr
1326xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001327 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001328
1329 if (val2 == NULL) return(val1);
1330 if (val1 == NULL) {
1331 val1 = xmlXPathNodeSetCreate(NULL);
1332 }
1333
1334 initNr = val1->nodeNr;
1335
1336 for (i = 0;i < val2->nodeNr;i++) {
1337 /*
1338 * check against doublons
1339 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001340 skip = 0;
1341 for (j = 0; j < initNr; j++) {
1342 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1343 skip = 1;
1344 break;
1345 }
1346 }
1347 if (skip)
1348 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001349
1350 /*
1351 * grow the nodeTab if needed
1352 */
1353 if (val1->nodeMax == 0) {
1354 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1355 sizeof(xmlNodePtr));
1356 if (val1->nodeTab == NULL) {
1357 xmlGenericError(xmlGenericErrorContext,
1358 "xmlXPathNodeSetMerge: out of memory\n");
1359 return(NULL);
1360 }
1361 memset(val1->nodeTab, 0 ,
1362 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1363 val1->nodeMax = XML_NODESET_DEFAULT;
1364 } else if (val1->nodeNr == val1->nodeMax) {
1365 xmlNodePtr *temp;
1366
1367 val1->nodeMax *= 2;
1368 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1369 sizeof(xmlNodePtr));
1370 if (temp == NULL) {
1371 xmlGenericError(xmlGenericErrorContext,
1372 "xmlXPathNodeSetMerge: out of memory\n");
1373 return(NULL);
1374 }
1375 val1->nodeTab = temp;
1376 }
1377 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1378 }
1379
1380 return(val1);
1381}
1382
1383/**
1384 * xmlXPathNodeSetDel:
1385 * @cur: the initial node set
1386 * @val: an xmlNodePtr
1387 *
1388 * Removes an xmlNodePtr from an existing NodeSet
1389 */
1390void
1391xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1392 int i;
1393
1394 if (cur == NULL) return;
1395 if (val == NULL) return;
1396
1397 /*
1398 * check against doublons
1399 */
1400 for (i = 0;i < cur->nodeNr;i++)
1401 if (cur->nodeTab[i] == val) break;
1402
1403 if (i >= cur->nodeNr) {
1404#ifdef DEBUG
1405 xmlGenericError(xmlGenericErrorContext,
1406 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1407 val->name);
1408#endif
1409 return;
1410 }
1411 cur->nodeNr--;
1412 for (;i < cur->nodeNr;i++)
1413 cur->nodeTab[i] = cur->nodeTab[i + 1];
1414 cur->nodeTab[cur->nodeNr] = NULL;
1415}
1416
1417/**
1418 * xmlXPathNodeSetRemove:
1419 * @cur: the initial node set
1420 * @val: the index to remove
1421 *
1422 * Removes an entry from an existing NodeSet list.
1423 */
1424void
1425xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1426 if (cur == NULL) return;
1427 if (val >= cur->nodeNr) return;
1428 cur->nodeNr--;
1429 for (;val < cur->nodeNr;val++)
1430 cur->nodeTab[val] = cur->nodeTab[val + 1];
1431 cur->nodeTab[cur->nodeNr] = NULL;
1432}
1433
1434/**
1435 * xmlXPathFreeNodeSet:
1436 * @obj: the xmlNodeSetPtr to free
1437 *
1438 * Free the NodeSet compound (not the actual nodes !).
1439 */
1440void
1441xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1442 if (obj == NULL) return;
1443 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001444 xmlFree(obj->nodeTab);
1445 }
Owen Taylor3473f882001-02-23 17:55:21 +00001446 xmlFree(obj);
1447}
1448
1449/**
1450 * xmlXPathFreeValueTree:
1451 * @obj: the xmlNodeSetPtr to free
1452 *
1453 * Free the NodeSet compound and the actual tree, this is different
1454 * from xmlXPathFreeNodeSet()
1455 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001456static void
Owen Taylor3473f882001-02-23 17:55:21 +00001457xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1458 int i;
1459
1460 if (obj == NULL) return;
1461 for (i = 0;i < obj->nodeNr;i++)
1462 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001463 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001464
1465 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001466 xmlFree(obj->nodeTab);
1467 }
Owen Taylor3473f882001-02-23 17:55:21 +00001468 xmlFree(obj);
1469}
1470
1471#if defined(DEBUG) || defined(DEBUG_STEP)
1472/**
1473 * xmlGenericErrorContextNodeSet:
1474 * @output: a FILE * for the output
1475 * @obj: the xmlNodeSetPtr to free
1476 *
1477 * Quick display of a NodeSet
1478 */
1479void
1480xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1481 int i;
1482
1483 if (output == NULL) output = xmlGenericErrorContext;
1484 if (obj == NULL) {
1485 fprintf(output, "NodeSet == NULL !\n");
1486 return;
1487 }
1488 if (obj->nodeNr == 0) {
1489 fprintf(output, "NodeSet is empty\n");
1490 return;
1491 }
1492 if (obj->nodeTab == NULL) {
1493 fprintf(output, " nodeTab == NULL !\n");
1494 return;
1495 }
1496 for (i = 0; i < obj->nodeNr; i++) {
1497 if (obj->nodeTab[i] == NULL) {
1498 fprintf(output, " NULL !\n");
1499 return;
1500 }
1501 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1502 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1503 fprintf(output, " /");
1504 else if (obj->nodeTab[i]->name == NULL)
1505 fprintf(output, " noname!");
1506 else fprintf(output, " %s", obj->nodeTab[i]->name);
1507 }
1508 fprintf(output, "\n");
1509}
1510#endif
1511
1512/**
1513 * xmlXPathNewNodeSet:
1514 * @val: the NodePtr value
1515 *
1516 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1517 * it with the single Node @val
1518 *
1519 * Returns the newly created object.
1520 */
1521xmlXPathObjectPtr
1522xmlXPathNewNodeSet(xmlNodePtr val) {
1523 xmlXPathObjectPtr ret;
1524
1525 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1526 if (ret == NULL) {
1527 xmlGenericError(xmlGenericErrorContext,
1528 "xmlXPathNewNodeSet: out of memory\n");
1529 return(NULL);
1530 }
1531 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1532 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001533 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001534 ret->nodesetval = xmlXPathNodeSetCreate(val);
1535 return(ret);
1536}
1537
1538/**
1539 * xmlXPathNewValueTree:
1540 * @val: the NodePtr value
1541 *
1542 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1543 * it with the tree root @val
1544 *
1545 * Returns the newly created object.
1546 */
1547xmlXPathObjectPtr
1548xmlXPathNewValueTree(xmlNodePtr val) {
1549 xmlXPathObjectPtr ret;
1550
1551 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1552 if (ret == NULL) {
1553 xmlGenericError(xmlGenericErrorContext,
1554 "xmlXPathNewNodeSet: out of memory\n");
1555 return(NULL);
1556 }
1557 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1558 ret->type = XPATH_XSLT_TREE;
1559 ret->nodesetval = xmlXPathNodeSetCreate(val);
1560 return(ret);
1561}
1562
1563/**
1564 * xmlXPathNewNodeSetList:
1565 * @val: an existing NodeSet
1566 *
1567 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1568 * it with the Nodeset @val
1569 *
1570 * Returns the newly created object.
1571 */
1572xmlXPathObjectPtr
1573xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1574 xmlXPathObjectPtr ret;
1575 int i;
1576
1577 if (val == NULL)
1578 ret = NULL;
1579 else if (val->nodeTab == NULL)
1580 ret = xmlXPathNewNodeSet(NULL);
1581 else
1582 {
1583 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1584 for (i = 1; i < val->nodeNr; ++i)
1585 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1586 }
1587
1588 return(ret);
1589}
1590
1591/**
1592 * xmlXPathWrapNodeSet:
1593 * @val: the NodePtr value
1594 *
1595 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1596 *
1597 * Returns the newly created object.
1598 */
1599xmlXPathObjectPtr
1600xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1601 xmlXPathObjectPtr ret;
1602
1603 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1604 if (ret == NULL) {
1605 xmlGenericError(xmlGenericErrorContext,
1606 "xmlXPathWrapNodeSet: out of memory\n");
1607 return(NULL);
1608 }
1609 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1610 ret->type = XPATH_NODESET;
1611 ret->nodesetval = val;
1612 return(ret);
1613}
1614
1615/**
1616 * xmlXPathFreeNodeSetList:
1617 * @obj: an existing NodeSetList object
1618 *
1619 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1620 * the list contrary to xmlXPathFreeObject().
1621 */
1622void
1623xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1624 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001625 xmlFree(obj);
1626}
1627
1628/************************************************************************
1629 * *
1630 * Routines to handle extra functions *
1631 * *
1632 ************************************************************************/
1633
1634/**
1635 * xmlXPathRegisterFunc:
1636 * @ctxt: the XPath context
1637 * @name: the function name
1638 * @f: the function implementation or NULL
1639 *
1640 * Register a new function. If @f is NULL it unregisters the function
1641 *
1642 * Returns 0 in case of success, -1 in case of error
1643 */
1644int
1645xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1646 xmlXPathFunction f) {
1647 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1648}
1649
1650/**
1651 * xmlXPathRegisterFuncNS:
1652 * @ctxt: the XPath context
1653 * @name: the function name
1654 * @ns_uri: the function namespace URI
1655 * @f: the function implementation or NULL
1656 *
1657 * Register a new function. If @f is NULL it unregisters the function
1658 *
1659 * Returns 0 in case of success, -1 in case of error
1660 */
1661int
1662xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1663 const xmlChar *ns_uri, xmlXPathFunction f) {
1664 if (ctxt == NULL)
1665 return(-1);
1666 if (name == NULL)
1667 return(-1);
1668
1669 if (ctxt->funcHash == NULL)
1670 ctxt->funcHash = xmlHashCreate(0);
1671 if (ctxt->funcHash == NULL)
1672 return(-1);
1673 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1674}
1675
1676/**
1677 * xmlXPathFunctionLookup:
1678 * @ctxt: the XPath context
1679 * @name: the function name
1680 *
1681 * Search in the Function array of the context for the given
1682 * function.
1683 *
1684 * Returns the xmlXPathFunction or NULL if not found
1685 */
1686xmlXPathFunction
1687xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1688 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1689}
1690
1691/**
1692 * xmlXPathFunctionLookupNS:
1693 * @ctxt: the XPath context
1694 * @name: the function name
1695 * @ns_uri: the function namespace URI
1696 *
1697 * Search in the Function array of the context for the given
1698 * function.
1699 *
1700 * Returns the xmlXPathFunction or NULL if not found
1701 */
1702xmlXPathFunction
1703xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1704 const xmlChar *ns_uri) {
1705 if (ctxt == NULL)
1706 return(NULL);
1707 if (ctxt->funcHash == NULL)
1708 return(NULL);
1709 if (name == NULL)
1710 return(NULL);
1711
1712 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1713}
1714
1715/**
1716 * xmlXPathRegisteredFuncsCleanup:
1717 * @ctxt: the XPath context
1718 *
1719 * Cleanup the XPath context data associated to registered functions
1720 */
1721void
1722xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1723 if (ctxt == NULL)
1724 return;
1725
1726 xmlHashFree(ctxt->funcHash, NULL);
1727 ctxt->funcHash = NULL;
1728}
1729
1730/************************************************************************
1731 * *
1732 * Routines to handle Variable *
1733 * *
1734 ************************************************************************/
1735
1736/**
1737 * xmlXPathRegisterVariable:
1738 * @ctxt: the XPath context
1739 * @name: the variable name
1740 * @value: the variable value or NULL
1741 *
1742 * Register a new variable value. If @value is NULL it unregisters
1743 * the variable
1744 *
1745 * Returns 0 in case of success, -1 in case of error
1746 */
1747int
1748xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1749 xmlXPathObjectPtr value) {
1750 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1751}
1752
1753/**
1754 * xmlXPathRegisterVariableNS:
1755 * @ctxt: the XPath context
1756 * @name: the variable name
1757 * @ns_uri: the variable namespace URI
1758 * @value: the variable value or NULL
1759 *
1760 * Register a new variable value. If @value is NULL it unregisters
1761 * the variable
1762 *
1763 * Returns 0 in case of success, -1 in case of error
1764 */
1765int
1766xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1767 const xmlChar *ns_uri,
1768 xmlXPathObjectPtr value) {
1769 if (ctxt == NULL)
1770 return(-1);
1771 if (name == NULL)
1772 return(-1);
1773
1774 if (ctxt->varHash == NULL)
1775 ctxt->varHash = xmlHashCreate(0);
1776 if (ctxt->varHash == NULL)
1777 return(-1);
1778 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1779 (void *) value,
1780 (xmlHashDeallocator)xmlXPathFreeObject));
1781}
1782
1783/**
1784 * xmlXPathRegisterVariableLookup:
1785 * @ctxt: the XPath context
1786 * @f: the lookup function
1787 * @data: the lookup data
1788 *
1789 * register an external mechanism to do variable lookup
1790 */
1791void
1792xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1793 xmlXPathVariableLookupFunc f, void *data) {
1794 if (ctxt == NULL)
1795 return;
1796 ctxt->varLookupFunc = (void *) f;
1797 ctxt->varLookupData = data;
1798}
1799
1800/**
1801 * xmlXPathVariableLookup:
1802 * @ctxt: the XPath context
1803 * @name: the variable name
1804 *
1805 * Search in the Variable array of the context for the given
1806 * variable value.
1807 *
1808 * Returns the value or NULL if not found
1809 */
1810xmlXPathObjectPtr
1811xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1812 if (ctxt == NULL)
1813 return(NULL);
1814
1815 if (ctxt->varLookupFunc != NULL) {
1816 xmlXPathObjectPtr ret;
1817
1818 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1819 (ctxt->varLookupData, name, NULL);
1820 if (ret != NULL) return(ret);
1821 }
1822 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1823}
1824
1825/**
1826 * xmlXPathVariableLookupNS:
1827 * @ctxt: the XPath context
1828 * @name: the variable name
1829 * @ns_uri: the variable namespace URI
1830 *
1831 * Search in the Variable array of the context for the given
1832 * variable value.
1833 *
1834 * Returns the value or NULL if not found
1835 */
1836xmlXPathObjectPtr
1837xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1838 const xmlChar *ns_uri) {
1839 if (ctxt == NULL)
1840 return(NULL);
1841
1842 if (ctxt->varLookupFunc != NULL) {
1843 xmlXPathObjectPtr ret;
1844
1845 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1846 (ctxt->varLookupData, name, ns_uri);
1847 if (ret != NULL) return(ret);
1848 }
1849
1850 if (ctxt->varHash == NULL)
1851 return(NULL);
1852 if (name == NULL)
1853 return(NULL);
1854
1855 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1856}
1857
1858/**
1859 * xmlXPathRegisteredVariablesCleanup:
1860 * @ctxt: the XPath context
1861 *
1862 * Cleanup the XPath context data associated to registered variables
1863 */
1864void
1865xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1866 if (ctxt == NULL)
1867 return;
1868
1869 xmlHashFree(ctxt->varHash, NULL);
1870 ctxt->varHash = NULL;
1871}
1872
1873/**
1874 * xmlXPathRegisterNs:
1875 * @ctxt: the XPath context
1876 * @prefix: the namespace prefix
1877 * @ns_uri: the namespace name
1878 *
1879 * Register a new namespace. If @ns_uri is NULL it unregisters
1880 * the namespace
1881 *
1882 * Returns 0 in case of success, -1 in case of error
1883 */
1884int
1885xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1886 const xmlChar *ns_uri) {
1887 if (ctxt == NULL)
1888 return(-1);
1889 if (prefix == NULL)
1890 return(-1);
1891
1892 if (ctxt->nsHash == NULL)
1893 ctxt->nsHash = xmlHashCreate(10);
1894 if (ctxt->nsHash == NULL)
1895 return(-1);
1896 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1897 (xmlHashDeallocator)xmlFree));
1898}
1899
1900/**
1901 * xmlXPathNsLookup:
1902 * @ctxt: the XPath context
1903 * @prefix: the namespace prefix value
1904 *
1905 * Search in the namespace declaration array of the context for the given
1906 * namespace name associated to the given prefix
1907 *
1908 * Returns the value or NULL if not found
1909 */
1910const xmlChar *
1911xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1912 if (ctxt == NULL)
1913 return(NULL);
1914 if (prefix == NULL)
1915 return(NULL);
1916
1917#ifdef XML_XML_NAMESPACE
1918 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1919 return(XML_XML_NAMESPACE);
1920#endif
1921
1922 if (ctxt->nsHash == NULL)
1923 return(NULL);
1924
1925 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1926}
1927
1928/**
1929 * xmlXPathRegisteredVariablesCleanup:
1930 * @ctxt: the XPath context
1931 *
1932 * Cleanup the XPath context data associated to registered variables
1933 */
1934void
1935xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
1936 if (ctxt == NULL)
1937 return;
1938
1939 xmlHashFree(ctxt->nsHash, NULL);
1940 ctxt->nsHash = NULL;
1941}
1942
1943/************************************************************************
1944 * *
1945 * Routines to handle Values *
1946 * *
1947 ************************************************************************/
1948
1949/* Allocations are terrible, one need to optimize all this !!! */
1950
1951/**
1952 * xmlXPathNewFloat:
1953 * @val: the double value
1954 *
1955 * Create a new xmlXPathObjectPtr of type double and of value @val
1956 *
1957 * Returns the newly created object.
1958 */
1959xmlXPathObjectPtr
1960xmlXPathNewFloat(double val) {
1961 xmlXPathObjectPtr ret;
1962
1963 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1964 if (ret == NULL) {
1965 xmlGenericError(xmlGenericErrorContext,
1966 "xmlXPathNewFloat: out of memory\n");
1967 return(NULL);
1968 }
1969 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1970 ret->type = XPATH_NUMBER;
1971 ret->floatval = val;
1972 return(ret);
1973}
1974
1975/**
1976 * xmlXPathNewBoolean:
1977 * @val: the boolean value
1978 *
1979 * Create a new xmlXPathObjectPtr of type boolean and of value @val
1980 *
1981 * Returns the newly created object.
1982 */
1983xmlXPathObjectPtr
1984xmlXPathNewBoolean(int val) {
1985 xmlXPathObjectPtr ret;
1986
1987 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1988 if (ret == NULL) {
1989 xmlGenericError(xmlGenericErrorContext,
1990 "xmlXPathNewBoolean: out of memory\n");
1991 return(NULL);
1992 }
1993 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1994 ret->type = XPATH_BOOLEAN;
1995 ret->boolval = (val != 0);
1996 return(ret);
1997}
1998
1999/**
2000 * xmlXPathNewString:
2001 * @val: the xmlChar * value
2002 *
2003 * Create a new xmlXPathObjectPtr of type string and of value @val
2004 *
2005 * Returns the newly created object.
2006 */
2007xmlXPathObjectPtr
2008xmlXPathNewString(const xmlChar *val) {
2009 xmlXPathObjectPtr ret;
2010
2011 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2012 if (ret == NULL) {
2013 xmlGenericError(xmlGenericErrorContext,
2014 "xmlXPathNewString: out of memory\n");
2015 return(NULL);
2016 }
2017 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2018 ret->type = XPATH_STRING;
2019 if (val != NULL)
2020 ret->stringval = xmlStrdup(val);
2021 else
2022 ret->stringval = xmlStrdup((const xmlChar *)"");
2023 return(ret);
2024}
2025
2026/**
2027 * xmlXPathNewCString:
2028 * @val: the char * value
2029 *
2030 * Create a new xmlXPathObjectPtr of type string and of value @val
2031 *
2032 * Returns the newly created object.
2033 */
2034xmlXPathObjectPtr
2035xmlXPathNewCString(const char *val) {
2036 xmlXPathObjectPtr ret;
2037
2038 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2039 if (ret == NULL) {
2040 xmlGenericError(xmlGenericErrorContext,
2041 "xmlXPathNewCString: out of memory\n");
2042 return(NULL);
2043 }
2044 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2045 ret->type = XPATH_STRING;
2046 ret->stringval = xmlStrdup(BAD_CAST val);
2047 return(ret);
2048}
2049
2050/**
2051 * xmlXPathObjectCopy:
2052 * @val: the original object
2053 *
2054 * allocate a new copy of a given object
2055 *
2056 * Returns the newly created object.
2057 */
2058xmlXPathObjectPtr
2059xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2060 xmlXPathObjectPtr ret;
2061
2062 if (val == NULL)
2063 return(NULL);
2064
2065 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2066 if (ret == NULL) {
2067 xmlGenericError(xmlGenericErrorContext,
2068 "xmlXPathObjectCopy: out of memory\n");
2069 return(NULL);
2070 }
2071 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2072 switch (val->type) {
2073 case XPATH_BOOLEAN:
2074 case XPATH_NUMBER:
2075 case XPATH_POINT:
2076 case XPATH_RANGE:
2077 break;
2078 case XPATH_STRING:
2079 ret->stringval = xmlStrdup(val->stringval);
2080 break;
2081 case XPATH_XSLT_TREE:
2082 if ((val->nodesetval != NULL) &&
2083 (val->nodesetval->nodeTab != NULL))
2084 ret->nodesetval = xmlXPathNodeSetCreate(
2085 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2086 else
2087 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2088 break;
2089 case XPATH_NODESET:
2090 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2091 break;
2092 case XPATH_LOCATIONSET:
2093#ifdef LIBXML_XPTR_ENABLED
2094 {
2095 xmlLocationSetPtr loc = val->user;
2096 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2097 break;
2098 }
2099#endif
2100 case XPATH_UNDEFINED:
2101 case XPATH_USERS:
2102 xmlGenericError(xmlGenericErrorContext,
2103 "xmlXPathObjectCopy: unsupported type %d\n",
2104 val->type);
2105 break;
2106 }
2107 return(ret);
2108}
2109
2110/**
2111 * xmlXPathFreeObject:
2112 * @obj: the object to free
2113 *
2114 * Free up an xmlXPathObjectPtr object.
2115 */
2116void
2117xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2118 if (obj == NULL) return;
2119 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002120 if (obj->boolval) {
2121 obj->type = XPATH_XSLT_TREE;
2122 if (obj->nodesetval != NULL)
2123 xmlXPathFreeValueTree(obj->nodesetval);
2124 } else {
2125 if (obj->nodesetval != NULL)
2126 xmlXPathFreeNodeSet(obj->nodesetval);
2127 }
Owen Taylor3473f882001-02-23 17:55:21 +00002128#ifdef LIBXML_XPTR_ENABLED
2129 } else if (obj->type == XPATH_LOCATIONSET) {
2130 if (obj->user != NULL)
2131 xmlXPtrFreeLocationSet(obj->user);
2132#endif
2133 } else if (obj->type == XPATH_STRING) {
2134 if (obj->stringval != NULL)
2135 xmlFree(obj->stringval);
2136 } else if (obj->type == XPATH_XSLT_TREE) {
2137 if (obj->nodesetval != NULL)
2138 xmlXPathFreeValueTree(obj->nodesetval);
2139 }
2140
Owen Taylor3473f882001-02-23 17:55:21 +00002141 xmlFree(obj);
2142}
2143
2144/************************************************************************
2145 * *
2146 * Routines to handle XPath contexts *
2147 * *
2148 ************************************************************************/
2149
2150/**
2151 * xmlXPathNewContext:
2152 * @doc: the XML document
2153 *
2154 * Create a new xmlXPathContext
2155 *
2156 * Returns the xmlXPathContext just allocated.
2157 */
2158xmlXPathContextPtr
2159xmlXPathNewContext(xmlDocPtr doc) {
2160 xmlXPathContextPtr ret;
2161
2162 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2163 if (ret == NULL) {
2164 xmlGenericError(xmlGenericErrorContext,
2165 "xmlXPathNewContext: out of memory\n");
2166 return(NULL);
2167 }
2168 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2169 ret->doc = doc;
2170 ret->node = NULL;
2171
2172 ret->varHash = NULL;
2173
2174 ret->nb_types = 0;
2175 ret->max_types = 0;
2176 ret->types = NULL;
2177
2178 ret->funcHash = xmlHashCreate(0);
2179
2180 ret->nb_axis = 0;
2181 ret->max_axis = 0;
2182 ret->axis = NULL;
2183
2184 ret->nsHash = NULL;
2185 ret->user = NULL;
2186
2187 ret->contextSize = -1;
2188 ret->proximityPosition = -1;
2189
2190 xmlXPathRegisterAllFunctions(ret);
2191
2192 return(ret);
2193}
2194
2195/**
2196 * xmlXPathFreeContext:
2197 * @ctxt: the context to free
2198 *
2199 * Free up an xmlXPathContext
2200 */
2201void
2202xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2203 xmlXPathRegisteredNsCleanup(ctxt);
2204 xmlXPathRegisteredFuncsCleanup(ctxt);
2205 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002206 xmlFree(ctxt);
2207}
2208
2209/************************************************************************
2210 * *
2211 * Routines to handle XPath parser contexts *
2212 * *
2213 ************************************************************************/
2214
2215#define CHECK_CTXT(ctxt) \
2216 if (ctxt == NULL) { \
2217 xmlGenericError(xmlGenericErrorContext, \
2218 "%s:%d Internal error: ctxt == NULL\n", \
2219 __FILE__, __LINE__); \
2220 } \
2221
2222
2223#define CHECK_CONTEXT(ctxt) \
2224 if (ctxt == NULL) { \
2225 xmlGenericError(xmlGenericErrorContext, \
2226 "%s:%d Internal error: no context\n", \
2227 __FILE__, __LINE__); \
2228 } \
2229 else if (ctxt->doc == NULL) { \
2230 xmlGenericError(xmlGenericErrorContext, \
2231 "%s:%d Internal error: no document\n", \
2232 __FILE__, __LINE__); \
2233 } \
2234 else if (ctxt->doc->children == NULL) { \
2235 xmlGenericError(xmlGenericErrorContext, \
2236 "%s:%d Internal error: document without root\n", \
2237 __FILE__, __LINE__); \
2238 } \
2239
2240
2241/**
2242 * xmlXPathNewParserContext:
2243 * @str: the XPath expression
2244 * @ctxt: the XPath context
2245 *
2246 * Create a new xmlXPathParserContext
2247 *
2248 * Returns the xmlXPathParserContext just allocated.
2249 */
2250xmlXPathParserContextPtr
2251xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2252 xmlXPathParserContextPtr ret;
2253
2254 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2255 if (ret == NULL) {
2256 xmlGenericError(xmlGenericErrorContext,
2257 "xmlXPathNewParserContext: out of memory\n");
2258 return(NULL);
2259 }
2260 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2261 ret->cur = ret->base = str;
2262 ret->context = ctxt;
2263
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002264 ret->comp = xmlXPathNewCompExpr();
2265 if (ret->comp == NULL) {
2266 xmlFree(ret->valueTab);
2267 xmlFree(ret);
2268 return(NULL);
2269 }
2270
2271 return(ret);
2272}
2273
2274/**
2275 * xmlXPathCompParserContext:
2276 * @comp: the XPath compiled expression
2277 * @ctxt: the XPath context
2278 *
2279 * Create a new xmlXPathParserContext when processing a compiled expression
2280 *
2281 * Returns the xmlXPathParserContext just allocated.
2282 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002283static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002284xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2285 xmlXPathParserContextPtr ret;
2286
2287 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2288 if (ret == NULL) {
2289 xmlGenericError(xmlGenericErrorContext,
2290 "xmlXPathNewParserContext: out of memory\n");
2291 return(NULL);
2292 }
2293 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2294
Owen Taylor3473f882001-02-23 17:55:21 +00002295 /* Allocate the value stack */
2296 ret->valueTab = (xmlXPathObjectPtr *)
2297 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002298 if (ret->valueTab == NULL) {
2299 xmlFree(ret);
2300 xmlGenericError(xmlGenericErrorContext,
2301 "xmlXPathNewParserContext: out of memory\n");
2302 return(NULL);
2303 }
Owen Taylor3473f882001-02-23 17:55:21 +00002304 ret->valueNr = 0;
2305 ret->valueMax = 10;
2306 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002307
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002308 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002309 ret->comp = comp;
2310
Owen Taylor3473f882001-02-23 17:55:21 +00002311 return(ret);
2312}
2313
2314/**
2315 * xmlXPathFreeParserContext:
2316 * @ctxt: the context to free
2317 *
2318 * Free up an xmlXPathParserContext
2319 */
2320void
2321xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2322 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002323 xmlFree(ctxt->valueTab);
2324 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002325 if (ctxt->comp)
2326 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002327 xmlFree(ctxt);
2328}
2329
2330/************************************************************************
2331 * *
2332 * The implicit core function library *
2333 * *
2334 ************************************************************************/
2335
2336/*
2337 * Auto-pop and cast to a number
2338 */
2339void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
2340
2341
2342#define POP_FLOAT \
2343 arg = valuePop(ctxt); \
2344 if (arg == NULL) { \
2345 XP_ERROR(XPATH_INVALID_OPERAND); \
2346 } \
2347 if (arg->type != XPATH_NUMBER) { \
2348 valuePush(ctxt, arg); \
2349 xmlXPathNumberFunction(ctxt, 1); \
2350 arg = valuePop(ctxt); \
2351 }
2352
2353/**
2354 * xmlXPathCompareNodeSetFloat:
2355 * @ctxt: the XPath Parser context
2356 * @inf: less than (1) or greater than (0)
2357 * @strict: is the comparison strict
2358 * @arg: the node set
2359 * @f: the value
2360 *
2361 * Implement the compare operation between a nodeset and a number
2362 * @ns < @val (1, 1, ...
2363 * @ns <= @val (1, 0, ...
2364 * @ns > @val (0, 1, ...
2365 * @ns >= @val (0, 0, ...
2366 *
2367 * If one object to be compared is a node-set and the other is a number,
2368 * then the comparison will be true if and only if there is a node in the
2369 * node-set such that the result of performing the comparison on the number
2370 * to be compared and on the result of converting the string-value of that
2371 * node to a number using the number function is true.
2372 *
2373 * Returns 0 or 1 depending on the results of the test.
2374 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002375static int
Owen Taylor3473f882001-02-23 17:55:21 +00002376xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2377 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2378 int i, ret = 0;
2379 xmlNodeSetPtr ns;
2380 xmlChar *str2;
2381
2382 if ((f == NULL) || (arg == NULL) ||
2383 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2384 xmlXPathFreeObject(arg);
2385 xmlXPathFreeObject(f);
2386 return(0);
2387 }
2388 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002389 if (ns != NULL) {
2390 for (i = 0;i < ns->nodeNr;i++) {
2391 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2392 if (str2 != NULL) {
2393 valuePush(ctxt,
2394 xmlXPathNewString(str2));
2395 xmlFree(str2);
2396 xmlXPathNumberFunction(ctxt, 1);
2397 valuePush(ctxt, xmlXPathObjectCopy(f));
2398 ret = xmlXPathCompareValues(ctxt, inf, strict);
2399 if (ret)
2400 break;
2401 }
2402 }
Owen Taylor3473f882001-02-23 17:55:21 +00002403 }
2404 xmlXPathFreeObject(arg);
2405 xmlXPathFreeObject(f);
2406 return(ret);
2407}
2408
2409/**
2410 * xmlXPathCompareNodeSetString:
2411 * @ctxt: the XPath Parser context
2412 * @inf: less than (1) or greater than (0)
2413 * @strict: is the comparison strict
2414 * @arg: the node set
2415 * @s: the value
2416 *
2417 * Implement the compare operation between a nodeset and a string
2418 * @ns < @val (1, 1, ...
2419 * @ns <= @val (1, 0, ...
2420 * @ns > @val (0, 1, ...
2421 * @ns >= @val (0, 0, ...
2422 *
2423 * If one object to be compared is a node-set and the other is a string,
2424 * then the comparison will be true if and only if there is a node in
2425 * the node-set such that the result of performing the comparison on the
2426 * string-value of the node and the other string is true.
2427 *
2428 * Returns 0 or 1 depending on the results of the test.
2429 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002430static int
Owen Taylor3473f882001-02-23 17:55:21 +00002431xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2432 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2433 int i, ret = 0;
2434 xmlNodeSetPtr ns;
2435 xmlChar *str2;
2436
2437 if ((s == NULL) || (arg == NULL) ||
2438 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2439 xmlXPathFreeObject(arg);
2440 xmlXPathFreeObject(s);
2441 return(0);
2442 }
2443 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002444 if (ns != NULL) {
2445 for (i = 0;i < ns->nodeNr;i++) {
2446 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2447 if (str2 != NULL) {
2448 valuePush(ctxt,
2449 xmlXPathNewString(str2));
2450 xmlFree(str2);
2451 valuePush(ctxt, xmlXPathObjectCopy(s));
2452 ret = xmlXPathCompareValues(ctxt, inf, strict);
2453 if (ret)
2454 break;
2455 }
2456 }
Owen Taylor3473f882001-02-23 17:55:21 +00002457 }
2458 xmlXPathFreeObject(arg);
2459 xmlXPathFreeObject(s);
2460 return(ret);
2461}
2462
2463/**
2464 * xmlXPathCompareNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00002465 * @op: less than (-1), equal (0) or greater than (1)
2466 * @strict: is the comparison strict
2467 * @arg1: the fist node set object
2468 * @arg2: the second node set object
2469 *
2470 * Implement the compare operation on nodesets:
2471 *
2472 * If both objects to be compared are node-sets, then the comparison
2473 * will be true if and only if there is a node in the first node-set
2474 * and a node in the second node-set such that the result of performing
2475 * the comparison on the string-values of the two nodes is true.
2476 * ....
2477 * When neither object to be compared is a node-set and the operator
2478 * is <=, <, >= or >, then the objects are compared by converting both
2479 * objects to numbers and comparing the numbers according to IEEE 754.
2480 * ....
2481 * The number function converts its argument to a number as follows:
2482 * - a string that consists of optional whitespace followed by an
2483 * optional minus sign followed by a Number followed by whitespace
2484 * is converted to the IEEE 754 number that is nearest (according
2485 * to the IEEE 754 round-to-nearest rule) to the mathematical value
2486 * represented by the string; any other string is converted to NaN
2487 *
2488 * Conclusion all nodes need to be converted first to their string value
2489 * and then the comparison must be done when possible
2490 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002491static int
2492xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00002493 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2494 int i, j, init = 0;
2495 double val1;
2496 double *values2;
2497 int ret = 0;
2498 xmlChar *str;
2499 xmlNodeSetPtr ns1;
2500 xmlNodeSetPtr ns2;
2501
2502 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002503 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
2504 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002505 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002506 }
Owen Taylor3473f882001-02-23 17:55:21 +00002507 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002508 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
2509 xmlXPathFreeObject(arg1);
2510 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002511 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002512 }
Owen Taylor3473f882001-02-23 17:55:21 +00002513
2514 ns1 = arg1->nodesetval;
2515 ns2 = arg2->nodesetval;
2516
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002517 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002518 xmlXPathFreeObject(arg1);
2519 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002520 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002521 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002522 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002523 xmlXPathFreeObject(arg1);
2524 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002525 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002526 }
Owen Taylor3473f882001-02-23 17:55:21 +00002527
2528 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
2529 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002530 xmlXPathFreeObject(arg1);
2531 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002532 return(0);
2533 }
2534 for (i = 0;i < ns1->nodeNr;i++) {
2535 str = xmlNodeGetContent(ns1->nodeTab[i]);
2536 if (str == NULL)
2537 continue;
2538 val1 = xmlXPathStringEvalNumber(str);
2539 xmlFree(str);
2540 if (isnan(val1))
2541 continue;
2542 for (j = 0;j < ns2->nodeNr;j++) {
2543 if (init == 0) {
2544 str = xmlNodeGetContent(ns2->nodeTab[j]);
2545 if (str == NULL) {
2546 values2[j] = xmlXPathNAN;
2547 } else {
2548 values2[j] = xmlXPathStringEvalNumber(str);
2549 xmlFree(str);
2550 }
2551 }
2552 if (isnan(values2[j]))
2553 continue;
2554 if (inf && strict)
2555 ret = (val1 < values2[j]);
2556 else if (inf && !strict)
2557 ret = (val1 <= values2[j]);
2558 else if (!inf && strict)
2559 ret = (val1 > values2[j]);
2560 else if (!inf && !strict)
2561 ret = (val1 >= values2[j]);
2562 if (ret)
2563 break;
2564 }
2565 if (ret)
2566 break;
2567 init = 1;
2568 }
2569 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002570 xmlXPathFreeObject(arg1);
2571 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002572 return(ret);
2573 return(0);
2574}
2575
2576/**
2577 * xmlXPathCompareNodeSetValue:
2578 * @ctxt: the XPath Parser context
2579 * @inf: less than (1) or greater than (0)
2580 * @strict: is the comparison strict
2581 * @arg: the node set
2582 * @val: the value
2583 *
2584 * Implement the compare operation between a nodeset and a value
2585 * @ns < @val (1, 1, ...
2586 * @ns <= @val (1, 0, ...
2587 * @ns > @val (0, 1, ...
2588 * @ns >= @val (0, 0, ...
2589 *
2590 * If one object to be compared is a node-set and the other is a boolean,
2591 * then the comparison will be true if and only if the result of performing
2592 * the comparison on the boolean and on the result of converting
2593 * the node-set to a boolean using the boolean function is true.
2594 *
2595 * Returns 0 or 1 depending on the results of the test.
2596 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002597static int
Owen Taylor3473f882001-02-23 17:55:21 +00002598xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
2599 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
2600 if ((val == NULL) || (arg == NULL) ||
2601 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2602 return(0);
2603
2604 switch(val->type) {
2605 case XPATH_NUMBER:
2606 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
2607 case XPATH_NODESET:
2608 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002609 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00002610 case XPATH_STRING:
2611 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
2612 case XPATH_BOOLEAN:
2613 valuePush(ctxt, arg);
2614 xmlXPathBooleanFunction(ctxt, 1);
2615 valuePush(ctxt, val);
2616 return(xmlXPathCompareValues(ctxt, inf, strict));
2617 default:
2618 TODO
2619 return(0);
2620 }
2621 return(0);
2622}
2623
2624/**
2625 * xmlXPathEqualNodeSetString
2626 * @arg: the nodeset object argument
2627 * @str: the string to compare to.
2628 *
2629 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2630 * If one object to be compared is a node-set and the other is a string,
2631 * then the comparison will be true if and only if there is a node in
2632 * the node-set such that the result of performing the comparison on the
2633 * string-value of the node and the other string is true.
2634 *
2635 * Returns 0 or 1 depending on the results of the test.
2636 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002637static int
Owen Taylor3473f882001-02-23 17:55:21 +00002638xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
2639 int i;
2640 xmlNodeSetPtr ns;
2641 xmlChar *str2;
2642
2643 if ((str == NULL) || (arg == NULL) ||
2644 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2645 return(0);
2646 ns = arg->nodesetval;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002647 if (ns == NULL)
2648 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002649 if (ns->nodeNr <= 0)
2650 return(0);
2651 for (i = 0;i < ns->nodeNr;i++) {
2652 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2653 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
2654 xmlFree(str2);
2655 return(1);
2656 }
2657 if (str2 != NULL)
2658 xmlFree(str2);
2659 }
2660 return(0);
2661}
2662
2663/**
2664 * xmlXPathEqualNodeSetFloat
2665 * @arg: the nodeset object argument
2666 * @f: the float to compare to
2667 *
2668 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2669 * If one object to be compared is a node-set and the other is a number,
2670 * then the comparison will be true if and only if there is a node in
2671 * the node-set such that the result of performing the comparison on the
2672 * number to be compared and on the result of converting the string-value
2673 * of that node to a number using the number function is true.
2674 *
2675 * Returns 0 or 1 depending on the results of the test.
2676 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002677static int
Owen Taylor3473f882001-02-23 17:55:21 +00002678xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
2679 char buf[100] = "";
2680
2681 if ((arg == NULL) ||
2682 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2683 return(0);
2684
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002685 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00002686 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
2687}
2688
2689
2690/**
2691 * xmlXPathEqualNodeSets
2692 * @arg1: first nodeset object argument
2693 * @arg2: second nodeset object argument
2694 *
2695 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
2696 * If both objects to be compared are node-sets, then the comparison
2697 * will be true if and only if there is a node in the first node-set and
2698 * a node in the second node-set such that the result of performing the
2699 * comparison on the string-values of the two nodes is true.
2700 *
2701 * (needless to say, this is a costly operation)
2702 *
2703 * Returns 0 or 1 depending on the results of the test.
2704 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002705static int
Owen Taylor3473f882001-02-23 17:55:21 +00002706xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2707 int i, j;
2708 xmlChar **values1;
2709 xmlChar **values2;
2710 int ret = 0;
2711 xmlNodeSetPtr ns1;
2712 xmlNodeSetPtr ns2;
2713
2714 if ((arg1 == NULL) ||
2715 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
2716 return(0);
2717 if ((arg2 == NULL) ||
2718 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
2719 return(0);
2720
2721 ns1 = arg1->nodesetval;
2722 ns2 = arg2->nodesetval;
2723
Daniel Veillard911f49a2001-04-07 15:39:35 +00002724 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00002725 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002726 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00002727 return(0);
2728
2729 /*
2730 * check if there is a node pertaining to both sets
2731 */
2732 for (i = 0;i < ns1->nodeNr;i++)
2733 for (j = 0;j < ns2->nodeNr;j++)
2734 if (ns1->nodeTab[i] == ns2->nodeTab[j])
2735 return(1);
2736
2737 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
2738 if (values1 == NULL)
2739 return(0);
2740 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
2741 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
2742 if (values2 == NULL) {
2743 xmlFree(values1);
2744 return(0);
2745 }
2746 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
2747 for (i = 0;i < ns1->nodeNr;i++) {
2748 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
2749 for (j = 0;j < ns2->nodeNr;j++) {
2750 if (i == 0)
2751 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
2752 ret = xmlStrEqual(values1[i], values2[j]);
2753 if (ret)
2754 break;
2755 }
2756 if (ret)
2757 break;
2758 }
2759 for (i = 0;i < ns1->nodeNr;i++)
2760 if (values1[i] != NULL)
2761 xmlFree(values1[i]);
2762 for (j = 0;j < ns2->nodeNr;j++)
2763 if (values2[j] != NULL)
2764 xmlFree(values2[j]);
2765 xmlFree(values1);
2766 xmlFree(values2);
2767 return(ret);
2768}
2769
2770/**
2771 * xmlXPathEqualValues:
2772 * @ctxt: the XPath Parser context
2773 *
2774 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2775 *
2776 * Returns 0 or 1 depending on the results of the test.
2777 */
2778int
2779xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
2780 xmlXPathObjectPtr arg1, arg2;
2781 int ret = 0;
2782
2783 arg1 = valuePop(ctxt);
2784 if (arg1 == NULL)
2785 XP_ERROR0(XPATH_INVALID_OPERAND);
2786
2787 arg2 = valuePop(ctxt);
2788 if (arg2 == NULL) {
2789 xmlXPathFreeObject(arg1);
2790 XP_ERROR0(XPATH_INVALID_OPERAND);
2791 }
2792
2793 if (arg1 == arg2) {
2794#ifdef DEBUG_EXPR
2795 xmlGenericError(xmlGenericErrorContext,
2796 "Equal: by pointer\n");
2797#endif
2798 return(1);
2799 }
2800
2801 switch (arg1->type) {
2802 case XPATH_UNDEFINED:
2803#ifdef DEBUG_EXPR
2804 xmlGenericError(xmlGenericErrorContext,
2805 "Equal: undefined\n");
2806#endif
2807 break;
2808 case XPATH_XSLT_TREE:
2809 case XPATH_NODESET:
2810 switch (arg2->type) {
2811 case XPATH_UNDEFINED:
2812#ifdef DEBUG_EXPR
2813 xmlGenericError(xmlGenericErrorContext,
2814 "Equal: undefined\n");
2815#endif
2816 break;
2817 case XPATH_XSLT_TREE:
2818 case XPATH_NODESET:
2819 ret = xmlXPathEqualNodeSets(arg1, arg2);
2820 break;
2821 case XPATH_BOOLEAN:
2822 if ((arg1->nodesetval == NULL) ||
2823 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2824 else
2825 ret = 1;
2826 ret = (ret == arg2->boolval);
2827 break;
2828 case XPATH_NUMBER:
2829 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2830 break;
2831 case XPATH_STRING:
2832 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2833 break;
2834 case XPATH_USERS:
2835 case XPATH_POINT:
2836 case XPATH_RANGE:
2837 case XPATH_LOCATIONSET:
2838 TODO
2839 break;
2840 }
2841 break;
2842 case XPATH_BOOLEAN:
2843 switch (arg2->type) {
2844 case XPATH_UNDEFINED:
2845#ifdef DEBUG_EXPR
2846 xmlGenericError(xmlGenericErrorContext,
2847 "Equal: undefined\n");
2848#endif
2849 break;
2850 case XPATH_NODESET:
2851 case XPATH_XSLT_TREE:
2852 if ((arg2->nodesetval == NULL) ||
2853 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2854 else
2855 ret = 1;
2856 break;
2857 case XPATH_BOOLEAN:
2858#ifdef DEBUG_EXPR
2859 xmlGenericError(xmlGenericErrorContext,
2860 "Equal: %d boolean %d \n",
2861 arg1->boolval, arg2->boolval);
2862#endif
2863 ret = (arg1->boolval == arg2->boolval);
2864 break;
2865 case XPATH_NUMBER:
2866 if (arg2->floatval) ret = 1;
2867 else ret = 0;
2868 ret = (arg1->boolval == ret);
2869 break;
2870 case XPATH_STRING:
2871 if ((arg2->stringval == NULL) ||
2872 (arg2->stringval[0] == 0)) ret = 0;
2873 else
2874 ret = 1;
2875 ret = (arg1->boolval == ret);
2876 break;
2877 case XPATH_USERS:
2878 case XPATH_POINT:
2879 case XPATH_RANGE:
2880 case XPATH_LOCATIONSET:
2881 TODO
2882 break;
2883 }
2884 break;
2885 case XPATH_NUMBER:
2886 switch (arg2->type) {
2887 case XPATH_UNDEFINED:
2888#ifdef DEBUG_EXPR
2889 xmlGenericError(xmlGenericErrorContext,
2890 "Equal: undefined\n");
2891#endif
2892 break;
2893 case XPATH_NODESET:
2894 case XPATH_XSLT_TREE:
2895 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2896 break;
2897 case XPATH_BOOLEAN:
2898 if (arg1->floatval) ret = 1;
2899 else ret = 0;
2900 ret = (arg2->boolval == ret);
2901 break;
2902 case XPATH_STRING:
2903 valuePush(ctxt, arg2);
2904 xmlXPathNumberFunction(ctxt, 1);
2905 arg2 = valuePop(ctxt);
2906 /* no break on purpose */
2907 case XPATH_NUMBER:
2908 ret = (arg1->floatval == arg2->floatval);
2909 break;
2910 case XPATH_USERS:
2911 case XPATH_POINT:
2912 case XPATH_RANGE:
2913 case XPATH_LOCATIONSET:
2914 TODO
2915 break;
2916 }
2917 break;
2918 case XPATH_STRING:
2919 switch (arg2->type) {
2920 case XPATH_UNDEFINED:
2921#ifdef DEBUG_EXPR
2922 xmlGenericError(xmlGenericErrorContext,
2923 "Equal: undefined\n");
2924#endif
2925 break;
2926 case XPATH_NODESET:
2927 case XPATH_XSLT_TREE:
2928 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2929 break;
2930 case XPATH_BOOLEAN:
2931 if ((arg1->stringval == NULL) ||
2932 (arg1->stringval[0] == 0)) ret = 0;
2933 else
2934 ret = 1;
2935 ret = (arg2->boolval == ret);
2936 break;
2937 case XPATH_STRING:
2938 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
2939 break;
2940 case XPATH_NUMBER:
2941 valuePush(ctxt, arg1);
2942 xmlXPathNumberFunction(ctxt, 1);
2943 arg1 = valuePop(ctxt);
2944 ret = (arg1->floatval == arg2->floatval);
2945 break;
2946 case XPATH_USERS:
2947 case XPATH_POINT:
2948 case XPATH_RANGE:
2949 case XPATH_LOCATIONSET:
2950 TODO
2951 break;
2952 }
2953 break;
2954 case XPATH_USERS:
2955 case XPATH_POINT:
2956 case XPATH_RANGE:
2957 case XPATH_LOCATIONSET:
2958 TODO
2959 break;
2960 }
2961 xmlXPathFreeObject(arg1);
2962 xmlXPathFreeObject(arg2);
2963 return(ret);
2964}
2965
2966
2967/**
2968 * xmlXPathCompareValues:
2969 * @ctxt: the XPath Parser context
2970 * @inf: less than (1) or greater than (0)
2971 * @strict: is the comparison strict
2972 *
2973 * Implement the compare operation on XPath objects:
2974 * @arg1 < @arg2 (1, 1, ...
2975 * @arg1 <= @arg2 (1, 0, ...
2976 * @arg1 > @arg2 (0, 1, ...
2977 * @arg1 >= @arg2 (0, 0, ...
2978 *
2979 * When neither object to be compared is a node-set and the operator is
2980 * <=, <, >=, >, then the objects are compared by converted both objects
2981 * to numbers and comparing the numbers according to IEEE 754. The <
2982 * comparison will be true if and only if the first number is less than the
2983 * second number. The <= comparison will be true if and only if the first
2984 * number is less than or equal to the second number. The > comparison
2985 * will be true if and only if the first number is greater than the second
2986 * number. The >= comparison will be true if and only if the first number
2987 * is greater than or equal to the second number.
2988 *
2989 * Returns 1 if the comparaison succeeded, 0 if it failed
2990 */
2991int
2992xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
2993 int ret = 0;
2994 xmlXPathObjectPtr arg1, arg2;
2995
2996 arg2 = valuePop(ctxt);
2997 if (arg2 == NULL) {
2998 XP_ERROR0(XPATH_INVALID_OPERAND);
2999 }
3000
3001 arg1 = valuePop(ctxt);
3002 if (arg1 == NULL) {
3003 xmlXPathFreeObject(arg2);
3004 XP_ERROR0(XPATH_INVALID_OPERAND);
3005 }
3006
3007 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3008 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003009 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003010 } else {
3011 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003012 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3013 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003014 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003015 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3016 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003017 }
3018 }
3019 return(ret);
3020 }
3021
3022 if (arg1->type != XPATH_NUMBER) {
3023 valuePush(ctxt, arg1);
3024 xmlXPathNumberFunction(ctxt, 1);
3025 arg1 = valuePop(ctxt);
3026 }
3027 if (arg1->type != XPATH_NUMBER) {
3028 xmlXPathFreeObject(arg1);
3029 xmlXPathFreeObject(arg2);
3030 XP_ERROR0(XPATH_INVALID_OPERAND);
3031 }
3032 if (arg2->type != XPATH_NUMBER) {
3033 valuePush(ctxt, arg2);
3034 xmlXPathNumberFunction(ctxt, 1);
3035 arg2 = valuePop(ctxt);
3036 }
3037 if (arg2->type != XPATH_NUMBER) {
3038 xmlXPathFreeObject(arg1);
3039 xmlXPathFreeObject(arg2);
3040 XP_ERROR0(XPATH_INVALID_OPERAND);
3041 }
3042 /*
3043 * Add tests for infinity and nan
3044 * => feedback on 3.4 for Inf and NaN
3045 */
3046 if (inf && strict)
3047 ret = (arg1->floatval < arg2->floatval);
3048 else if (inf && !strict)
3049 ret = (arg1->floatval <= arg2->floatval);
3050 else if (!inf && strict)
3051 ret = (arg1->floatval > arg2->floatval);
3052 else if (!inf && !strict)
3053 ret = (arg1->floatval >= arg2->floatval);
3054 xmlXPathFreeObject(arg1);
3055 xmlXPathFreeObject(arg2);
3056 return(ret);
3057}
3058
3059/**
3060 * xmlXPathValueFlipSign:
3061 * @ctxt: the XPath Parser context
3062 *
3063 * Implement the unary - operation on an XPath object
3064 * The numeric operators convert their operands to numbers as if
3065 * by calling the number function.
3066 */
3067void
3068xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
3069 xmlXPathObjectPtr arg;
3070
3071 POP_FLOAT
3072 arg->floatval = -arg->floatval;
3073 valuePush(ctxt, arg);
3074}
3075
3076/**
3077 * xmlXPathAddValues:
3078 * @ctxt: the XPath Parser context
3079 *
3080 * Implement the add operation on XPath objects:
3081 * The numeric operators convert their operands to numbers as if
3082 * by calling the number function.
3083 */
3084void
3085xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3086 xmlXPathObjectPtr arg;
3087 double val;
3088
3089 POP_FLOAT
3090 val = arg->floatval;
3091 xmlXPathFreeObject(arg);
3092
3093 POP_FLOAT
3094 arg->floatval += val;
3095 valuePush(ctxt, arg);
3096}
3097
3098/**
3099 * xmlXPathSubValues:
3100 * @ctxt: the XPath Parser context
3101 *
3102 * Implement the substraction operation on XPath objects:
3103 * The numeric operators convert their operands to numbers as if
3104 * by calling the number function.
3105 */
3106void
3107xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3108 xmlXPathObjectPtr arg;
3109 double val;
3110
3111 POP_FLOAT
3112 val = arg->floatval;
3113 xmlXPathFreeObject(arg);
3114
3115 POP_FLOAT
3116 arg->floatval -= val;
3117 valuePush(ctxt, arg);
3118}
3119
3120/**
3121 * xmlXPathMultValues:
3122 * @ctxt: the XPath Parser context
3123 *
3124 * Implement the multiply operation on XPath objects:
3125 * The numeric operators convert their operands to numbers as if
3126 * by calling the number function.
3127 */
3128void
3129xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3130 xmlXPathObjectPtr arg;
3131 double val;
3132
3133 POP_FLOAT
3134 val = arg->floatval;
3135 xmlXPathFreeObject(arg);
3136
3137 POP_FLOAT
3138 arg->floatval *= val;
3139 valuePush(ctxt, arg);
3140}
3141
3142/**
3143 * xmlXPathDivValues:
3144 * @ctxt: the XPath Parser context
3145 *
3146 * Implement the div operation on XPath objects @arg1 / @arg2:
3147 * The numeric operators convert their operands to numbers as if
3148 * by calling the number function.
3149 */
3150void
3151xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3152 xmlXPathObjectPtr arg;
3153 double val;
3154
3155 POP_FLOAT
3156 val = arg->floatval;
3157 xmlXPathFreeObject(arg);
3158
3159 POP_FLOAT
3160 arg->floatval /= val;
3161 valuePush(ctxt, arg);
3162}
3163
3164/**
3165 * xmlXPathModValues:
3166 * @ctxt: the XPath Parser context
3167 *
3168 * Implement the mod operation on XPath objects: @arg1 / @arg2
3169 * The numeric operators convert their operands to numbers as if
3170 * by calling the number function.
3171 */
3172void
3173xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3174 xmlXPathObjectPtr arg;
3175 int arg1, arg2;
3176
3177 POP_FLOAT
3178 arg2 = (int) arg->floatval;
3179 xmlXPathFreeObject(arg);
3180
3181 POP_FLOAT
3182 arg1 = (int) arg->floatval;
3183 arg->floatval = arg1 % arg2;
3184 valuePush(ctxt, arg);
3185}
3186
3187/************************************************************************
3188 * *
3189 * The traversal functions *
3190 * *
3191 ************************************************************************/
3192
Owen Taylor3473f882001-02-23 17:55:21 +00003193/*
3194 * A traversal function enumerates nodes along an axis.
3195 * Initially it must be called with NULL, and it indicates
3196 * termination on the axis by returning NULL.
3197 */
3198typedef xmlNodePtr (*xmlXPathTraversalFunction)
3199 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3200
3201/**
3202 * xmlXPathNextSelf:
3203 * @ctxt: the XPath Parser context
3204 * @cur: the current node in the traversal
3205 *
3206 * Traversal function for the "self" direction
3207 * The self axis contains just the context node itself
3208 *
3209 * Returns the next element following that axis
3210 */
3211xmlNodePtr
3212xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3213 if (cur == NULL)
3214 return(ctxt->context->node);
3215 return(NULL);
3216}
3217
3218/**
3219 * xmlXPathNextChild:
3220 * @ctxt: the XPath Parser context
3221 * @cur: the current node in the traversal
3222 *
3223 * Traversal function for the "child" direction
3224 * The child axis contains the children of the context node in document order.
3225 *
3226 * Returns the next element following that axis
3227 */
3228xmlNodePtr
3229xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3230 if (cur == NULL) {
3231 if (ctxt->context->node == NULL) return(NULL);
3232 switch (ctxt->context->node->type) {
3233 case XML_ELEMENT_NODE:
3234 case XML_TEXT_NODE:
3235 case XML_CDATA_SECTION_NODE:
3236 case XML_ENTITY_REF_NODE:
3237 case XML_ENTITY_NODE:
3238 case XML_PI_NODE:
3239 case XML_COMMENT_NODE:
3240 case XML_NOTATION_NODE:
3241 case XML_DTD_NODE:
3242 return(ctxt->context->node->children);
3243 case XML_DOCUMENT_NODE:
3244 case XML_DOCUMENT_TYPE_NODE:
3245 case XML_DOCUMENT_FRAG_NODE:
3246 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003247#ifdef LIBXML_DOCB_ENABLED
3248 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003249#endif
3250 return(((xmlDocPtr) ctxt->context->node)->children);
3251 case XML_ELEMENT_DECL:
3252 case XML_ATTRIBUTE_DECL:
3253 case XML_ENTITY_DECL:
3254 case XML_ATTRIBUTE_NODE:
3255 case XML_NAMESPACE_DECL:
3256 case XML_XINCLUDE_START:
3257 case XML_XINCLUDE_END:
3258 return(NULL);
3259 }
3260 return(NULL);
3261 }
3262 if ((cur->type == XML_DOCUMENT_NODE) ||
3263 (cur->type == XML_HTML_DOCUMENT_NODE))
3264 return(NULL);
3265 return(cur->next);
3266}
3267
3268/**
3269 * xmlXPathNextDescendant:
3270 * @ctxt: the XPath Parser context
3271 * @cur: the current node in the traversal
3272 *
3273 * Traversal function for the "descendant" direction
3274 * the descendant axis contains the descendants of the context node in document
3275 * order; a descendant is a child or a child of a child and so on.
3276 *
3277 * Returns the next element following that axis
3278 */
3279xmlNodePtr
3280xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3281 if (cur == NULL) {
3282 if (ctxt->context->node == NULL)
3283 return(NULL);
3284 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3285 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3286 return(NULL);
3287
3288 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3289 return(ctxt->context->doc->children);
3290 return(ctxt->context->node->children);
3291 }
3292
3293 if (cur->children != NULL)
3294 {
3295 if (cur->children->type != XML_ENTITY_DECL)
3296 return(cur->children);
3297 }
3298 if (cur->next != NULL) return(cur->next);
3299
3300 do {
3301 cur = cur->parent;
3302 if (cur == NULL) return(NULL);
3303 if (cur == ctxt->context->node) return(NULL);
3304 if (cur->next != NULL) {
3305 cur = cur->next;
3306 return(cur);
3307 }
3308 } while (cur != NULL);
3309 return(cur);
3310}
3311
3312/**
3313 * xmlXPathNextDescendantOrSelf:
3314 * @ctxt: the XPath Parser context
3315 * @cur: the current node in the traversal
3316 *
3317 * Traversal function for the "descendant-or-self" direction
3318 * the descendant-or-self axis contains the context node and the descendants
3319 * of the context node in document order; thus the context node is the first
3320 * node on the axis, and the first child of the context node is the second node
3321 * on the axis
3322 *
3323 * Returns the next element following that axis
3324 */
3325xmlNodePtr
3326xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3327 if (cur == NULL) {
3328 if (ctxt->context->node == NULL)
3329 return(NULL);
3330 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3331 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3332 return(NULL);
3333 return(ctxt->context->node);
3334 }
3335
3336 return(xmlXPathNextDescendant(ctxt, cur));
3337}
3338
3339/**
3340 * xmlXPathNextParent:
3341 * @ctxt: the XPath Parser context
3342 * @cur: the current node in the traversal
3343 *
3344 * Traversal function for the "parent" direction
3345 * The parent axis contains the parent of the context node, if there is one.
3346 *
3347 * Returns the next element following that axis
3348 */
3349xmlNodePtr
3350xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3351 /*
3352 * the parent of an attribute or namespace node is the element
3353 * to which the attribute or namespace node is attached
3354 * Namespace handling !!!
3355 */
3356 if (cur == NULL) {
3357 if (ctxt->context->node == NULL) return(NULL);
3358 switch (ctxt->context->node->type) {
3359 case XML_ELEMENT_NODE:
3360 case XML_TEXT_NODE:
3361 case XML_CDATA_SECTION_NODE:
3362 case XML_ENTITY_REF_NODE:
3363 case XML_ENTITY_NODE:
3364 case XML_PI_NODE:
3365 case XML_COMMENT_NODE:
3366 case XML_NOTATION_NODE:
3367 case XML_DTD_NODE:
3368 case XML_ELEMENT_DECL:
3369 case XML_ATTRIBUTE_DECL:
3370 case XML_XINCLUDE_START:
3371 case XML_XINCLUDE_END:
3372 case XML_ENTITY_DECL:
3373 if (ctxt->context->node->parent == NULL)
3374 return((xmlNodePtr) ctxt->context->doc);
3375 return(ctxt->context->node->parent);
3376 case XML_ATTRIBUTE_NODE: {
3377 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3378
3379 return(att->parent);
3380 }
3381 case XML_DOCUMENT_NODE:
3382 case XML_DOCUMENT_TYPE_NODE:
3383 case XML_DOCUMENT_FRAG_NODE:
3384 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003385#ifdef LIBXML_DOCB_ENABLED
3386 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003387#endif
3388 return(NULL);
3389 case XML_NAMESPACE_DECL:
3390 /*
3391 * TODO !!! may require extending struct _xmlNs with
3392 * parent field
3393 * C.f. Infoset case...
3394 */
3395 return(NULL);
3396 }
3397 }
3398 return(NULL);
3399}
3400
3401/**
3402 * xmlXPathNextAncestor:
3403 * @ctxt: the XPath Parser context
3404 * @cur: the current node in the traversal
3405 *
3406 * Traversal function for the "ancestor" direction
3407 * the ancestor axis contains the ancestors of the context node; the ancestors
3408 * of the context node consist of the parent of context node and the parent's
3409 * parent and so on; the nodes are ordered in reverse document order; thus the
3410 * parent is the first node on the axis, and the parent's parent is the second
3411 * node on the axis
3412 *
3413 * Returns the next element following that axis
3414 */
3415xmlNodePtr
3416xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3417 /*
3418 * the parent of an attribute or namespace node is the element
3419 * to which the attribute or namespace node is attached
3420 * !!!!!!!!!!!!!
3421 */
3422 if (cur == NULL) {
3423 if (ctxt->context->node == NULL) return(NULL);
3424 switch (ctxt->context->node->type) {
3425 case XML_ELEMENT_NODE:
3426 case XML_TEXT_NODE:
3427 case XML_CDATA_SECTION_NODE:
3428 case XML_ENTITY_REF_NODE:
3429 case XML_ENTITY_NODE:
3430 case XML_PI_NODE:
3431 case XML_COMMENT_NODE:
3432 case XML_DTD_NODE:
3433 case XML_ELEMENT_DECL:
3434 case XML_ATTRIBUTE_DECL:
3435 case XML_ENTITY_DECL:
3436 case XML_NOTATION_NODE:
3437 case XML_XINCLUDE_START:
3438 case XML_XINCLUDE_END:
3439 if (ctxt->context->node->parent == NULL)
3440 return((xmlNodePtr) ctxt->context->doc);
3441 return(ctxt->context->node->parent);
3442 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003443 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00003444
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003445 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003446 }
3447 case XML_DOCUMENT_NODE:
3448 case XML_DOCUMENT_TYPE_NODE:
3449 case XML_DOCUMENT_FRAG_NODE:
3450 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003451#ifdef LIBXML_DOCB_ENABLED
3452 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003453#endif
3454 return(NULL);
3455 case XML_NAMESPACE_DECL:
3456 /*
3457 * TODO !!! may require extending struct _xmlNs with
3458 * parent field
3459 * C.f. Infoset case...
3460 */
3461 return(NULL);
3462 }
3463 return(NULL);
3464 }
3465 if (cur == ctxt->context->doc->children)
3466 return((xmlNodePtr) ctxt->context->doc);
3467 if (cur == (xmlNodePtr) ctxt->context->doc)
3468 return(NULL);
3469 switch (cur->type) {
3470 case XML_ELEMENT_NODE:
3471 case XML_TEXT_NODE:
3472 case XML_CDATA_SECTION_NODE:
3473 case XML_ENTITY_REF_NODE:
3474 case XML_ENTITY_NODE:
3475 case XML_PI_NODE:
3476 case XML_COMMENT_NODE:
3477 case XML_NOTATION_NODE:
3478 case XML_DTD_NODE:
3479 case XML_ELEMENT_DECL:
3480 case XML_ATTRIBUTE_DECL:
3481 case XML_ENTITY_DECL:
3482 case XML_XINCLUDE_START:
3483 case XML_XINCLUDE_END:
3484 return(cur->parent);
3485 case XML_ATTRIBUTE_NODE: {
3486 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3487
3488 return(att->parent);
3489 }
3490 case XML_DOCUMENT_NODE:
3491 case XML_DOCUMENT_TYPE_NODE:
3492 case XML_DOCUMENT_FRAG_NODE:
3493 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003494#ifdef LIBXML_DOCB_ENABLED
3495 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003496#endif
3497 return(NULL);
3498 case XML_NAMESPACE_DECL:
3499 /*
3500 * TODO !!! may require extending struct _xmlNs with
3501 * parent field
3502 * C.f. Infoset case...
3503 */
3504 return(NULL);
3505 }
3506 return(NULL);
3507}
3508
3509/**
3510 * xmlXPathNextAncestorOrSelf:
3511 * @ctxt: the XPath Parser context
3512 * @cur: the current node in the traversal
3513 *
3514 * Traversal function for the "ancestor-or-self" direction
3515 * he ancestor-or-self axis contains the context node and ancestors of
3516 * the context node in reverse document order; thus the context node is
3517 * the first node on the axis, and the context node's parent the second;
3518 * parent here is defined the same as with the parent axis.
3519 *
3520 * Returns the next element following that axis
3521 */
3522xmlNodePtr
3523xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3524 if (cur == NULL)
3525 return(ctxt->context->node);
3526 return(xmlXPathNextAncestor(ctxt, cur));
3527}
3528
3529/**
3530 * xmlXPathNextFollowingSibling:
3531 * @ctxt: the XPath Parser context
3532 * @cur: the current node in the traversal
3533 *
3534 * Traversal function for the "following-sibling" direction
3535 * The following-sibling axis contains the following siblings of the context
3536 * node in document order.
3537 *
3538 * Returns the next element following that axis
3539 */
3540xmlNodePtr
3541xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3542 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3543 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3544 return(NULL);
3545 if (cur == (xmlNodePtr) ctxt->context->doc)
3546 return(NULL);
3547 if (cur == NULL)
3548 return(ctxt->context->node->next);
3549 return(cur->next);
3550}
3551
3552/**
3553 * xmlXPathNextPrecedingSibling:
3554 * @ctxt: the XPath Parser context
3555 * @cur: the current node in the traversal
3556 *
3557 * Traversal function for the "preceding-sibling" direction
3558 * The preceding-sibling axis contains the preceding siblings of the context
3559 * node in reverse document order; the first preceding sibling is first on the
3560 * axis; the sibling preceding that node is the second on the axis and so on.
3561 *
3562 * Returns the next element following that axis
3563 */
3564xmlNodePtr
3565xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3566 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3567 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3568 return(NULL);
3569 if (cur == (xmlNodePtr) ctxt->context->doc)
3570 return(NULL);
3571 if (cur == NULL)
3572 return(ctxt->context->node->prev);
3573 return(cur->prev);
3574}
3575
3576/**
3577 * xmlXPathNextFollowing:
3578 * @ctxt: the XPath Parser context
3579 * @cur: the current node in the traversal
3580 *
3581 * Traversal function for the "following" direction
3582 * The following axis contains all nodes in the same document as the context
3583 * node that are after the context node in document order, excluding any
3584 * descendants and excluding attribute nodes and namespace nodes; the nodes
3585 * are ordered in document order
3586 *
3587 * Returns the next element following that axis
3588 */
3589xmlNodePtr
3590xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3591 if (cur != NULL && cur->children != NULL)
3592 return cur->children ;
3593 if (cur == NULL) cur = ctxt->context->node;
3594 if (cur == NULL) return(NULL) ; /* ERROR */
3595 if (cur->next != NULL) return(cur->next) ;
3596 do {
3597 cur = cur->parent;
3598 if (cur == NULL) return(NULL);
3599 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
3600 if (cur->next != NULL) return(cur->next);
3601 } while (cur != NULL);
3602 return(cur);
3603}
3604
3605/*
3606 * xmlXPathIsAncestor:
3607 * @ancestor: the ancestor node
3608 * @node: the current node
3609 *
3610 * Check that @ancestor is a @node's ancestor
3611 *
3612 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
3613 */
3614static int
3615xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
3616 if ((ancestor == NULL) || (node == NULL)) return(0);
3617 /* nodes need to be in the same document */
3618 if (ancestor->doc != node->doc) return(0);
3619 /* avoid searching if ancestor or node is the root node */
3620 if (ancestor == (xmlNodePtr) node->doc) return(1);
3621 if (node == (xmlNodePtr) ancestor->doc) return(0);
3622 while (node->parent != NULL) {
3623 if (node->parent == ancestor)
3624 return(1);
3625 node = node->parent;
3626 }
3627 return(0);
3628}
3629
3630/**
3631 * xmlXPathNextPreceding:
3632 * @ctxt: the XPath Parser context
3633 * @cur: the current node in the traversal
3634 *
3635 * Traversal function for the "preceding" direction
3636 * the preceding axis contains all nodes in the same document as the context
3637 * node that are before the context node in document order, excluding any
3638 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
3639 * ordered in reverse document order
3640 *
3641 * Returns the next element following that axis
3642 */
3643xmlNodePtr
3644xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3645 if (cur == NULL)
3646 cur = ctxt->context->node ;
3647 do {
3648 if (cur->prev != NULL) {
3649 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
3650 ;
3651 return(cur) ;
3652 }
3653
3654 cur = cur->parent;
3655 if (cur == NULL) return(NULL);
3656 if (cur == ctxt->context->doc->children) return(NULL);
3657 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
3658 return(cur);
3659}
3660
3661/**
3662 * xmlXPathNextNamespace:
3663 * @ctxt: the XPath Parser context
3664 * @cur: the current attribute in the traversal
3665 *
3666 * Traversal function for the "namespace" direction
3667 * the namespace axis contains the namespace nodes of the context node;
3668 * the order of nodes on this axis is implementation-defined; the axis will
3669 * be empty unless the context node is an element
3670 *
3671 * Returns the next element following that axis
3672 */
3673xmlNodePtr
3674xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3675 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3676 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
3677 if (ctxt->context->namespaces != NULL)
3678 xmlFree(ctxt->context->namespaces);
3679 ctxt->context->namespaces =
3680 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
3681 if (ctxt->context->namespaces == NULL) return(NULL);
3682 ctxt->context->nsNr = 0;
3683 }
3684 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
3685}
3686
3687/**
3688 * xmlXPathNextAttribute:
3689 * @ctxt: the XPath Parser context
3690 * @cur: the current attribute in the traversal
3691 *
3692 * Traversal function for the "attribute" direction
3693 * TODO: support DTD inherited default attributes
3694 *
3695 * Returns the next element following that axis
3696 */
3697xmlNodePtr
3698xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00003699 if (ctxt->context->node == NULL)
3700 return(NULL);
3701 if (ctxt->context->node->type != XML_ELEMENT_NODE)
3702 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003703 if (cur == NULL) {
3704 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3705 return(NULL);
3706 return((xmlNodePtr)ctxt->context->node->properties);
3707 }
3708 return((xmlNodePtr)cur->next);
3709}
3710
3711/************************************************************************
3712 * *
3713 * NodeTest Functions *
3714 * *
3715 ************************************************************************/
3716
Owen Taylor3473f882001-02-23 17:55:21 +00003717#define IS_FUNCTION 200
3718
Owen Taylor3473f882001-02-23 17:55:21 +00003719
3720/************************************************************************
3721 * *
3722 * Implicit tree core function library *
3723 * *
3724 ************************************************************************/
3725
3726/**
3727 * xmlXPathRoot:
3728 * @ctxt: the XPath Parser context
3729 *
3730 * Initialize the context to the root of the document
3731 */
3732void
3733xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
3734 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
3735 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3736}
3737
3738/************************************************************************
3739 * *
3740 * The explicit core function library *
3741 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
3742 * *
3743 ************************************************************************/
3744
3745
3746/**
3747 * xmlXPathLastFunction:
3748 * @ctxt: the XPath Parser context
3749 * @nargs: the number of arguments
3750 *
3751 * Implement the last() XPath function
3752 * number last()
3753 * The last function returns the number of nodes in the context node list.
3754 */
3755void
3756xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3757 CHECK_ARITY(0);
3758 if (ctxt->context->contextSize >= 0) {
3759 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
3760#ifdef DEBUG_EXPR
3761 xmlGenericError(xmlGenericErrorContext,
3762 "last() : %d\n", ctxt->context->contextSize);
3763#endif
3764 } else {
3765 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
3766 }
3767}
3768
3769/**
3770 * xmlXPathPositionFunction:
3771 * @ctxt: the XPath Parser context
3772 * @nargs: the number of arguments
3773 *
3774 * Implement the position() XPath function
3775 * number position()
3776 * The position function returns the position of the context node in the
3777 * context node list. The first position is 1, and so the last positionr
3778 * will be equal to last().
3779 */
3780void
3781xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3782 CHECK_ARITY(0);
3783 if (ctxt->context->proximityPosition >= 0) {
3784 valuePush(ctxt,
3785 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
3786#ifdef DEBUG_EXPR
3787 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
3788 ctxt->context->proximityPosition);
3789#endif
3790 } else {
3791 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
3792 }
3793}
3794
3795/**
3796 * xmlXPathCountFunction:
3797 * @ctxt: the XPath Parser context
3798 * @nargs: the number of arguments
3799 *
3800 * Implement the count() XPath function
3801 * number count(node-set)
3802 */
3803void
3804xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3805 xmlXPathObjectPtr cur;
3806
3807 CHECK_ARITY(1);
3808 if ((ctxt->value == NULL) ||
3809 ((ctxt->value->type != XPATH_NODESET) &&
3810 (ctxt->value->type != XPATH_XSLT_TREE)))
3811 XP_ERROR(XPATH_INVALID_TYPE);
3812 cur = valuePop(ctxt);
3813
Daniel Veillard911f49a2001-04-07 15:39:35 +00003814 if ((cur == NULL) || (cur->nodesetval == NULL))
3815 valuePush(ctxt, xmlXPathNewFloat((double) 0));
3816 else
3817 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00003818 xmlXPathFreeObject(cur);
3819}
3820
3821/**
3822 * xmlXPathIdFunction:
3823 * @ctxt: the XPath Parser context
3824 * @nargs: the number of arguments
3825 *
3826 * Implement the id() XPath function
3827 * node-set id(object)
3828 * The id function selects elements by their unique ID
3829 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
3830 * then the result is the union of the result of applying id to the
3831 * string value of each of the nodes in the argument node-set. When the
3832 * argument to id is of any other type, the argument is converted to a
3833 * string as if by a call to the string function; the string is split
3834 * into a whitespace-separated list of tokens (whitespace is any sequence
3835 * of characters matching the production S); the result is a node-set
3836 * containing the elements in the same document as the context node that
3837 * have a unique ID equal to any of the tokens in the list.
3838 */
3839void
3840xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3841 const xmlChar *tokens;
3842 const xmlChar *cur;
3843 xmlChar *ID;
3844 xmlAttrPtr attr;
3845 xmlNodePtr elem = NULL;
3846 xmlXPathObjectPtr ret, obj;
3847
3848 CHECK_ARITY(1);
3849 obj = valuePop(ctxt);
3850 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3851 if (obj->type == XPATH_NODESET) {
3852 xmlXPathObjectPtr newobj;
3853 int i;
3854
3855 ret = xmlXPathNewNodeSet(NULL);
3856
Daniel Veillard911f49a2001-04-07 15:39:35 +00003857 if (obj->nodesetval != NULL) {
3858 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
3859 valuePush(ctxt,
3860 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
3861 xmlXPathStringFunction(ctxt, 1);
3862 xmlXPathIdFunction(ctxt, 1);
3863 newobj = valuePop(ctxt);
3864 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
3865 newobj->nodesetval);
3866 xmlXPathFreeObject(newobj);
3867 }
Owen Taylor3473f882001-02-23 17:55:21 +00003868 }
3869
3870 xmlXPathFreeObject(obj);
3871 valuePush(ctxt, ret);
3872 return;
3873 }
3874 if (obj->type != XPATH_STRING) {
3875 valuePush(ctxt, obj);
3876 xmlXPathStringFunction(ctxt, 1);
3877 obj = valuePop(ctxt);
3878 if (obj->type != XPATH_STRING) {
3879 xmlXPathFreeObject(obj);
3880 return;
3881 }
3882 }
3883 tokens = obj->stringval;
3884
3885 ret = xmlXPathNewNodeSet(NULL);
3886 valuePush(ctxt, ret);
3887 if (tokens == NULL) {
3888 xmlXPathFreeObject(obj);
3889 return;
3890 }
3891
3892 cur = tokens;
3893
3894 while (IS_BLANK(*cur)) cur++;
3895 while (*cur != 0) {
3896 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
3897 (*cur == '.') || (*cur == '-') ||
3898 (*cur == '_') || (*cur == ':') ||
3899 (IS_COMBINING(*cur)) ||
3900 (IS_EXTENDER(*cur)))
3901 cur++;
3902
3903 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
3904
3905 ID = xmlStrndup(tokens, cur - tokens);
3906 attr = xmlGetID(ctxt->context->doc, ID);
3907 if (attr != NULL) {
3908 elem = attr->parent;
3909 xmlXPathNodeSetAdd(ret->nodesetval, elem);
3910 }
3911 if (ID != NULL)
3912 xmlFree(ID);
3913
3914 while (IS_BLANK(*cur)) cur++;
3915 tokens = cur;
3916 }
3917 xmlXPathFreeObject(obj);
3918 return;
3919}
3920
3921/**
3922 * xmlXPathLocalNameFunction:
3923 * @ctxt: the XPath Parser context
3924 * @nargs: the number of arguments
3925 *
3926 * Implement the local-name() XPath function
3927 * string local-name(node-set?)
3928 * The local-name function returns a string containing the local part
3929 * of the name of the node in the argument node-set that is first in
3930 * document order. If the node-set is empty or the first node has no
3931 * name, an empty string is returned. If the argument is omitted it
3932 * defaults to the context node.
3933 */
3934void
3935xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3936 xmlXPathObjectPtr cur;
3937
3938 if (nargs == 0) {
3939 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3940 nargs = 1;
3941 }
3942
3943 CHECK_ARITY(1);
3944 if ((ctxt->value == NULL) ||
3945 ((ctxt->value->type != XPATH_NODESET) &&
3946 (ctxt->value->type != XPATH_XSLT_TREE)))
3947 XP_ERROR(XPATH_INVALID_TYPE);
3948 cur = valuePop(ctxt);
3949
Daniel Veillard911f49a2001-04-07 15:39:35 +00003950 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003951 valuePush(ctxt, xmlXPathNewCString(""));
3952 } else {
3953 int i = 0; /* Should be first in document order !!!!! */
3954 switch (cur->nodesetval->nodeTab[i]->type) {
3955 case XML_ELEMENT_NODE:
3956 case XML_ATTRIBUTE_NODE:
3957 case XML_PI_NODE:
3958 valuePush(ctxt,
3959 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
3960 break;
3961 case XML_NAMESPACE_DECL:
3962 valuePush(ctxt, xmlXPathNewString(
3963 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
3964 break;
3965 default:
3966 valuePush(ctxt, xmlXPathNewCString(""));
3967 }
3968 }
3969 xmlXPathFreeObject(cur);
3970}
3971
3972/**
3973 * xmlXPathNamespaceURIFunction:
3974 * @ctxt: the XPath Parser context
3975 * @nargs: the number of arguments
3976 *
3977 * Implement the namespace-uri() XPath function
3978 * string namespace-uri(node-set?)
3979 * The namespace-uri function returns a string containing the
3980 * namespace URI of the expanded name of the node in the argument
3981 * node-set that is first in document order. If the node-set is empty,
3982 * the first node has no name, or the expanded name has no namespace
3983 * URI, an empty string is returned. If the argument is omitted it
3984 * defaults to the context node.
3985 */
3986void
3987xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3988 xmlXPathObjectPtr cur;
3989
3990 if (nargs == 0) {
3991 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3992 nargs = 1;
3993 }
3994 CHECK_ARITY(1);
3995 if ((ctxt->value == NULL) ||
3996 ((ctxt->value->type != XPATH_NODESET) &&
3997 (ctxt->value->type != XPATH_XSLT_TREE)))
3998 XP_ERROR(XPATH_INVALID_TYPE);
3999 cur = valuePop(ctxt);
4000
Daniel Veillard911f49a2001-04-07 15:39:35 +00004001 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004002 valuePush(ctxt, xmlXPathNewCString(""));
4003 } else {
4004 int i = 0; /* Should be first in document order !!!!! */
4005 switch (cur->nodesetval->nodeTab[i]->type) {
4006 case XML_ELEMENT_NODE:
4007 case XML_ATTRIBUTE_NODE:
4008 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4009 valuePush(ctxt, xmlXPathNewCString(""));
4010 else
4011 valuePush(ctxt, xmlXPathNewString(
4012 cur->nodesetval->nodeTab[i]->ns->href));
4013 break;
4014 default:
4015 valuePush(ctxt, xmlXPathNewCString(""));
4016 }
4017 }
4018 xmlXPathFreeObject(cur);
4019}
4020
4021/**
4022 * xmlXPathNameFunction:
4023 * @ctxt: the XPath Parser context
4024 * @nargs: the number of arguments
4025 *
4026 * Implement the name() XPath function
4027 * string name(node-set?)
4028 * The name function returns a string containing a QName representing
4029 * the name of the node in the argument node-set that is first in documenti
4030 * order. The QName must represent the name with respect to the namespace
4031 * declarations in effect on the node whose name is being represented.
4032 * Typically, this will be the form in which the name occurred in the XML
4033 * source. This need not be the case if there are namespace declarations
4034 * in effect on the node that associate multiple prefixes with the same
4035 * namespace. However, an implementation may include information about
4036 * the original prefix in its representation of nodes; in this case, an
4037 * implementation can ensure that the returned string is always the same
4038 * as the QName used in the XML source. If the argument it omitted it
4039 * defaults to the context node.
4040 * Libxml keep the original prefix so the "real qualified name" used is
4041 * returned.
4042 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004043static void
Owen Taylor3473f882001-02-23 17:55:21 +00004044xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4045 xmlXPathObjectPtr cur;
4046
4047 if (nargs == 0) {
4048 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4049 nargs = 1;
4050 }
4051
4052 CHECK_ARITY(1);
4053 if ((ctxt->value == NULL) ||
4054 ((ctxt->value->type != XPATH_NODESET) &&
4055 (ctxt->value->type != XPATH_XSLT_TREE)))
4056 XP_ERROR(XPATH_INVALID_TYPE);
4057 cur = valuePop(ctxt);
4058
Daniel Veillard911f49a2001-04-07 15:39:35 +00004059 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004060 valuePush(ctxt, xmlXPathNewCString(""));
4061 } else {
4062 int i = 0; /* Should be first in document order !!!!! */
4063
4064 switch (cur->nodesetval->nodeTab[i]->type) {
4065 case XML_ELEMENT_NODE:
4066 case XML_ATTRIBUTE_NODE:
4067 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4068 valuePush(ctxt, xmlXPathNewString(
4069 cur->nodesetval->nodeTab[i]->name));
4070
4071 else {
4072 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004073 snprintf(name, sizeof(name), "%s:%s",
4074 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4075 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 name[sizeof(name) - 1] = 0;
4077 valuePush(ctxt, xmlXPathNewCString(name));
4078 }
4079 break;
4080 default:
4081 valuePush(ctxt,
4082 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4083 xmlXPathLocalNameFunction(ctxt, 1);
4084 }
4085 }
4086 xmlXPathFreeObject(cur);
4087}
4088
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004089
4090/**
4091 * xmlXPathConvertString:
4092 * @val: an XPath object
4093 *
4094 * Converts an existing object to its string() equivalent
4095 *
4096 * Returns the new object, the old one is freed (or the operation
4097 * is done directly on @val)
4098 */
4099xmlXPathObjectPtr
4100xmlXPathConvertString(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004101 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004102
4103 if (val == NULL)
4104 return(xmlXPathNewCString(""));
4105 switch (val->type) {
4106 case XPATH_UNDEFINED:
4107#ifdef DEBUG_EXPR
4108 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
4109#endif
4110 ret = xmlXPathNewCString("");
4111 break;
4112 case XPATH_XSLT_TREE:
4113 case XPATH_NODESET:
Daniel Veillard911f49a2001-04-07 15:39:35 +00004114 if ((val->nodesetval == NULL) || (val->nodesetval->nodeNr == 0)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004115 ret = xmlXPathNewCString("");
4116 } else {
4117 xmlChar *res;
4118
4119 xmlXPathNodeSetSort(val->nodesetval);
4120 res = xmlNodeGetContent(val->nodesetval->nodeTab[0]);
4121 /* TODO: avoid allocating res to free it */
4122 ret = xmlXPathNewString(res);
4123 if (res != NULL)
4124 xmlFree(res);
4125 }
4126 break;
4127 case XPATH_STRING:
4128 return(val);
4129 case XPATH_BOOLEAN:
4130 if (val->boolval) ret = xmlXPathNewCString("true");
4131 else ret = xmlXPathNewCString("false");
4132 break;
4133 case XPATH_NUMBER: {
4134 char buf[100];
4135
4136 xmlXPathFormatNumber(val->floatval, buf, sizeof(buf));
4137 ret = xmlXPathNewCString(buf);
4138 break;
4139 }
4140 case XPATH_USERS:
4141 case XPATH_POINT:
4142 case XPATH_RANGE:
4143 case XPATH_LOCATIONSET:
4144 TODO
4145 ret = xmlXPathNewCString("");
4146 break;
4147 }
4148 xmlXPathFreeObject(val);
4149 return(ret);
4150}
4151
Owen Taylor3473f882001-02-23 17:55:21 +00004152/**
4153 * xmlXPathStringFunction:
4154 * @ctxt: the XPath Parser context
4155 * @nargs: the number of arguments
4156 *
4157 * Implement the string() XPath function
4158 * string string(object?)
4159 * he string function converts an object to a string as follows:
4160 * - A node-set is converted to a string by returning the value of
4161 * the node in the node-set that is first in document order.
4162 * If the node-set is empty, an empty string is returned.
4163 * - A number is converted to a string as follows
4164 * + NaN is converted to the string NaN
4165 * + positive zero is converted to the string 0
4166 * + negative zero is converted to the string 0
4167 * + positive infinity is converted to the string Infinity
4168 * + negative infinity is converted to the string -Infinity
4169 * + if the number is an integer, the number is represented in
4170 * decimal form as a Number with no decimal point and no leading
4171 * zeros, preceded by a minus sign (-) if the number is negative
4172 * + otherwise, the number is represented in decimal form as a
4173 * Number including a decimal point with at least one digit
4174 * before the decimal point and at least one digit after the
4175 * decimal point, preceded by a minus sign (-) if the number
4176 * is negative; there must be no leading zeros before the decimal
4177 * point apart possibly from the one required digit immediatelyi
4178 * before the decimal point; beyond the one required digit
4179 * after the decimal point there must be as many, but only as
4180 * many, more digits as are needed to uniquely distinguish the
4181 * number from all other IEEE 754 numeric values.
4182 * - The boolean false value is converted to the string false.
4183 * The boolean true value is converted to the string true.
4184 *
4185 * If the argument is omitted, it defaults to a node-set with the
4186 * context node as its only member.
4187 */
4188void
4189xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4190 xmlXPathObjectPtr cur;
4191
4192 if (nargs == 0) {
4193 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4194 nargs = 1;
4195 }
4196
4197 CHECK_ARITY(1);
4198 cur = valuePop(ctxt);
4199 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004200 cur = xmlXPathConvertString(cur);
4201 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004202}
4203
4204/**
4205 * xmlXPathStringLengthFunction:
4206 * @ctxt: the XPath Parser context
4207 * @nargs: the number of arguments
4208 *
4209 * Implement the string-length() XPath function
4210 * number string-length(string?)
4211 * The string-length returns the number of characters in the string
4212 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4213 * the context node converted to a string, in other words the value
4214 * of the context node.
4215 */
4216void
4217xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4218 xmlXPathObjectPtr cur;
4219
4220 if (nargs == 0) {
4221 if (ctxt->context->node == NULL) {
4222 valuePush(ctxt, xmlXPathNewFloat(0));
4223 } else {
4224 xmlChar *content;
4225
4226 content = xmlNodeGetContent(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004227 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004228 xmlFree(content);
4229 }
4230 return;
4231 }
4232 CHECK_ARITY(1);
4233 CAST_TO_STRING;
4234 CHECK_TYPE(XPATH_STRING);
4235 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004236 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004237 xmlXPathFreeObject(cur);
4238}
4239
4240/**
4241 * xmlXPathConcatFunction:
4242 * @ctxt: the XPath Parser context
4243 * @nargs: the number of arguments
4244 *
4245 * Implement the concat() XPath function
4246 * string concat(string, string, string*)
4247 * The concat function returns the concatenation of its arguments.
4248 */
4249void
4250xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4251 xmlXPathObjectPtr cur, newobj;
4252 xmlChar *tmp;
4253
4254 if (nargs < 2) {
4255 CHECK_ARITY(2);
4256 }
4257
4258 CAST_TO_STRING;
4259 cur = valuePop(ctxt);
4260 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4261 xmlXPathFreeObject(cur);
4262 return;
4263 }
4264 nargs--;
4265
4266 while (nargs > 0) {
4267 CAST_TO_STRING;
4268 newobj = valuePop(ctxt);
4269 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4270 xmlXPathFreeObject(newobj);
4271 xmlXPathFreeObject(cur);
4272 XP_ERROR(XPATH_INVALID_TYPE);
4273 }
4274 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4275 newobj->stringval = cur->stringval;
4276 cur->stringval = tmp;
4277
4278 xmlXPathFreeObject(newobj);
4279 nargs--;
4280 }
4281 valuePush(ctxt, cur);
4282}
4283
4284/**
4285 * xmlXPathContainsFunction:
4286 * @ctxt: the XPath Parser context
4287 * @nargs: the number of arguments
4288 *
4289 * Implement the contains() XPath function
4290 * boolean contains(string, string)
4291 * The contains function returns true if the first argument string
4292 * contains the second argument string, and otherwise returns false.
4293 */
4294void
4295xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4296 xmlXPathObjectPtr hay, needle;
4297
4298 CHECK_ARITY(2);
4299 CAST_TO_STRING;
4300 CHECK_TYPE(XPATH_STRING);
4301 needle = valuePop(ctxt);
4302 CAST_TO_STRING;
4303 hay = valuePop(ctxt);
4304 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4305 xmlXPathFreeObject(hay);
4306 xmlXPathFreeObject(needle);
4307 XP_ERROR(XPATH_INVALID_TYPE);
4308 }
4309 if (xmlStrstr(hay->stringval, needle->stringval))
4310 valuePush(ctxt, xmlXPathNewBoolean(1));
4311 else
4312 valuePush(ctxt, xmlXPathNewBoolean(0));
4313 xmlXPathFreeObject(hay);
4314 xmlXPathFreeObject(needle);
4315}
4316
4317/**
4318 * xmlXPathStartsWithFunction:
4319 * @ctxt: the XPath Parser context
4320 * @nargs: the number of arguments
4321 *
4322 * Implement the starts-with() XPath function
4323 * boolean starts-with(string, string)
4324 * The starts-with function returns true if the first argument string
4325 * starts with the second argument string, and otherwise returns false.
4326 */
4327void
4328xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4329 xmlXPathObjectPtr hay, needle;
4330 int n;
4331
4332 CHECK_ARITY(2);
4333 CAST_TO_STRING;
4334 CHECK_TYPE(XPATH_STRING);
4335 needle = valuePop(ctxt);
4336 CAST_TO_STRING;
4337 hay = valuePop(ctxt);
4338 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4339 xmlXPathFreeObject(hay);
4340 xmlXPathFreeObject(needle);
4341 XP_ERROR(XPATH_INVALID_TYPE);
4342 }
4343 n = xmlStrlen(needle->stringval);
4344 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4345 valuePush(ctxt, xmlXPathNewBoolean(0));
4346 else
4347 valuePush(ctxt, xmlXPathNewBoolean(1));
4348 xmlXPathFreeObject(hay);
4349 xmlXPathFreeObject(needle);
4350}
4351
4352/**
4353 * xmlXPathSubstringFunction:
4354 * @ctxt: the XPath Parser context
4355 * @nargs: the number of arguments
4356 *
4357 * Implement the substring() XPath function
4358 * string substring(string, number, number?)
4359 * The substring function returns the substring of the first argument
4360 * starting at the position specified in the second argument with
4361 * length specified in the third argument. For example,
4362 * substring("12345",2,3) returns "234". If the third argument is not
4363 * specified, it returns the substring starting at the position specified
4364 * in the second argument and continuing to the end of the string. For
4365 * example, substring("12345",2) returns "2345". More precisely, each
4366 * character in the string (see [3.6 Strings]) is considered to have a
4367 * numeric position: the position of the first character is 1, the position
4368 * of the second character is 2 and so on. The returned substring contains
4369 * those characters for which the position of the character is greater than
4370 * or equal to the second argument and, if the third argument is specified,
4371 * less than the sum of the second and third arguments; the comparisons
4372 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4373 * - substring("12345", 1.5, 2.6) returns "234"
4374 * - substring("12345", 0, 3) returns "12"
4375 * - substring("12345", 0 div 0, 3) returns ""
4376 * - substring("12345", 1, 0 div 0) returns ""
4377 * - substring("12345", -42, 1 div 0) returns "12345"
4378 * - substring("12345", -1 div 0, 1 div 0) returns ""
4379 */
4380void
4381xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4382 xmlXPathObjectPtr str, start, len;
4383 double le, in;
4384 int i, l;
4385 xmlChar *ret;
4386
4387 /*
Daniel Veillarde043ee12001-04-16 14:08:07 +00004388 * TODO: need to be converted to UTF8 strings
Owen Taylor3473f882001-02-23 17:55:21 +00004389 */
4390 if (nargs < 2) {
4391 CHECK_ARITY(2);
4392 }
4393 if (nargs > 3) {
4394 CHECK_ARITY(3);
4395 }
4396 if (nargs == 3) {
4397 CAST_TO_NUMBER;
4398 CHECK_TYPE(XPATH_NUMBER);
4399 len = valuePop(ctxt);
4400 le = len->floatval;
4401 xmlXPathFreeObject(len);
4402 } else {
4403 le = 2000000000;
4404 }
4405 CAST_TO_NUMBER;
4406 CHECK_TYPE(XPATH_NUMBER);
4407 start = valuePop(ctxt);
4408 in = start->floatval;
4409 xmlXPathFreeObject(start);
4410 CAST_TO_STRING;
4411 CHECK_TYPE(XPATH_STRING);
4412 str = valuePop(ctxt);
4413 le += in;
4414
4415 /* integer index of the first char */
4416 i = (int) in;
4417 if (((double)i) != in) i++;
4418
4419 /* integer index of the last char */
4420 l = (int) le;
4421 if (((double)l) != le) l++;
4422
4423 /* back to a zero based len */
4424 i--;
4425 l--;
4426
4427 /* check against the string len */
4428 if (l > 1024) {
4429 l = xmlStrlen(str->stringval);
4430 }
4431 if (i < 0) {
4432 i = 0;
4433 }
4434
4435 /* number of chars to copy */
4436 l -= i;
4437
4438 ret = xmlStrsub(str->stringval, i, l);
4439 if (ret == NULL)
4440 valuePush(ctxt, xmlXPathNewCString(""));
4441 else {
4442 valuePush(ctxt, xmlXPathNewString(ret));
4443 xmlFree(ret);
4444 }
4445 xmlXPathFreeObject(str);
4446}
4447
4448/**
4449 * xmlXPathSubstringBeforeFunction:
4450 * @ctxt: the XPath Parser context
4451 * @nargs: the number of arguments
4452 *
4453 * Implement the substring-before() XPath function
4454 * string substring-before(string, string)
4455 * The substring-before function returns the substring of the first
4456 * argument string that precedes the first occurrence of the second
4457 * argument string in the first argument string, or the empty string
4458 * if the first argument string does not contain the second argument
4459 * string. For example, substring-before("1999/04/01","/") returns 1999.
4460 */
4461void
4462xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4463 xmlXPathObjectPtr str;
4464 xmlXPathObjectPtr find;
4465 xmlBufferPtr target;
4466 const xmlChar *point;
4467 int offset;
4468
4469 CHECK_ARITY(2);
4470 CAST_TO_STRING;
4471 find = valuePop(ctxt);
4472 CAST_TO_STRING;
4473 str = valuePop(ctxt);
4474
4475 target = xmlBufferCreate();
4476 if (target) {
4477 point = xmlStrstr(str->stringval, find->stringval);
4478 if (point) {
4479 offset = (int)(point - str->stringval);
4480 xmlBufferAdd(target, str->stringval, offset);
4481 }
4482 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4483 xmlBufferFree(target);
4484 }
4485
4486 xmlXPathFreeObject(str);
4487 xmlXPathFreeObject(find);
4488}
4489
4490/**
4491 * xmlXPathSubstringAfterFunction:
4492 * @ctxt: the XPath Parser context
4493 * @nargs: the number of arguments
4494 *
4495 * Implement the substring-after() XPath function
4496 * string substring-after(string, string)
4497 * The substring-after function returns the substring of the first
4498 * argument string that follows the first occurrence of the second
4499 * argument string in the first argument string, or the empty stringi
4500 * if the first argument string does not contain the second argument
4501 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4502 * and substring-after("1999/04/01","19") returns 99/04/01.
4503 */
4504void
4505xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4506 xmlXPathObjectPtr str;
4507 xmlXPathObjectPtr find;
4508 xmlBufferPtr target;
4509 const xmlChar *point;
4510 int offset;
4511
4512 CHECK_ARITY(2);
4513 CAST_TO_STRING;
4514 find = valuePop(ctxt);
4515 CAST_TO_STRING;
4516 str = valuePop(ctxt);
4517
4518 target = xmlBufferCreate();
4519 if (target) {
4520 point = xmlStrstr(str->stringval, find->stringval);
4521 if (point) {
4522 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4523 xmlBufferAdd(target, &str->stringval[offset],
4524 xmlStrlen(str->stringval) - offset);
4525 }
4526 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4527 xmlBufferFree(target);
4528 }
4529
4530 xmlXPathFreeObject(str);
4531 xmlXPathFreeObject(find);
4532}
4533
4534/**
4535 * xmlXPathNormalizeFunction:
4536 * @ctxt: the XPath Parser context
4537 * @nargs: the number of arguments
4538 *
4539 * Implement the normalize-space() XPath function
4540 * string normalize-space(string?)
4541 * The normalize-space function returns the argument string with white
4542 * space normalized by stripping leading and trailing whitespace
4543 * and replacing sequences of whitespace characters by a single
4544 * space. Whitespace characters are the same allowed by the S production
4545 * in XML. If the argument is omitted, it defaults to the context
4546 * node converted to a string, in other words the value of the context node.
4547 */
4548void
4549xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4550 xmlXPathObjectPtr obj = NULL;
4551 xmlChar *source = NULL;
4552 xmlBufferPtr target;
4553 xmlChar blank;
4554
4555 if (nargs == 0) {
4556 /* Use current context node */
4557 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4558 xmlXPathStringFunction(ctxt, 1);
4559 nargs = 1;
4560 }
4561
4562 CHECK_ARITY(1);
4563 CAST_TO_STRING;
4564 CHECK_TYPE(XPATH_STRING);
4565 obj = valuePop(ctxt);
4566 source = obj->stringval;
4567
4568 target = xmlBufferCreate();
4569 if (target && source) {
4570
4571 /* Skip leading whitespaces */
4572 while (IS_BLANK(*source))
4573 source++;
4574
4575 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4576 blank = 0;
4577 while (*source) {
4578 if (IS_BLANK(*source)) {
4579 blank = *source;
4580 } else {
4581 if (blank) {
4582 xmlBufferAdd(target, &blank, 1);
4583 blank = 0;
4584 }
4585 xmlBufferAdd(target, source, 1);
4586 }
4587 source++;
4588 }
4589
4590 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4591 xmlBufferFree(target);
4592 }
4593 xmlXPathFreeObject(obj);
4594}
4595
4596/**
4597 * xmlXPathTranslateFunction:
4598 * @ctxt: the XPath Parser context
4599 * @nargs: the number of arguments
4600 *
4601 * Implement the translate() XPath function
4602 * string translate(string, string, string)
4603 * The translate function returns the first argument string with
4604 * occurrences of characters in the second argument string replaced
4605 * by the character at the corresponding position in the third argument
4606 * string. For example, translate("bar","abc","ABC") returns the string
4607 * BAr. If there is a character in the second argument string with no
4608 * character at a corresponding position in the third argument string
4609 * (because the second argument string is longer than the third argument
4610 * string), then occurrences of that character in the first argument
4611 * string are removed. For example, translate("--aaa--","abc-","ABC")
4612 * returns "AAA". If a character occurs more than once in second
4613 * argument string, then the first occurrence determines the replacement
4614 * character. If the third argument string is longer than the second
4615 * argument string, then excess characters are ignored.
4616 */
4617void
4618xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00004619 xmlXPathObjectPtr str;
4620 xmlXPathObjectPtr from;
4621 xmlXPathObjectPtr to;
4622 xmlBufferPtr target;
4623 int i, offset, max;
4624 xmlChar ch;
4625 const xmlChar *point;
Owen Taylor3473f882001-02-23 17:55:21 +00004626
Daniel Veillarde043ee12001-04-16 14:08:07 +00004627 /*
4628 * TODO: need to be converted to UTF8 strings
4629 */
4630 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00004631
Daniel Veillarde043ee12001-04-16 14:08:07 +00004632 CAST_TO_STRING;
4633 to = valuePop(ctxt);
4634 CAST_TO_STRING;
4635 from = valuePop(ctxt);
4636 CAST_TO_STRING;
4637 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004638
Daniel Veillarde043ee12001-04-16 14:08:07 +00004639 target = xmlBufferCreate();
4640 if (target) {
4641 max = xmlStrlen(to->stringval);
4642 for (i = 0; (ch = str->stringval[i]); i++) {
4643 point = xmlStrchr(from->stringval, ch);
4644 if (point) {
4645 offset = (int)(point - from->stringval);
4646 if (offset < max)
4647 xmlBufferAdd(target, &to->stringval[offset], 1);
4648 } else
4649 xmlBufferAdd(target, &ch, 1);
4650 }
Owen Taylor3473f882001-02-23 17:55:21 +00004651 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00004652 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4653 xmlBufferFree(target);
4654 xmlXPathFreeObject(str);
4655 xmlXPathFreeObject(from);
4656 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00004657}
4658
4659/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004660 * xmlXPathConvertBoolean:
4661 * @val: an XPath object
4662 *
4663 * Converts an existing object to its boolean() equivalent
4664 *
4665 * Returns the new object, the old one is freed (or the operation
4666 * is done directly on @val)
4667 */
4668xmlXPathObjectPtr
4669xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4670 int res = 0;
4671
4672 if (val == NULL)
4673 return(NULL);
4674 switch (val->type) {
4675 case XPATH_NODESET:
4676 case XPATH_XSLT_TREE:
4677 if ((val->nodesetval == NULL) ||
4678 (val->nodesetval->nodeNr == 0)) res = 0;
4679 else
4680 res = 1;
4681 break;
4682 case XPATH_STRING:
4683 if ((val->stringval == NULL) ||
4684 (val->stringval[0] == 0)) res = 0;
4685 else
4686 res = 1;
4687 break;
4688 case XPATH_BOOLEAN:
4689 return(val);
4690 case XPATH_NUMBER:
4691 if (val->floatval) res = 1;
4692 break;
4693 default:
4694 STRANGE
4695 }
4696 xmlXPathFreeObject(val);
4697 return(xmlXPathNewBoolean(res));
4698}
4699
4700/**
Owen Taylor3473f882001-02-23 17:55:21 +00004701 * xmlXPathBooleanFunction:
4702 * @ctxt: the XPath Parser context
4703 * @nargs: the number of arguments
4704 *
4705 * Implement the boolean() XPath function
4706 * boolean boolean(object)
4707 * he boolean function converts its argument to a boolean as follows:
4708 * - a number is true if and only if it is neither positive or
4709 * negative zero nor NaN
4710 * - a node-set is true if and only if it is non-empty
4711 * - a string is true if and only if its length is non-zero
4712 */
4713void
4714xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4715 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00004716
4717 CHECK_ARITY(1);
4718 cur = valuePop(ctxt);
4719 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004720 cur = xmlXPathConvertBoolean(cur);
4721 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004722}
4723
4724/**
4725 * xmlXPathNotFunction:
4726 * @ctxt: the XPath Parser context
4727 * @nargs: the number of arguments
4728 *
4729 * Implement the not() XPath function
4730 * boolean not(boolean)
4731 * The not function returns true if its argument is false,
4732 * and false otherwise.
4733 */
4734void
4735xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4736 CHECK_ARITY(1);
4737 CAST_TO_BOOLEAN;
4738 CHECK_TYPE(XPATH_BOOLEAN);
4739 ctxt->value->boolval = ! ctxt->value->boolval;
4740}
4741
4742/**
4743 * xmlXPathTrueFunction:
4744 * @ctxt: the XPath Parser context
4745 * @nargs: the number of arguments
4746 *
4747 * Implement the true() XPath function
4748 * boolean true()
4749 */
4750void
4751xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4752 CHECK_ARITY(0);
4753 valuePush(ctxt, xmlXPathNewBoolean(1));
4754}
4755
4756/**
4757 * xmlXPathFalseFunction:
4758 * @ctxt: the XPath Parser context
4759 * @nargs: the number of arguments
4760 *
4761 * Implement the false() XPath function
4762 * boolean false()
4763 */
4764void
4765xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4766 CHECK_ARITY(0);
4767 valuePush(ctxt, xmlXPathNewBoolean(0));
4768}
4769
4770/**
4771 * xmlXPathLangFunction:
4772 * @ctxt: the XPath Parser context
4773 * @nargs: the number of arguments
4774 *
4775 * Implement the lang() XPath function
4776 * boolean lang(string)
4777 * The lang function returns true or false depending on whether the
4778 * language of the context node as specified by xml:lang attributes
4779 * is the same as or is a sublanguage of the language specified by
4780 * the argument string. The language of the context node is determined
4781 * by the value of the xml:lang attribute on the context node, or, if
4782 * the context node has no xml:lang attribute, by the value of the
4783 * xml:lang attribute on the nearest ancestor of the context node that
4784 * has an xml:lang attribute. If there is no such attribute, then lang
4785 * returns false. If there is such an attribute, then lang returns
4786 * true if the attribute value is equal to the argument ignoring case,
4787 * or if there is some suffix starting with - such that the attribute
4788 * value is equal to the argument ignoring that suffix of the attribute
4789 * value and ignoring case.
4790 */
4791void
4792xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4793 xmlXPathObjectPtr val;
4794 const xmlChar *theLang;
4795 const xmlChar *lang;
4796 int ret = 0;
4797 int i;
4798
4799 CHECK_ARITY(1);
4800 CAST_TO_STRING;
4801 CHECK_TYPE(XPATH_STRING);
4802 val = valuePop(ctxt);
4803 lang = val->stringval;
4804 theLang = xmlNodeGetLang(ctxt->context->node);
4805 if ((theLang != NULL) && (lang != NULL)) {
4806 for (i = 0;lang[i] != 0;i++)
4807 if (toupper(lang[i]) != toupper(theLang[i]))
4808 goto not_equal;
4809 ret = 1;
4810 }
4811not_equal:
4812 xmlXPathFreeObject(val);
4813 valuePush(ctxt, xmlXPathNewBoolean(ret));
4814}
4815
4816/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004817 * xmlXPathConvertNumber:
4818 * @val: an XPath object
4819 *
4820 * Converts an existing object to its number() equivalent
4821 *
4822 * Returns the new object, the old one is freed (or the operation
4823 * is done directly on @val)
4824 */
4825xmlXPathObjectPtr
4826xmlXPathConvertNumber(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004827 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004828 double res;
4829
4830 if (val == NULL)
4831 return(xmlXPathNewFloat(0.0));
4832 switch (val->type) {
4833 case XPATH_UNDEFINED:
4834#ifdef DEBUG_EXPR
4835 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
4836#endif
4837 ret = xmlXPathNewFloat(0.0);
4838 break;
4839 case XPATH_XSLT_TREE:
4840 case XPATH_NODESET:
4841 val = xmlXPathConvertString(val);
4842 /* no break on purpose */
4843 case XPATH_STRING:
4844 res = xmlXPathStringEvalNumber(val->stringval);
4845 ret = xmlXPathNewFloat(res);
4846 break;
4847 case XPATH_BOOLEAN:
4848 if (val->boolval) ret = xmlXPathNewFloat(1.0);
4849 else ret = xmlXPathNewFloat(0.0);
4850 break;
4851 case XPATH_NUMBER:
4852 return(val);
4853 case XPATH_USERS:
4854 case XPATH_POINT:
4855 case XPATH_RANGE:
4856 case XPATH_LOCATIONSET:
4857 TODO
4858 ret = xmlXPathNewFloat(0.0);
4859 break;
4860 }
4861 xmlXPathFreeObject(val);
4862 return(ret);
4863}
4864
4865/**
Owen Taylor3473f882001-02-23 17:55:21 +00004866 * xmlXPathNumberFunction:
4867 * @ctxt: the XPath Parser context
4868 * @nargs: the number of arguments
4869 *
4870 * Implement the number() XPath function
4871 * number number(object?)
4872 */
4873void
4874xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4875 xmlXPathObjectPtr cur;
4876 double res;
4877
4878 if (nargs == 0) {
4879 if (ctxt->context->node == NULL) {
4880 valuePush(ctxt, xmlXPathNewFloat(0.0));
4881 } else {
4882 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
4883
4884 res = xmlXPathStringEvalNumber(content);
4885 valuePush(ctxt, xmlXPathNewFloat(res));
4886 xmlFree(content);
4887 }
4888 return;
4889 }
4890
4891 CHECK_ARITY(1);
4892 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004893 cur = xmlXPathConvertNumber(cur);
4894 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004895}
4896
4897/**
4898 * xmlXPathSumFunction:
4899 * @ctxt: the XPath Parser context
4900 * @nargs: the number of arguments
4901 *
4902 * Implement the sum() XPath function
4903 * number sum(node-set)
4904 * The sum function returns the sum of the values of the nodes in
4905 * the argument node-set.
4906 */
4907void
4908xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4909 xmlXPathObjectPtr cur;
4910 int i;
4911
4912 CHECK_ARITY(1);
4913 if ((ctxt->value == NULL) ||
4914 ((ctxt->value->type != XPATH_NODESET) &&
4915 (ctxt->value->type != XPATH_XSLT_TREE)))
4916 XP_ERROR(XPATH_INVALID_TYPE);
4917 cur = valuePop(ctxt);
4918
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004919 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004920 valuePush(ctxt, xmlXPathNewFloat(0.0));
4921 } else {
4922 valuePush(ctxt,
4923 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
4924 xmlXPathNumberFunction(ctxt, 1);
4925 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
4926 valuePush(ctxt,
4927 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4928 xmlXPathAddValues(ctxt);
4929 }
4930 }
4931 xmlXPathFreeObject(cur);
4932}
4933
4934/**
4935 * xmlXPathFloorFunction:
4936 * @ctxt: the XPath Parser context
4937 * @nargs: the number of arguments
4938 *
4939 * Implement the floor() XPath function
4940 * number floor(number)
4941 * The floor function returns the largest (closest to positive infinity)
4942 * number that is not greater than the argument and that is an integer.
4943 */
4944void
4945xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4946 CHECK_ARITY(1);
4947 CAST_TO_NUMBER;
4948 CHECK_TYPE(XPATH_NUMBER);
4949#if 0
4950 ctxt->value->floatval = floor(ctxt->value->floatval);
4951#else
4952 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
4953 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
4954#endif
4955}
4956
4957/**
4958 * xmlXPathCeilingFunction:
4959 * @ctxt: the XPath Parser context
4960 * @nargs: the number of arguments
4961 *
4962 * Implement the ceiling() XPath function
4963 * number ceiling(number)
4964 * The ceiling function returns the smallest (closest to negative infinity)
4965 * number that is not less than the argument and that is an integer.
4966 */
4967void
4968xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4969 double f;
4970
4971 CHECK_ARITY(1);
4972 CAST_TO_NUMBER;
4973 CHECK_TYPE(XPATH_NUMBER);
4974
4975#if 0
4976 ctxt->value->floatval = ceil(ctxt->value->floatval);
4977#else
4978 f = (double)((int) ctxt->value->floatval);
4979 if (f != ctxt->value->floatval)
4980 ctxt->value->floatval = f + 1;
4981#endif
4982}
4983
4984/**
4985 * xmlXPathRoundFunction:
4986 * @ctxt: the XPath Parser context
4987 * @nargs: the number of arguments
4988 *
4989 * Implement the round() XPath function
4990 * number round(number)
4991 * The round function returns the number that is closest to the
4992 * argument and that is an integer. If there are two such numbers,
4993 * then the one that is even is returned.
4994 */
4995void
4996xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4997 double f;
4998
4999 CHECK_ARITY(1);
5000 CAST_TO_NUMBER;
5001 CHECK_TYPE(XPATH_NUMBER);
5002
5003 if ((ctxt->value->floatval == xmlXPathNAN) ||
5004 (ctxt->value->floatval == xmlXPathPINF) ||
5005 (ctxt->value->floatval == xmlXPathNINF) ||
5006 (ctxt->value->floatval == 0.0))
5007 return;
5008
5009#if 0
5010 f = floor(ctxt->value->floatval);
5011#else
5012 f = (double)((int) ctxt->value->floatval);
5013#endif
5014 if (ctxt->value->floatval < f + 0.5)
5015 ctxt->value->floatval = f;
5016 else
5017 ctxt->value->floatval = f + 1;
5018}
5019
5020/************************************************************************
5021 * *
5022 * The Parser *
5023 * *
5024 ************************************************************************/
5025
5026/*
5027 * a couple of forward declarations since we use a recursive call based
5028 * implementation.
5029 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005030static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005031static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005032static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005033#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005034static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5035#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005036#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005037static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005038#endif
5039
5040/**
5041 * xmlXPathParseNCName:
5042 * @ctxt: the XPath Parser context
5043 *
5044 * parse an XML namespace non qualified name.
5045 *
5046 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5047 *
5048 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5049 * CombiningChar | Extender
5050 *
5051 * Returns the namespace name or NULL
5052 */
5053
5054xmlChar *
5055xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
5056 const xmlChar *q;
5057 xmlChar *ret = NULL;
5058
5059 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
5060 q = NEXT;
5061
5062 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
5063 (CUR == '.') || (CUR == '-') ||
5064 (CUR == '_') ||
5065 (IS_COMBINING(CUR)) ||
5066 (IS_EXTENDER(CUR)))
5067 NEXT;
5068
5069 ret = xmlStrndup(q, CUR_PTR - q);
5070
5071 return(ret);
5072}
5073
5074/**
5075 * xmlXPathParseQName:
5076 * @ctxt: the XPath Parser context
5077 * @prefix: a xmlChar **
5078 *
5079 * parse an XML qualified name
5080 *
5081 * [NS 5] QName ::= (Prefix ':')? LocalPart
5082 *
5083 * [NS 6] Prefix ::= NCName
5084 *
5085 * [NS 7] LocalPart ::= NCName
5086 *
5087 * Returns the function returns the local part, and prefix is updated
5088 * to get the Prefix if any.
5089 */
5090
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005091static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005092xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5093 xmlChar *ret = NULL;
5094
5095 *prefix = NULL;
5096 ret = xmlXPathParseNCName(ctxt);
5097 if (CUR == ':') {
5098 *prefix = ret;
5099 NEXT;
5100 ret = xmlXPathParseNCName(ctxt);
5101 }
5102 return(ret);
5103}
5104
5105/**
5106 * xmlXPathParseName:
5107 * @ctxt: the XPath Parser context
5108 *
5109 * parse an XML name
5110 *
5111 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5112 * CombiningChar | Extender
5113 *
5114 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5115 *
5116 * Returns the namespace name or NULL
5117 */
5118
5119xmlChar *
5120xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
5121 const xmlChar *q;
5122 xmlChar *ret = NULL;
5123
5124 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
5125 q = NEXT;
5126
5127 /* TODO Make this UTF8 compliant !!! */
5128 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
5129 (CUR == '.') || (CUR == '-') ||
5130 (CUR == '_') || (CUR == ':') ||
5131 (IS_COMBINING(CUR)) ||
5132 (IS_EXTENDER(CUR)))
5133 NEXT;
5134
5135 ret = xmlStrndup(q, CUR_PTR - q);
5136
5137 return(ret);
5138}
5139
5140/**
5141 * xmlXPathStringEvalNumber:
5142 * @str: A string to scan
5143 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005144 * [30a] Float ::= Number ('e' Digits?)?
5145 *
Owen Taylor3473f882001-02-23 17:55:21 +00005146 * [30] Number ::= Digits ('.' Digits?)?
5147 * | '.' Digits
5148 * [31] Digits ::= [0-9]+
5149 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005150 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005151 * In complement of the Number expression, this function also handles
5152 * negative values : '-' Number.
5153 *
5154 * Returns the double value.
5155 */
5156double
5157xmlXPathStringEvalNumber(const xmlChar *str) {
5158 const xmlChar *cur = str;
5159 double ret = 0.0;
5160 double mult = 1;
5161 int ok = 0;
5162 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005163 int exponent = 0;
5164 int is_exponent_negative = 0;
5165
Owen Taylor3473f882001-02-23 17:55:21 +00005166 while (IS_BLANK(*cur)) cur++;
5167 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5168 return(xmlXPathNAN);
5169 }
5170 if (*cur == '-') {
5171 isneg = 1;
5172 cur++;
5173 }
5174 while ((*cur >= '0') && (*cur <= '9')) {
5175 ret = ret * 10 + (*cur - '0');
5176 ok = 1;
5177 cur++;
5178 }
5179 if (*cur == '.') {
5180 cur++;
5181 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5182 return(xmlXPathNAN);
5183 }
5184 while ((*cur >= '0') && (*cur <= '9')) {
5185 mult /= 10;
5186 ret = ret + (*cur - '0') * mult;
5187 cur++;
5188 }
5189 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005190 if ((*cur == 'e') || (*cur == 'E')) {
5191 cur++;
5192 if (*cur == '-') {
5193 is_exponent_negative = 1;
5194 cur++;
5195 }
5196 while ((*cur >= '0') && (*cur <= '9')) {
5197 exponent = exponent * 10 + (*cur - '0');
5198 cur++;
5199 }
5200 }
Owen Taylor3473f882001-02-23 17:55:21 +00005201 while (IS_BLANK(*cur)) cur++;
5202 if (*cur != 0) return(xmlXPathNAN);
5203 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005204 if (is_exponent_negative) exponent = -exponent;
5205 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005206 return(ret);
5207}
5208
5209/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005210 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005211 * @ctxt: the XPath Parser context
5212 *
5213 * [30] Number ::= Digits ('.' Digits?)?
5214 * | '.' Digits
5215 * [31] Digits ::= [0-9]+
5216 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005217 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005218 *
5219 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005220static void
5221xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005222 double ret = 0.0;
5223 double mult = 1;
5224 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005225 int exponent = 0;
5226 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005227
5228 CHECK_ERROR;
5229 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5230 XP_ERROR(XPATH_NUMBER_ERROR);
5231 }
5232 while ((CUR >= '0') && (CUR <= '9')) {
5233 ret = ret * 10 + (CUR - '0');
5234 ok = 1;
5235 NEXT;
5236 }
5237 if (CUR == '.') {
5238 NEXT;
5239 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5240 XP_ERROR(XPATH_NUMBER_ERROR);
5241 }
5242 while ((CUR >= '0') && (CUR <= '9')) {
5243 mult /= 10;
5244 ret = ret + (CUR - '0') * mult;
5245 NEXT;
5246 }
5247 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005248 if ((CUR == 'e') || (CUR == 'E')) {
5249 NEXT;
5250 if (CUR == '-') {
5251 is_exponent_negative = 1;
5252 NEXT;
5253 }
5254 while ((CUR >= '0') && (CUR <= '9')) {
5255 exponent = exponent * 10 + (CUR - '0');
5256 NEXT;
5257 }
5258 }
5259 if (is_exponent_negative)
5260 exponent = -exponent;
5261 ret *= pow(10.0, (double)exponent);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005262 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5263 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005264}
5265
5266/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005267 * xmlXPathParseLiteral:
5268 * @ctxt: the XPath Parser context
5269 *
5270 * Parse a Literal
5271 *
5272 * [29] Literal ::= '"' [^"]* '"'
5273 * | "'" [^']* "'"
5274 *
5275 * Returns the value found or NULL in case of error
5276 */
5277static xmlChar *
5278xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5279 const xmlChar *q;
5280 xmlChar *ret = NULL;
5281
5282 if (CUR == '"') {
5283 NEXT;
5284 q = CUR_PTR;
5285 while ((IS_CHAR(CUR)) && (CUR != '"'))
5286 NEXT;
5287 if (!IS_CHAR(CUR)) {
5288 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5289 } else {
5290 ret = xmlStrndup(q, CUR_PTR - q);
5291 NEXT;
5292 }
5293 } else if (CUR == '\'') {
5294 NEXT;
5295 q = CUR_PTR;
5296 while ((IS_CHAR(CUR)) && (CUR != '\''))
5297 NEXT;
5298 if (!IS_CHAR(CUR)) {
5299 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5300 } else {
5301 ret = xmlStrndup(q, CUR_PTR - q);
5302 NEXT;
5303 }
5304 } else {
5305 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5306 }
5307 return(ret);
5308}
5309
5310/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005311 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005312 * @ctxt: the XPath Parser context
5313 *
5314 * Parse a Literal and push it on the stack.
5315 *
5316 * [29] Literal ::= '"' [^"]* '"'
5317 * | "'" [^']* "'"
5318 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005319 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005320 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005321static void
5322xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005323 const xmlChar *q;
5324 xmlChar *ret = NULL;
5325
5326 if (CUR == '"') {
5327 NEXT;
5328 q = CUR_PTR;
5329 while ((IS_CHAR(CUR)) && (CUR != '"'))
5330 NEXT;
5331 if (!IS_CHAR(CUR)) {
5332 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5333 } else {
5334 ret = xmlStrndup(q, CUR_PTR - q);
5335 NEXT;
5336 }
5337 } else if (CUR == '\'') {
5338 NEXT;
5339 q = CUR_PTR;
5340 while ((IS_CHAR(CUR)) && (CUR != '\''))
5341 NEXT;
5342 if (!IS_CHAR(CUR)) {
5343 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5344 } else {
5345 ret = xmlStrndup(q, CUR_PTR - q);
5346 NEXT;
5347 }
5348 } else {
5349 XP_ERROR(XPATH_START_LITERAL_ERROR);
5350 }
5351 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005352 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5353 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005354 xmlFree(ret);
5355}
5356
5357/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005358 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005359 * @ctxt: the XPath Parser context
5360 *
5361 * Parse a VariableReference, evaluate it and push it on the stack.
5362 *
5363 * The variable bindings consist of a mapping from variable names
5364 * to variable values. The value of a variable is an object, which
5365 * of any of the types that are possible for the value of an expression,
5366 * and may also be of additional types not specified here.
5367 *
5368 * Early evaluation is possible since:
5369 * The variable bindings [...] used to evaluate a subexpression are
5370 * always the same as those used to evaluate the containing expression.
5371 *
5372 * [36] VariableReference ::= '$' QName
5373 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005374static void
5375xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005376 xmlChar *name;
5377 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005378
5379 SKIP_BLANKS;
5380 if (CUR != '$') {
5381 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5382 }
5383 NEXT;
5384 name = xmlXPathParseQName(ctxt, &prefix);
5385 if (name == NULL) {
5386 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5387 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005388 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005389 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5390 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005391 SKIP_BLANKS;
5392}
5393
5394/**
5395 * xmlXPathIsNodeType:
5396 * @ctxt: the XPath Parser context
5397 * @name: a name string
5398 *
5399 * Is the name given a NodeType one.
5400 *
5401 * [38] NodeType ::= 'comment'
5402 * | 'text'
5403 * | 'processing-instruction'
5404 * | 'node'
5405 *
5406 * Returns 1 if true 0 otherwise
5407 */
5408int
5409xmlXPathIsNodeType(const xmlChar *name) {
5410 if (name == NULL)
5411 return(0);
5412
5413 if (xmlStrEqual(name, BAD_CAST "comment"))
5414 return(1);
5415 if (xmlStrEqual(name, BAD_CAST "text"))
5416 return(1);
5417 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5418 return(1);
5419 if (xmlStrEqual(name, BAD_CAST "node"))
5420 return(1);
5421 return(0);
5422}
5423
5424/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005425 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005426 * @ctxt: the XPath Parser context
5427 *
5428 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5429 * [17] Argument ::= Expr
5430 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005431 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00005432 * pushed on the stack
5433 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005434static void
5435xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005436 xmlChar *name;
5437 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005438 int nbargs = 0;
5439
5440 name = xmlXPathParseQName(ctxt, &prefix);
5441 if (name == NULL) {
5442 XP_ERROR(XPATH_EXPR_ERROR);
5443 }
5444 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005445#ifdef DEBUG_EXPR
5446 if (prefix == NULL)
5447 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5448 name);
5449 else
5450 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5451 prefix, name);
5452#endif
5453
Owen Taylor3473f882001-02-23 17:55:21 +00005454 if (CUR != '(') {
5455 XP_ERROR(XPATH_EXPR_ERROR);
5456 }
5457 NEXT;
5458 SKIP_BLANKS;
5459
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005460 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005461 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005462 int op1 = ctxt->comp->last;
5463 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005464 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005465 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005466 nbargs++;
5467 if (CUR == ')') break;
5468 if (CUR != ',') {
5469 XP_ERROR(XPATH_EXPR_ERROR);
5470 }
5471 NEXT;
5472 SKIP_BLANKS;
5473 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005474 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
5475 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005476 NEXT;
5477 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005478}
5479
5480/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005481 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005482 * @ctxt: the XPath Parser context
5483 *
5484 * [15] PrimaryExpr ::= VariableReference
5485 * | '(' Expr ')'
5486 * | Literal
5487 * | Number
5488 * | FunctionCall
5489 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005490 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005491 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005492static void
5493xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005494 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005495 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005496 else if (CUR == '(') {
5497 NEXT;
5498 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005499 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005500 if (CUR != ')') {
5501 XP_ERROR(XPATH_EXPR_ERROR);
5502 }
5503 NEXT;
5504 SKIP_BLANKS;
5505 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005506 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005507 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005508 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005509 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005510 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005511 }
5512 SKIP_BLANKS;
5513}
5514
5515/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005516 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005517 * @ctxt: the XPath Parser context
5518 *
5519 * [20] FilterExpr ::= PrimaryExpr
5520 * | FilterExpr Predicate
5521 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005522 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005523 * Square brackets are used to filter expressions in the same way that
5524 * they are used in location paths. It is an error if the expression to
5525 * be filtered does not evaluate to a node-set. The context node list
5526 * used for evaluating the expression in square brackets is the node-set
5527 * to be filtered listed in document order.
5528 */
5529
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005530static void
5531xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
5532 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005533 CHECK_ERROR;
5534 SKIP_BLANKS;
5535
5536 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005537 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00005538 SKIP_BLANKS;
5539 }
5540
5541
5542}
5543
5544/**
5545 * xmlXPathScanName:
5546 * @ctxt: the XPath Parser context
5547 *
5548 * Trickery: parse an XML name but without consuming the input flow
5549 * Needed to avoid insanity in the parser state.
5550 *
5551 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5552 * CombiningChar | Extender
5553 *
5554 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5555 *
5556 * [6] Names ::= Name (S Name)*
5557 *
5558 * Returns the Name parsed or NULL
5559 */
5560
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005561static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005562xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
5563 xmlChar buf[XML_MAX_NAMELEN];
5564 int len = 0;
5565
5566 SKIP_BLANKS;
5567 if (!IS_LETTER(CUR) && (CUR != '_') &&
5568 (CUR != ':')) {
5569 return(NULL);
5570 }
5571
5572 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5573 (NXT(len) == '.') || (NXT(len) == '-') ||
5574 (NXT(len) == '_') || (NXT(len) == ':') ||
5575 (IS_COMBINING(NXT(len))) ||
5576 (IS_EXTENDER(NXT(len)))) {
5577 buf[len] = NXT(len);
5578 len++;
5579 if (len >= XML_MAX_NAMELEN) {
5580 xmlGenericError(xmlGenericErrorContext,
5581 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5582 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5583 (NXT(len) == '.') || (NXT(len) == '-') ||
5584 (NXT(len) == '_') || (NXT(len) == ':') ||
5585 (IS_COMBINING(NXT(len))) ||
5586 (IS_EXTENDER(NXT(len))))
5587 len++;
5588 break;
5589 }
5590 }
5591 return(xmlStrndup(buf, len));
5592}
5593
5594/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005595 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005596 * @ctxt: the XPath Parser context
5597 *
5598 * [19] PathExpr ::= LocationPath
5599 * | FilterExpr
5600 * | FilterExpr '/' RelativeLocationPath
5601 * | FilterExpr '//' RelativeLocationPath
5602 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005603 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005604 * The / operator and // operators combine an arbitrary expression
5605 * and a relative location path. It is an error if the expression
5606 * does not evaluate to a node-set.
5607 * The / operator does composition in the same way as when / is
5608 * used in a location path. As in location paths, // is short for
5609 * /descendant-or-self::node()/.
5610 */
5611
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005612static void
5613xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005614 int lc = 1; /* Should we branch to LocationPath ? */
5615 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5616
5617 SKIP_BLANKS;
5618 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5619 (CUR == '\'') || (CUR == '"')) {
5620 lc = 0;
5621 } else if (CUR == '*') {
5622 /* relative or absolute location path */
5623 lc = 1;
5624 } else if (CUR == '/') {
5625 /* relative or absolute location path */
5626 lc = 1;
5627 } else if (CUR == '@') {
5628 /* relative abbreviated attribute location path */
5629 lc = 1;
5630 } else if (CUR == '.') {
5631 /* relative abbreviated attribute location path */
5632 lc = 1;
5633 } else {
5634 /*
5635 * Problem is finding if we have a name here whether it's:
5636 * - a nodetype
5637 * - a function call in which case it's followed by '('
5638 * - an axis in which case it's followed by ':'
5639 * - a element name
5640 * We do an a priori analysis here rather than having to
5641 * maintain parsed token content through the recursive function
5642 * calls. This looks uglier but makes the code quite easier to
5643 * read/write/debug.
5644 */
5645 SKIP_BLANKS;
5646 name = xmlXPathScanName(ctxt);
5647 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
5648#ifdef DEBUG_STEP
5649 xmlGenericError(xmlGenericErrorContext,
5650 "PathExpr: Axis\n");
5651#endif
5652 lc = 1;
5653 xmlFree(name);
5654 } else if (name != NULL) {
5655 int len =xmlStrlen(name);
5656 int blank = 0;
5657
5658
5659 while (NXT(len) != 0) {
5660 if (NXT(len) == '/') {
5661 /* element name */
5662#ifdef DEBUG_STEP
5663 xmlGenericError(xmlGenericErrorContext,
5664 "PathExpr: AbbrRelLocation\n");
5665#endif
5666 lc = 1;
5667 break;
5668 } else if (IS_BLANK(NXT(len))) {
5669 /* skip to next */
5670 blank = 1;
5671 } else if (NXT(len) == ':') {
5672#ifdef DEBUG_STEP
5673 xmlGenericError(xmlGenericErrorContext,
5674 "PathExpr: AbbrRelLocation\n");
5675#endif
5676 lc = 1;
5677 break;
5678 } else if ((NXT(len) == '(')) {
5679 /* Note Type or Function */
5680 if (xmlXPathIsNodeType(name)) {
5681#ifdef DEBUG_STEP
5682 xmlGenericError(xmlGenericErrorContext,
5683 "PathExpr: Type search\n");
5684#endif
5685 lc = 1;
5686 } else {
5687#ifdef DEBUG_STEP
5688 xmlGenericError(xmlGenericErrorContext,
5689 "PathExpr: function call\n");
5690#endif
5691 lc = 0;
5692 }
5693 break;
5694 } else if ((NXT(len) == '[')) {
5695 /* element name */
5696#ifdef DEBUG_STEP
5697 xmlGenericError(xmlGenericErrorContext,
5698 "PathExpr: AbbrRelLocation\n");
5699#endif
5700 lc = 1;
5701 break;
5702 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5703 (NXT(len) == '=')) {
5704 lc = 1;
5705 break;
5706 } else {
5707 lc = 1;
5708 break;
5709 }
5710 len++;
5711 }
5712 if (NXT(len) == 0) {
5713#ifdef DEBUG_STEP
5714 xmlGenericError(xmlGenericErrorContext,
5715 "PathExpr: AbbrRelLocation\n");
5716#endif
5717 /* element name */
5718 lc = 1;
5719 }
5720 xmlFree(name);
5721 } else {
5722 /* make sure all cases are covered explicitely */
5723 XP_ERROR(XPATH_EXPR_ERROR);
5724 }
5725 }
5726
5727 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005728 if (CUR == '/') {
5729 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
5730 } else {
5731 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005732 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005733 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005734 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005735 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005736 CHECK_ERROR;
5737 if ((CUR == '/') && (NXT(1) == '/')) {
5738 SKIP(2);
5739 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005740
5741 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
5742 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5743 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
5744
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005745 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005746 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005747 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005748 }
5749 }
5750 SKIP_BLANKS;
5751}
5752
5753/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005754 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005755 * @ctxt: the XPath Parser context
5756 *
5757 * [18] UnionExpr ::= PathExpr
5758 * | UnionExpr '|' PathExpr
5759 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005760 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005761 */
5762
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005763static void
5764xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
5765 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005766 CHECK_ERROR;
5767 SKIP_BLANKS;
5768 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005769 int op1 = ctxt->comp->last;
5770 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005771
5772 NEXT;
5773 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005774 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005775
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005776 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
5777
Owen Taylor3473f882001-02-23 17:55:21 +00005778 SKIP_BLANKS;
5779 }
Owen Taylor3473f882001-02-23 17:55:21 +00005780}
5781
5782/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005783 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005784 * @ctxt: the XPath Parser context
5785 *
5786 * [27] UnaryExpr ::= UnionExpr
5787 * | '-' UnaryExpr
5788 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005789 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005790 */
5791
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005792static void
5793xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005794 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005795 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005796
5797 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00005798 while (CUR == '-') {
5799 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005800 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005801 NEXT;
5802 SKIP_BLANKS;
5803 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005804
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005805 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005806 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005807 if (found) {
5808 if (minus)
5809 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
5810 else
5811 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005812 }
5813}
5814
5815/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005816 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005817 * @ctxt: the XPath Parser context
5818 *
5819 * [26] MultiplicativeExpr ::= UnaryExpr
5820 * | MultiplicativeExpr MultiplyOperator UnaryExpr
5821 * | MultiplicativeExpr 'div' UnaryExpr
5822 * | MultiplicativeExpr 'mod' UnaryExpr
5823 * [34] MultiplyOperator ::= '*'
5824 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005825 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005826 */
5827
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005828static void
5829xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
5830 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005831 CHECK_ERROR;
5832 SKIP_BLANKS;
5833 while ((CUR == '*') ||
5834 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
5835 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
5836 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005837 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005838
5839 if (CUR == '*') {
5840 op = 0;
5841 NEXT;
5842 } else if (CUR == 'd') {
5843 op = 1;
5844 SKIP(3);
5845 } else if (CUR == 'm') {
5846 op = 2;
5847 SKIP(3);
5848 }
5849 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005850 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005851 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005852 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005853 SKIP_BLANKS;
5854 }
5855}
5856
5857/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005858 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005859 * @ctxt: the XPath Parser context
5860 *
5861 * [25] AdditiveExpr ::= MultiplicativeExpr
5862 * | AdditiveExpr '+' MultiplicativeExpr
5863 * | AdditiveExpr '-' MultiplicativeExpr
5864 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005865 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005866 */
5867
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005868static void
5869xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005870
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005871 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005872 CHECK_ERROR;
5873 SKIP_BLANKS;
5874 while ((CUR == '+') || (CUR == '-')) {
5875 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005876 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005877
5878 if (CUR == '+') plus = 1;
5879 else plus = 0;
5880 NEXT;
5881 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005882 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005883 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005884 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005885 SKIP_BLANKS;
5886 }
5887}
5888
5889/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005890 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005891 * @ctxt: the XPath Parser context
5892 *
5893 * [24] RelationalExpr ::= AdditiveExpr
5894 * | RelationalExpr '<' AdditiveExpr
5895 * | RelationalExpr '>' AdditiveExpr
5896 * | RelationalExpr '<=' AdditiveExpr
5897 * | RelationalExpr '>=' AdditiveExpr
5898 *
5899 * A <= B > C is allowed ? Answer from James, yes with
5900 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
5901 * which is basically what got implemented.
5902 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005903 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00005904 * on the stack
5905 */
5906
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005907static void
5908xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
5909 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005910 CHECK_ERROR;
5911 SKIP_BLANKS;
5912 while ((CUR == '<') ||
5913 (CUR == '>') ||
5914 ((CUR == '<') && (NXT(1) == '=')) ||
5915 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005916 int inf, strict;
5917 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005918
5919 if (CUR == '<') inf = 1;
5920 else inf = 0;
5921 if (NXT(1) == '=') strict = 0;
5922 else strict = 1;
5923 NEXT;
5924 if (!strict) NEXT;
5925 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005926 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005927 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005928 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00005929 SKIP_BLANKS;
5930 }
5931}
5932
5933/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005934 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005935 * @ctxt: the XPath Parser context
5936 *
5937 * [23] EqualityExpr ::= RelationalExpr
5938 * | EqualityExpr '=' RelationalExpr
5939 * | EqualityExpr '!=' RelationalExpr
5940 *
5941 * A != B != C is allowed ? Answer from James, yes with
5942 * (RelationalExpr = RelationalExpr) = RelationalExpr
5943 * (RelationalExpr != RelationalExpr) != RelationalExpr
5944 * which is basically what got implemented.
5945 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005946 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005947 *
5948 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005949static void
5950xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
5951 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005952 CHECK_ERROR;
5953 SKIP_BLANKS;
5954 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005955 int eq;
5956 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005957
5958 if (CUR == '=') eq = 1;
5959 else eq = 0;
5960 NEXT;
5961 if (!eq) NEXT;
5962 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005963 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005964 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005965 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005966 SKIP_BLANKS;
5967 }
5968}
5969
5970/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005971 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005972 * @ctxt: the XPath Parser context
5973 *
5974 * [22] AndExpr ::= EqualityExpr
5975 * | AndExpr 'and' EqualityExpr
5976 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005977 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005978 *
5979 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005980static void
5981xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
5982 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005983 CHECK_ERROR;
5984 SKIP_BLANKS;
5985 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005986 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005987 SKIP(3);
5988 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005989 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005990 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005991 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005992 SKIP_BLANKS;
5993 }
5994}
5995
5996/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005997 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005998 * @ctxt: the XPath Parser context
5999 *
6000 * [14] Expr ::= OrExpr
6001 * [21] OrExpr ::= AndExpr
6002 * | OrExpr 'or' AndExpr
6003 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006004 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006005 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006006static void
6007xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6008 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006009 CHECK_ERROR;
6010 SKIP_BLANKS;
6011 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006012 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006013 SKIP(2);
6014 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006015 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006016 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006017 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6018 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006019 SKIP_BLANKS;
6020 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006021 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6022 /* more ops could be optimized too */
6023 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6024 }
Owen Taylor3473f882001-02-23 17:55:21 +00006025}
6026
6027/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006028 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006029 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006030 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006031 *
6032 * [8] Predicate ::= '[' PredicateExpr ']'
6033 * [9] PredicateExpr ::= Expr
6034 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006035 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006036 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006037static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006038xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006039 int op1 = ctxt->comp->last;
6040
6041 SKIP_BLANKS;
6042 if (CUR != '[') {
6043 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6044 }
6045 NEXT;
6046 SKIP_BLANKS;
6047
6048 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006049 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006050 CHECK_ERROR;
6051
6052 if (CUR != ']') {
6053 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6054 }
6055
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006056 if (filter)
6057 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6058 else
6059 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006060
6061 NEXT;
6062 SKIP_BLANKS;
6063}
6064
6065/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006066 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006067 * @ctxt: the XPath Parser context
6068 * @test: pointer to a xmlXPathTestVal
6069 * @type: pointer to a xmlXPathTypeVal
6070 * @prefix: placeholder for a possible name prefix
6071 *
6072 * [7] NodeTest ::= NameTest
6073 * | NodeType '(' ')'
6074 * | 'processing-instruction' '(' Literal ')'
6075 *
6076 * [37] NameTest ::= '*'
6077 * | NCName ':' '*'
6078 * | QName
6079 * [38] NodeType ::= 'comment'
6080 * | 'text'
6081 * | 'processing-instruction'
6082 * | 'node'
6083 *
6084 * Returns the name found and update @test, @type and @prefix appropriately
6085 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006086static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006087xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6088 xmlXPathTypeVal *type, const xmlChar **prefix,
6089 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006090 int blanks;
6091
6092 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6093 STRANGE;
6094 return(NULL);
6095 }
6096 *type = 0;
6097 *test = 0;
6098 *prefix = NULL;
6099 SKIP_BLANKS;
6100
6101 if ((name == NULL) && (CUR == '*')) {
6102 /*
6103 * All elements
6104 */
6105 NEXT;
6106 *test = NODE_TEST_ALL;
6107 return(NULL);
6108 }
6109
6110 if (name == NULL)
6111 name = xmlXPathParseNCName(ctxt);
6112 if (name == NULL) {
6113 XP_ERROR0(XPATH_EXPR_ERROR);
6114 }
6115
6116 blanks = IS_BLANK(CUR);
6117 SKIP_BLANKS;
6118 if (CUR == '(') {
6119 NEXT;
6120 /*
6121 * NodeType or PI search
6122 */
6123 if (xmlStrEqual(name, BAD_CAST "comment"))
6124 *type = NODE_TYPE_COMMENT;
6125 else if (xmlStrEqual(name, BAD_CAST "node"))
6126 *type = NODE_TYPE_NODE;
6127 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6128 *type = NODE_TYPE_PI;
6129 else if (xmlStrEqual(name, BAD_CAST "text"))
6130 *type = NODE_TYPE_TEXT;
6131 else {
6132 if (name != NULL)
6133 xmlFree(name);
6134 XP_ERROR0(XPATH_EXPR_ERROR);
6135 }
6136
6137 *test = NODE_TEST_TYPE;
6138
6139 SKIP_BLANKS;
6140 if (*type == NODE_TYPE_PI) {
6141 /*
6142 * Specific case: search a PI by name.
6143 */
Owen Taylor3473f882001-02-23 17:55:21 +00006144 if (name != NULL)
6145 xmlFree(name);
6146
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006147 name = xmlXPathParseLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006148 CHECK_ERROR 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006149 SKIP_BLANKS;
6150 }
6151 if (CUR != ')') {
6152 if (name != NULL)
6153 xmlFree(name);
6154 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6155 }
6156 NEXT;
6157 return(name);
6158 }
6159 *test = NODE_TEST_NAME;
6160 if ((!blanks) && (CUR == ':')) {
6161 NEXT;
6162
6163 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006164 * Since currently the parser context don't have a
6165 * namespace list associated:
6166 * The namespace name for this prefix can be computed
6167 * only at evaluation time. The compilation is done
6168 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006169 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006170#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006171 *prefix = xmlXPathNsLookup(ctxt->context, name);
6172 if (name != NULL)
6173 xmlFree(name);
6174 if (*prefix == NULL) {
6175 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6176 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006177#else
6178 *prefix = name;
6179#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006180
6181 if (CUR == '*') {
6182 /*
6183 * All elements
6184 */
6185 NEXT;
6186 *test = NODE_TEST_ALL;
6187 return(NULL);
6188 }
6189
6190 name = xmlXPathParseNCName(ctxt);
6191 if (name == NULL) {
6192 XP_ERROR0(XPATH_EXPR_ERROR);
6193 }
6194 }
6195 return(name);
6196}
6197
6198/**
6199 * xmlXPathIsAxisName:
6200 * @name: a preparsed name token
6201 *
6202 * [6] AxisName ::= 'ancestor'
6203 * | 'ancestor-or-self'
6204 * | 'attribute'
6205 * | 'child'
6206 * | 'descendant'
6207 * | 'descendant-or-self'
6208 * | 'following'
6209 * | 'following-sibling'
6210 * | 'namespace'
6211 * | 'parent'
6212 * | 'preceding'
6213 * | 'preceding-sibling'
6214 * | 'self'
6215 *
6216 * Returns the axis or 0
6217 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006218static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006219xmlXPathIsAxisName(const xmlChar *name) {
6220 xmlXPathAxisVal ret = 0;
6221 switch (name[0]) {
6222 case 'a':
6223 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6224 ret = AXIS_ANCESTOR;
6225 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6226 ret = AXIS_ANCESTOR_OR_SELF;
6227 if (xmlStrEqual(name, BAD_CAST "attribute"))
6228 ret = AXIS_ATTRIBUTE;
6229 break;
6230 case 'c':
6231 if (xmlStrEqual(name, BAD_CAST "child"))
6232 ret = AXIS_CHILD;
6233 break;
6234 case 'd':
6235 if (xmlStrEqual(name, BAD_CAST "descendant"))
6236 ret = AXIS_DESCENDANT;
6237 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6238 ret = AXIS_DESCENDANT_OR_SELF;
6239 break;
6240 case 'f':
6241 if (xmlStrEqual(name, BAD_CAST "following"))
6242 ret = AXIS_FOLLOWING;
6243 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6244 ret = AXIS_FOLLOWING_SIBLING;
6245 break;
6246 case 'n':
6247 if (xmlStrEqual(name, BAD_CAST "namespace"))
6248 ret = AXIS_NAMESPACE;
6249 break;
6250 case 'p':
6251 if (xmlStrEqual(name, BAD_CAST "parent"))
6252 ret = AXIS_PARENT;
6253 if (xmlStrEqual(name, BAD_CAST "preceding"))
6254 ret = AXIS_PRECEDING;
6255 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6256 ret = AXIS_PRECEDING_SIBLING;
6257 break;
6258 case 's':
6259 if (xmlStrEqual(name, BAD_CAST "self"))
6260 ret = AXIS_SELF;
6261 break;
6262 }
6263 return(ret);
6264}
6265
6266/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006267 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006268 * @ctxt: the XPath Parser context
6269 *
6270 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6271 * | AbbreviatedStep
6272 *
6273 * [12] AbbreviatedStep ::= '.' | '..'
6274 *
6275 * [5] AxisSpecifier ::= AxisName '::'
6276 * | AbbreviatedAxisSpecifier
6277 *
6278 * [13] AbbreviatedAxisSpecifier ::= '@'?
6279 *
6280 * Modified for XPtr range support as:
6281 *
6282 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6283 * | AbbreviatedStep
6284 * | 'range-to' '(' Expr ')' Predicate*
6285 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006286 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006287 * A location step of . is short for self::node(). This is
6288 * particularly useful in conjunction with //. For example, the
6289 * location path .//para is short for
6290 * self::node()/descendant-or-self::node()/child::para
6291 * and so will select all para descendant elements of the context
6292 * node.
6293 * Similarly, a location step of .. is short for parent::node().
6294 * For example, ../title is short for parent::node()/child::title
6295 * and so will select the title children of the parent of the context
6296 * node.
6297 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006298static void
6299xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006300#ifdef LIBXML_XPTR_ENABLED
6301 int rangeto = 0;
6302 int op2 = -1;
6303#endif
6304
Owen Taylor3473f882001-02-23 17:55:21 +00006305 SKIP_BLANKS;
6306 if ((CUR == '.') && (NXT(1) == '.')) {
6307 SKIP(2);
6308 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006309 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6310 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006311 } else if (CUR == '.') {
6312 NEXT;
6313 SKIP_BLANKS;
6314 } else {
6315 xmlChar *name = NULL;
6316 const xmlChar *prefix = NULL;
6317 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006318 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006319 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006320 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006321
6322 /*
6323 * The modification needed for XPointer change to the production
6324 */
6325#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006326 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006327 name = xmlXPathParseNCName(ctxt);
6328 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006329 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006330 xmlFree(name);
6331 SKIP_BLANKS;
6332 if (CUR != '(') {
6333 XP_ERROR(XPATH_EXPR_ERROR);
6334 }
6335 NEXT;
6336 SKIP_BLANKS;
6337
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006338 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006339 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006340 CHECK_ERROR;
6341
6342 SKIP_BLANKS;
6343 if (CUR != ')') {
6344 XP_ERROR(XPATH_EXPR_ERROR);
6345 }
6346 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006347 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006348 goto eval_predicates;
6349 }
6350 }
6351#endif
6352 if (name == NULL)
6353 name = xmlXPathParseNCName(ctxt);
6354 if (name != NULL) {
6355 axis = xmlXPathIsAxisName(name);
6356 if (axis != 0) {
6357 SKIP_BLANKS;
6358 if ((CUR == ':') && (NXT(1) == ':')) {
6359 SKIP(2);
6360 xmlFree(name);
6361 name = NULL;
6362 } else {
6363 /* an element name can conflict with an axis one :-\ */
6364 axis = AXIS_CHILD;
6365 }
6366 } else {
6367 axis = AXIS_CHILD;
6368 }
6369 } else if (CUR == '@') {
6370 NEXT;
6371 axis = AXIS_ATTRIBUTE;
6372 } else {
6373 axis = AXIS_CHILD;
6374 }
6375
6376 CHECK_ERROR;
6377
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006378 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006379 if (test == 0)
6380 return;
6381
6382#ifdef DEBUG_STEP
6383 xmlGenericError(xmlGenericErrorContext,
6384 "Basis : computing new set\n");
6385#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006386
Owen Taylor3473f882001-02-23 17:55:21 +00006387#ifdef DEBUG_STEP
6388 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006389 if (ctxt->value == NULL)
6390 xmlGenericError(xmlGenericErrorContext, "no value\n");
6391 else if (ctxt->value->nodesetval == NULL)
6392 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6393 else
6394 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006395#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006396
6397eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006398 op1 = ctxt->comp->last;
6399 ctxt->comp->last = -1;
6400
Owen Taylor3473f882001-02-23 17:55:21 +00006401 SKIP_BLANKS;
6402 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006403 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006404 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006405
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006406#ifdef LIBXML_XPTR_ENABLED
6407 if (rangeto) {
6408 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
6409 } else
6410#endif
6411 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
6412 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006413
Owen Taylor3473f882001-02-23 17:55:21 +00006414 }
6415#ifdef DEBUG_STEP
6416 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006417 if (ctxt->value == NULL)
6418 xmlGenericError(xmlGenericErrorContext, "no value\n");
6419 else if (ctxt->value->nodesetval == NULL)
6420 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6421 else
6422 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6423 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006424#endif
6425}
6426
6427/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006428 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006429 * @ctxt: the XPath Parser context
6430 *
6431 * [3] RelativeLocationPath ::= Step
6432 * | RelativeLocationPath '/' Step
6433 * | AbbreviatedRelativeLocationPath
6434 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6435 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006436 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00006437 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006438static void
Owen Taylor3473f882001-02-23 17:55:21 +00006439#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006440xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006441#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006442xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006443#endif
6444(xmlXPathParserContextPtr ctxt) {
6445 SKIP_BLANKS;
6446 if ((CUR == '/') && (NXT(1) == '/')) {
6447 SKIP(2);
6448 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006449 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6450 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006451 } else if (CUR == '/') {
6452 NEXT;
6453 SKIP_BLANKS;
6454 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006455 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006456 SKIP_BLANKS;
6457 while (CUR == '/') {
6458 if ((CUR == '/') && (NXT(1) == '/')) {
6459 SKIP(2);
6460 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006461 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00006462 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006463 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006464 } else if (CUR == '/') {
6465 NEXT;
6466 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006467 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006468 }
6469 SKIP_BLANKS;
6470 }
6471}
6472
6473/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006474 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006475 * @ctxt: the XPath Parser context
6476 *
6477 * [1] LocationPath ::= RelativeLocationPath
6478 * | AbsoluteLocationPath
6479 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6480 * | AbbreviatedAbsoluteLocationPath
6481 * [10] AbbreviatedAbsoluteLocationPath ::=
6482 * '//' RelativeLocationPath
6483 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006484 * Compile a location path
6485 *
Owen Taylor3473f882001-02-23 17:55:21 +00006486 * // is short for /descendant-or-self::node()/. For example,
6487 * //para is short for /descendant-or-self::node()/child::para and
6488 * so will select any para element in the document (even a para element
6489 * that is a document element will be selected by //para since the
6490 * document element node is a child of the root node); div//para is
6491 * short for div/descendant-or-self::node()/child::para and so will
6492 * select all para descendants of div children.
6493 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006494static void
6495xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006496 SKIP_BLANKS;
6497 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006498 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006499 } else {
6500 while (CUR == '/') {
6501 if ((CUR == '/') && (NXT(1) == '/')) {
6502 SKIP(2);
6503 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006504 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6505 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006506 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006507 } else if (CUR == '/') {
6508 NEXT;
6509 SKIP_BLANKS;
6510 if (CUR != 0)
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006511 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006512 }
6513 }
6514 }
6515}
6516
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006517/************************************************************************
6518 * *
6519 * XPath precompiled expression evaluation *
6520 * *
6521 ************************************************************************/
6522
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006523static void
6524xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
6525
6526/**
6527 * xmlXPathNodeCollectAndTest:
6528 * @ctxt: the XPath Parser context
6529 * @op: the XPath precompiled step operation
6530 *
6531 * This is the function implementing a step: based on the current list
6532 * of nodes, it builds up a new list, looking at all nodes under that
6533 * axis and selecting them it also do the predicate filtering
6534 *
6535 * Pushes the new NodeSet resulting from the search.
6536 */
6537static void
6538xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
6539 xmlXPathStepOpPtr op) {
6540 xmlXPathAxisVal axis = op->value;
6541 xmlXPathTestVal test = op->value2;
6542 xmlXPathTypeVal type = op->value3;
6543 const xmlChar *prefix = op->value4;
6544 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006545 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006546
6547#ifdef DEBUG_STEP
6548 int n = 0, t = 0;
6549#endif
6550 int i;
6551 xmlNodeSetPtr ret, list;
6552 xmlXPathTraversalFunction next = NULL;
6553 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
6554 xmlNodePtr cur = NULL;
6555 xmlXPathObjectPtr obj;
6556 xmlNodeSetPtr nodelist;
6557 xmlNodePtr tmp;
6558
6559 CHECK_TYPE(XPATH_NODESET);
6560 obj = valuePop(ctxt);
6561 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006562 if (prefix != NULL) {
6563 URI = xmlXPathNsLookup(ctxt->context, prefix);
6564 if (URI == NULL)
6565 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
6566 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006567
6568#ifdef DEBUG_STEP
6569 xmlGenericError(xmlGenericErrorContext,
6570 "new step : ");
6571#endif
6572 switch (axis) {
6573 case AXIS_ANCESTOR:
6574#ifdef DEBUG_STEP
6575 xmlGenericError(xmlGenericErrorContext,
6576 "axis 'ancestors' ");
6577#endif
6578 next = xmlXPathNextAncestor; break;
6579 case AXIS_ANCESTOR_OR_SELF:
6580#ifdef DEBUG_STEP
6581 xmlGenericError(xmlGenericErrorContext,
6582 "axis 'ancestors-or-self' ");
6583#endif
6584 next = xmlXPathNextAncestorOrSelf; break;
6585 case AXIS_ATTRIBUTE:
6586#ifdef DEBUG_STEP
6587 xmlGenericError(xmlGenericErrorContext,
6588 "axis 'attributes' ");
6589#endif
6590 next = xmlXPathNextAttribute; break;
6591 break;
6592 case AXIS_CHILD:
6593#ifdef DEBUG_STEP
6594 xmlGenericError(xmlGenericErrorContext,
6595 "axis 'child' ");
6596#endif
6597 next = xmlXPathNextChild; break;
6598 case AXIS_DESCENDANT:
6599#ifdef DEBUG_STEP
6600 xmlGenericError(xmlGenericErrorContext,
6601 "axis 'descendant' ");
6602#endif
6603 next = xmlXPathNextDescendant; break;
6604 case AXIS_DESCENDANT_OR_SELF:
6605#ifdef DEBUG_STEP
6606 xmlGenericError(xmlGenericErrorContext,
6607 "axis 'descendant-or-self' ");
6608#endif
6609 next = xmlXPathNextDescendantOrSelf; break;
6610 case AXIS_FOLLOWING:
6611#ifdef DEBUG_STEP
6612 xmlGenericError(xmlGenericErrorContext,
6613 "axis 'following' ");
6614#endif
6615 next = xmlXPathNextFollowing; break;
6616 case AXIS_FOLLOWING_SIBLING:
6617#ifdef DEBUG_STEP
6618 xmlGenericError(xmlGenericErrorContext,
6619 "axis 'following-siblings' ");
6620#endif
6621 next = xmlXPathNextFollowingSibling; break;
6622 case AXIS_NAMESPACE:
6623#ifdef DEBUG_STEP
6624 xmlGenericError(xmlGenericErrorContext,
6625 "axis 'namespace' ");
6626#endif
6627 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
6628 break;
6629 case AXIS_PARENT:
6630#ifdef DEBUG_STEP
6631 xmlGenericError(xmlGenericErrorContext,
6632 "axis 'parent' ");
6633#endif
6634 next = xmlXPathNextParent; break;
6635 case AXIS_PRECEDING:
6636#ifdef DEBUG_STEP
6637 xmlGenericError(xmlGenericErrorContext,
6638 "axis 'preceding' ");
6639#endif
6640 next = xmlXPathNextPreceding; break;
6641 case AXIS_PRECEDING_SIBLING:
6642#ifdef DEBUG_STEP
6643 xmlGenericError(xmlGenericErrorContext,
6644 "axis 'preceding-sibling' ");
6645#endif
6646 next = xmlXPathNextPrecedingSibling; break;
6647 case AXIS_SELF:
6648#ifdef DEBUG_STEP
6649 xmlGenericError(xmlGenericErrorContext,
6650 "axis 'self' ");
6651#endif
6652 next = xmlXPathNextSelf; break;
6653 }
6654 if (next == NULL)
6655 return;
6656
6657 nodelist = obj->nodesetval;
6658 if (nodelist == NULL) {
6659 xmlXPathFreeObject(obj);
6660 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
6661 return;
6662 }
6663 addNode = xmlXPathNodeSetAddUnique;
6664 ret = NULL;
6665#ifdef DEBUG_STEP
6666 xmlGenericError(xmlGenericErrorContext,
6667 " context contains %d nodes\n",
6668 nodelist->nodeNr);
6669 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006670 case NODE_TEST_NONE:
6671 xmlGenericError(xmlGenericErrorContext,
6672 " searching for none !!!\n");
6673 break;
6674 case NODE_TEST_TYPE:
6675 xmlGenericError(xmlGenericErrorContext,
6676 " searching for type %d\n", type);
6677 break;
6678 case NODE_TEST_PI:
6679 xmlGenericError(xmlGenericErrorContext,
6680 " searching for PI !!!\n");
6681 break;
6682 case NODE_TEST_ALL:
6683 xmlGenericError(xmlGenericErrorContext,
6684 " searching for *\n");
6685 break;
6686 case NODE_TEST_NS:
6687 xmlGenericError(xmlGenericErrorContext,
6688 " searching for namespace %s\n",
6689 prefix);
6690 break;
6691 case NODE_TEST_NAME:
6692 xmlGenericError(xmlGenericErrorContext,
6693 " searching for name %s\n", name);
6694 if (prefix != NULL)
6695 xmlGenericError(xmlGenericErrorContext,
6696 " with namespace %s\n",
6697 prefix);
6698 break;
6699 }
6700 xmlGenericError(xmlGenericErrorContext, "Testing : ");
6701#endif
6702 /*
6703 * 2.3 Node Tests
6704 * - For the attribute axis, the principal node type is attribute.
6705 * - For the namespace axis, the principal node type is namespace.
6706 * - For other axes, the principal node type is element.
6707 *
6708 * A node test * is true for any node of the
6709 * principal node type. For example, child::* willi
6710 * select all element children of the context node
6711 */
6712 tmp = ctxt->context->node;
6713 for (i = 0;i < nodelist->nodeNr; i++) {
6714 ctxt->context->node = nodelist->nodeTab[i];
6715
6716 cur = NULL;
6717 list = xmlXPathNodeSetCreate(NULL);
6718 do {
6719 cur = next(ctxt, cur);
6720 if (cur == NULL) break;
6721#ifdef DEBUG_STEP
6722 t++;
6723 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
6724#endif
6725 switch (test) {
6726 case NODE_TEST_NONE:
6727 ctxt->context->node = tmp;
6728 STRANGE
6729 return;
6730 case NODE_TEST_TYPE:
6731 if ((cur->type == type) ||
6732 ((type == NODE_TYPE_NODE) &&
6733 ((cur->type == XML_DOCUMENT_NODE) ||
6734 (cur->type == XML_HTML_DOCUMENT_NODE) ||
6735 (cur->type == XML_ELEMENT_NODE) ||
6736 (cur->type == XML_PI_NODE) ||
6737 (cur->type == XML_COMMENT_NODE) ||
6738 (cur->type == XML_CDATA_SECTION_NODE) ||
6739 (cur->type == XML_TEXT_NODE)))) {
6740#ifdef DEBUG_STEP
6741 n++;
6742#endif
6743 addNode(list, cur);
6744 }
6745 break;
6746 case NODE_TEST_PI:
6747 if (cur->type == XML_PI_NODE) {
6748 if ((name != NULL) &&
6749 (!xmlStrEqual(name, cur->name)))
6750 break;
6751#ifdef DEBUG_STEP
6752 n++;
6753#endif
6754 addNode(list, cur);
6755 }
6756 break;
6757 case NODE_TEST_ALL:
6758 if (axis == AXIS_ATTRIBUTE) {
6759 if (cur->type == XML_ATTRIBUTE_NODE) {
6760#ifdef DEBUG_STEP
6761 n++;
6762#endif
6763 addNode(list, cur);
6764 }
6765 } else if (axis == AXIS_NAMESPACE) {
6766 if (cur->type == XML_NAMESPACE_DECL) {
6767#ifdef DEBUG_STEP
6768 n++;
6769#endif
6770 addNode(list, cur);
6771 }
6772 } else {
6773 if ((cur->type == XML_ELEMENT_NODE) ||
6774 (cur->type == XML_DOCUMENT_NODE) ||
6775 (cur->type == XML_HTML_DOCUMENT_NODE)) {
6776 if (prefix == NULL) {
6777#ifdef DEBUG_STEP
6778 n++;
6779#endif
6780 addNode(list, cur);
6781 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00006782 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006783 cur->ns->href))) {
6784#ifdef DEBUG_STEP
6785 n++;
6786#endif
6787 addNode(list, cur);
6788 }
6789 }
6790 }
6791 break;
6792 case NODE_TEST_NS: {
6793 TODO;
6794 break;
6795 }
6796 case NODE_TEST_NAME:
6797 switch (cur->type) {
6798 case XML_ELEMENT_NODE:
6799 if (xmlStrEqual(name, cur->name)) {
6800 if (prefix == NULL) {
6801 if ((cur->ns == NULL) ||
6802 (cur->ns->prefix == NULL)) {
6803#ifdef DEBUG_STEP
6804 n++;
6805#endif
6806 addNode(list, cur);
6807 }
6808 } else {
6809 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00006810 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006811 cur->ns->href))) {
6812#ifdef DEBUG_STEP
6813 n++;
6814#endif
6815 addNode(list, cur);
6816 }
6817 }
6818 }
6819 break;
6820 case XML_ATTRIBUTE_NODE: {
6821 xmlAttrPtr attr = (xmlAttrPtr) cur;
6822 if (xmlStrEqual(name, attr->name)) {
6823 if (prefix == NULL) {
6824 if ((attr->ns == NULL) ||
6825 (attr->ns->prefix == NULL)) {
6826#ifdef DEBUG_STEP
6827 n++;
6828#endif
6829 addNode(list, (xmlNodePtr) attr);
6830 }
6831 } else {
6832 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00006833 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006834 attr->ns->href))) {
6835#ifdef DEBUG_STEP
6836 n++;
6837#endif
6838 addNode(list, (xmlNodePtr) attr);
6839 }
6840 }
6841 }
6842 break;
6843 }
6844 case XML_NAMESPACE_DECL: {
6845 TODO;
6846 break;
6847 }
6848 default:
6849 break;
6850 }
6851 break;
6852 }
6853 } while (cur != NULL);
6854
6855 /*
6856 * If there is some predicate filtering do it now
6857 */
6858 if (op->ch2 != -1) {
6859 xmlXPathObjectPtr obj2;
6860
6861 valuePush(ctxt, xmlXPathWrapNodeSet(list));
6862 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
6863 CHECK_TYPE(XPATH_NODESET);
6864 obj2 = valuePop(ctxt);
6865 list = obj2->nodesetval;
6866 obj2->nodesetval = NULL;
6867 xmlXPathFreeObject(obj2);
6868 }
6869 if (ret == NULL) {
6870 ret = list;
6871 } else {
6872 ret = xmlXPathNodeSetMerge(ret, list);
6873 xmlXPathFreeNodeSet(list);
6874 }
6875 }
6876 ctxt->context->node = tmp;
6877#ifdef DEBUG_STEP
6878 xmlGenericError(xmlGenericErrorContext,
6879 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
6880#endif
6881 xmlXPathFreeObject(obj);
6882 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
6883}
6884
Owen Taylor3473f882001-02-23 17:55:21 +00006885/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006886 * xmlXPathCompOpEval:
6887 * @ctxt: the XPath parser context with the compiled expression
6888 * @op: an XPath compiled operation
6889 *
6890 * Evaluate the Precompiled XPath operation
6891 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006892static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006893xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
6894 int equal, ret;
6895 xmlXPathCompExprPtr comp;
6896 xmlXPathObjectPtr arg1, arg2;
6897
6898 comp = ctxt->comp;
6899 switch (op->op) {
6900 case XPATH_OP_END:
6901 return;
6902 case XPATH_OP_AND:
6903 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6904 xmlXPathBooleanFunction(ctxt, 1);
6905 if (ctxt->value->boolval == 0)
6906 return;
6907 arg2 = valuePop(ctxt);
6908 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6909 xmlXPathBooleanFunction(ctxt, 1);
6910 arg1 = valuePop(ctxt);
6911 arg1->boolval &= arg2->boolval;
6912 valuePush(ctxt, arg1);
6913 xmlXPathFreeObject(arg2);
6914 return;
6915 case XPATH_OP_OR:
6916 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6917 xmlXPathBooleanFunction(ctxt, 1);
6918 if (ctxt->value->boolval == 1)
6919 return;
6920 arg2 = valuePop(ctxt);
6921 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6922 xmlXPathBooleanFunction(ctxt, 1);
6923 arg1 = valuePop(ctxt);
6924 arg1->boolval |= arg2->boolval;
6925 valuePush(ctxt, arg1);
6926 xmlXPathFreeObject(arg2);
6927 return;
6928 case XPATH_OP_EQUAL:
6929 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6930 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6931 equal = xmlXPathEqualValues(ctxt);
6932 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
6933 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
6934 return;
6935 case XPATH_OP_CMP:
6936 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6937 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6938 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
6939 valuePush(ctxt, xmlXPathNewBoolean(ret));
6940 return;
6941 case XPATH_OP_PLUS:
6942 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6943 if (op->ch2 != -1)
6944 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6945 if (op->value == 0) xmlXPathSubValues(ctxt);
6946 else if (op->value == 1) xmlXPathAddValues(ctxt);
6947 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
6948 else if (op->value == 3) {
6949 xmlXPathObjectPtr arg;
6950
6951 POP_FLOAT
6952 valuePush(ctxt, arg);
6953 }
6954 return;
6955 case XPATH_OP_MULT:
6956 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6957 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6958 if (op->value == 0) xmlXPathMultValues(ctxt);
6959 else if (op->value == 1) xmlXPathDivValues(ctxt);
6960 else if (op->value == 2) xmlXPathModValues(ctxt);
6961 return;
6962 case XPATH_OP_UNION:
6963 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6964 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6965 CHECK_TYPE(XPATH_NODESET);
6966 arg2 = valuePop(ctxt);
6967
6968 CHECK_TYPE(XPATH_NODESET);
6969 arg1 = valuePop(ctxt);
6970
6971 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
6972 arg2->nodesetval);
6973 valuePush(ctxt, arg1);
6974 xmlXPathFreeObject(arg2);
6975 return;
6976 case XPATH_OP_ROOT:
6977 xmlXPathRoot(ctxt);
6978 return;
6979 case XPATH_OP_NODE:
6980 if (op->ch1 != -1)
6981 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6982 if (op->ch2 != -1)
6983 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6984 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6985 return;
6986 case XPATH_OP_RESET:
6987 if (op->ch1 != -1)
6988 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6989 if (op->ch2 != -1)
6990 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
6991 ctxt->context->node = NULL;
6992 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006993 case XPATH_OP_COLLECT: {
6994 if (op->ch1 == -1)
6995 return;
6996
6997 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
6998 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006999 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007000 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007001 case XPATH_OP_VALUE:
7002 valuePush(ctxt,
7003 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7004 return;
7005 case XPATH_OP_VARIABLE: {
7006 if (op->ch1 != -1)
7007 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7008 if (op->value5 == NULL)
7009 valuePush(ctxt,
7010 xmlXPathVariableLookup(ctxt->context, op->value4));
7011 else {
7012 const xmlChar *URI;
7013 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7014 if (URI == NULL) {
7015 xmlGenericError(xmlGenericErrorContext,
7016 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7017 op->value4, op->value5);
7018 return;
7019 }
7020 valuePush(ctxt,
7021 xmlXPathVariableLookupNS(ctxt->context,
7022 op->value4, URI));
7023 }
7024 return;
7025 }
7026 case XPATH_OP_FUNCTION: {
7027 xmlXPathFunction func;
7028
7029 if (op->ch1 != -1)
7030 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7031 if (op->value5 == NULL)
7032 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7033 else {
7034 const xmlChar *URI;
7035 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7036 if (URI == NULL) {
7037 xmlGenericError(xmlGenericErrorContext,
7038 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7039 op->value4, op->value5);
7040 return;
7041 }
7042 func = xmlXPathFunctionLookupNS(ctxt->context,
7043 op->value4, URI);
7044 }
7045 if (func == NULL) {
7046 xmlGenericError(xmlGenericErrorContext,
7047 "xmlXPathRunEval: function %s not found\n",
7048 op->value4);
7049 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
7050 return;
7051 }
7052 func(ctxt, op->value);
7053 return;
7054 }
7055 case XPATH_OP_ARG:
7056 if (op->ch1 != -1)
7057 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7058 if (op->ch2 != -1)
7059 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7060 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007061 case XPATH_OP_PREDICATE:
7062 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007063 xmlXPathObjectPtr res;
7064 xmlXPathObjectPtr obj, tmp;
7065 xmlNodeSetPtr newset = NULL;
7066 xmlNodeSetPtr oldset;
7067 xmlNodePtr oldnode;
7068 int i;
7069
7070 if (op->ch1 != -1)
7071 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7072 if (op->ch2 == -1)
7073 return;
7074
7075 oldnode = ctxt->context->node;
7076
7077#ifdef LIBXML_XPTR_ENABLED
7078 /*
7079 * Hum are we filtering the result of an XPointer expression
7080 */
7081 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007082 xmlLocationSetPtr newlocset = NULL;
7083 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007084
7085 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007086 * Extract the old locset, and then evaluate the result of the
7087 * expression for all the element in the locset. use it to grow
7088 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007089 */
7090 CHECK_TYPE(XPATH_LOCATIONSET);
7091 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007092 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007093 ctxt->context->node = NULL;
7094
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007095 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007096 ctxt->context->contextSize = 0;
7097 ctxt->context->proximityPosition = 0;
7098 if (op->ch2 != -1)
7099 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7100 res = valuePop(ctxt);
7101 if (res != NULL)
7102 xmlXPathFreeObject(res);
7103 valuePush(ctxt, obj);
7104 CHECK_ERROR;
7105 return;
7106 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007107 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007108
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007109 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007110 /*
7111 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007112 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007113 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007114 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007115 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7116 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007117 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007118 ctxt->context->proximityPosition = i + 1;
7119
7120 if (op->ch2 != -1)
7121 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7122 CHECK_ERROR;
7123
7124 /*
7125 * The result of the evaluation need to be tested to
7126 * decided whether the filter succeeded or not
7127 */
7128 res = valuePop(ctxt);
7129 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007130 xmlXPtrLocationSetAdd(newlocset,
7131 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007132 }
7133
7134 /*
7135 * Cleanup
7136 */
7137 if (res != NULL)
7138 xmlXPathFreeObject(res);
7139 if (ctxt->value == tmp) {
7140 res = valuePop(ctxt);
7141 xmlXPathFreeObject(res);
7142 }
7143
7144 ctxt->context->node = NULL;
7145 }
7146
7147 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007148 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007149 */
7150 xmlXPathFreeObject(obj);
7151 ctxt->context->node = NULL;
7152 ctxt->context->contextSize = -1;
7153 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007154 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007155 ctxt->context->node = oldnode;
7156 return;
7157 }
7158#endif /* LIBXML_XPTR_ENABLED */
7159
7160 /*
7161 * Extract the old set, and then evaluate the result of the
7162 * expression for all the element in the set. use it to grow
7163 * up a new set.
7164 */
7165 CHECK_TYPE(XPATH_NODESET);
7166 obj = valuePop(ctxt);
7167 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007168
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007169 oldnode = ctxt->context->node;
7170 ctxt->context->node = NULL;
7171
7172 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7173 ctxt->context->contextSize = 0;
7174 ctxt->context->proximityPosition = 0;
7175 if (op->ch2 != -1)
7176 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7177 res = valuePop(ctxt);
7178 if (res != NULL)
7179 xmlXPathFreeObject(res);
7180 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007181 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007182 CHECK_ERROR;
7183 } else {
7184 /*
7185 * Initialize the new set.
7186 */
7187 newset = xmlXPathNodeSetCreate(NULL);
7188
7189 for (i = 0; i < oldset->nodeNr; i++) {
7190 /*
7191 * Run the evaluation with a node list made of
7192 * a single item in the nodeset.
7193 */
7194 ctxt->context->node = oldset->nodeTab[i];
7195 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7196 valuePush(ctxt, tmp);
7197 ctxt->context->contextSize = oldset->nodeNr;
7198 ctxt->context->proximityPosition = i + 1;
7199
7200 if (op->ch2 != -1)
7201 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7202 CHECK_ERROR;
7203
7204 /*
7205 * The result of the evaluation need to be tested to
7206 * decided whether the filter succeeded or not
7207 */
7208 res = valuePop(ctxt);
7209 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7210 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7211 }
7212
7213 /*
7214 * Cleanup
7215 */
7216 if (res != NULL)
7217 xmlXPathFreeObject(res);
7218 if (ctxt->value == tmp) {
7219 res = valuePop(ctxt);
7220 xmlXPathFreeObject(res);
7221 }
7222
7223 ctxt->context->node = NULL;
7224 }
7225
7226 /*
7227 * The result is used as the new evaluation set.
7228 */
7229 xmlXPathFreeObject(obj);
7230 ctxt->context->node = NULL;
7231 ctxt->context->contextSize = -1;
7232 ctxt->context->proximityPosition = -1;
7233 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7234 }
7235 ctxt->context->node = oldnode;
7236 return;
7237 }
7238 case XPATH_OP_SORT:
7239 if (op->ch1 != -1)
7240 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7241 if ((ctxt->value != NULL) &&
7242 (ctxt->value->type == XPATH_NODESET) &&
7243 (ctxt->value->nodesetval != NULL))
7244 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7245 return;
7246#ifdef LIBXML_XPTR_ENABLED
7247 case XPATH_OP_RANGETO: {
7248 xmlXPathObjectPtr range;
7249 xmlXPathObjectPtr res, obj;
7250 xmlXPathObjectPtr tmp;
7251 xmlLocationSetPtr newset = NULL;
7252 xmlNodeSetPtr oldset;
7253 int i;
7254
7255 if (op->ch1 != -1)
7256 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7257 if (op->ch2 == -1)
7258 return;
7259
7260 CHECK_TYPE(XPATH_NODESET);
7261 obj = valuePop(ctxt);
7262 oldset = obj->nodesetval;
7263 ctxt->context->node = NULL;
7264
7265 newset = xmlXPtrLocationSetCreate(NULL);
7266
Daniel Veillard911f49a2001-04-07 15:39:35 +00007267 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007268 for (i = 0; i < oldset->nodeNr; i++) {
7269 /*
7270 * Run the evaluation with a node list made of a single item
7271 * in the nodeset.
7272 */
7273 ctxt->context->node = oldset->nodeTab[i];
7274 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7275 valuePush(ctxt, tmp);
7276
7277 if (op->ch2 != -1)
7278 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7279 CHECK_ERROR;
7280
7281 /*
7282 * The result of the evaluation need to be tested to
7283 * decided whether the filter succeeded or not
7284 */
7285 res = valuePop(ctxt);
7286 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7287 if (range != NULL) {
7288 xmlXPtrLocationSetAdd(newset, range);
7289 }
7290
7291 /*
7292 * Cleanup
7293 */
7294 if (res != NULL)
7295 xmlXPathFreeObject(res);
7296 if (ctxt->value == tmp) {
7297 res = valuePop(ctxt);
7298 xmlXPathFreeObject(res);
7299 }
7300
7301 ctxt->context->node = NULL;
7302 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007303 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007304
7305 /*
7306 * The result is used as the new evaluation set.
7307 */
7308 xmlXPathFreeObject(obj);
7309 ctxt->context->node = NULL;
7310 ctxt->context->contextSize = -1;
7311 ctxt->context->proximityPosition = -1;
7312 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7313 return;
7314 }
7315#endif /* LIBXML_XPTR_ENABLED */
7316 }
7317 xmlGenericError(xmlGenericErrorContext,
7318 "XPath: unknown precompiled operation %d\n",
7319 op->op);
7320 return;
7321}
7322
7323/**
7324 * xmlXPathRunEval:
7325 * @ctxt: the XPath parser context with the compiled expression
7326 *
7327 * Evaluate the Precompiled XPath expression in the given context.
7328 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007329static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007330xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7331 xmlXPathCompExprPtr comp;
7332
7333 if ((ctxt == NULL) || (ctxt->comp == NULL))
7334 return;
7335
7336 if (ctxt->valueTab == NULL) {
7337 /* Allocate the value stack */
7338 ctxt->valueTab = (xmlXPathObjectPtr *)
7339 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7340 if (ctxt->valueTab == NULL) {
7341 xmlFree(ctxt);
7342 xmlGenericError(xmlGenericErrorContext,
7343 "xmlXPathRunEval: out of memory\n");
7344 return;
7345 }
7346 ctxt->valueNr = 0;
7347 ctxt->valueMax = 10;
7348 ctxt->value = NULL;
7349 }
7350 comp = ctxt->comp;
7351 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7352}
7353
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007354/************************************************************************
7355 * *
7356 * Public interfaces *
7357 * *
7358 ************************************************************************/
7359
7360/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007361 * xmlXPathEvalPredicate:
7362 * @ctxt: the XPath context
7363 * @res: the Predicate Expression evaluation result
7364 *
7365 * Evaluate a predicate result for the current node.
7366 * A PredicateExpr is evaluated by evaluating the Expr and converting
7367 * the result to a boolean. If the result is a number, the result will
7368 * be converted to true if the number is equal to the position of the
7369 * context node in the context node list (as returned by the position
7370 * function) and will be converted to false otherwise; if the result
7371 * is not a number, then the result will be converted as if by a call
7372 * to the boolean function.
7373 *
7374 * Return 1 if predicate is true, 0 otherwise
7375 */
7376int
7377xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7378 if (res == NULL) return(0);
7379 switch (res->type) {
7380 case XPATH_BOOLEAN:
7381 return(res->boolval);
7382 case XPATH_NUMBER:
7383 return(res->floatval == ctxt->proximityPosition);
7384 case XPATH_NODESET:
7385 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007386 if (res->nodesetval == NULL)
7387 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007388 return(res->nodesetval->nodeNr != 0);
7389 case XPATH_STRING:
7390 return((res->stringval != NULL) &&
7391 (xmlStrlen(res->stringval) != 0));
7392 default:
7393 STRANGE
7394 }
7395 return(0);
7396}
7397
7398/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007399 * xmlXPathEvaluatePredicateResult:
7400 * @ctxt: the XPath Parser context
7401 * @res: the Predicate Expression evaluation result
7402 *
7403 * Evaluate a predicate result for the current node.
7404 * A PredicateExpr is evaluated by evaluating the Expr and converting
7405 * the result to a boolean. If the result is a number, the result will
7406 * be converted to true if the number is equal to the position of the
7407 * context node in the context node list (as returned by the position
7408 * function) and will be converted to false otherwise; if the result
7409 * is not a number, then the result will be converted as if by a call
7410 * to the boolean function.
7411 *
7412 * Return 1 if predicate is true, 0 otherwise
7413 */
7414int
7415xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
7416 xmlXPathObjectPtr res) {
7417 if (res == NULL) return(0);
7418 switch (res->type) {
7419 case XPATH_BOOLEAN:
7420 return(res->boolval);
7421 case XPATH_NUMBER:
7422 return(res->floatval == ctxt->context->proximityPosition);
7423 case XPATH_NODESET:
7424 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00007425 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00007426 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007427 return(res->nodesetval->nodeNr != 0);
7428 case XPATH_STRING:
7429 return((res->stringval != NULL) &&
7430 (xmlStrlen(res->stringval) != 0));
7431 default:
7432 STRANGE
7433 }
7434 return(0);
7435}
7436
7437/**
7438 * xmlXPathCompile:
7439 * @str: the XPath expression
7440 *
7441 * Compile an XPath expression
7442 *
7443 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7444 * the caller has to free the object.
7445 */
7446xmlXPathCompExprPtr
7447xmlXPathCompile(const xmlChar *str) {
7448 xmlXPathParserContextPtr ctxt;
7449 xmlXPathCompExprPtr comp;
7450
7451 xmlXPathInit();
7452
7453 ctxt = xmlXPathNewParserContext(str, NULL);
7454 xmlXPathCompileExpr(ctxt);
7455
Daniel Veillard40af6492001-04-22 08:50:55 +00007456 if (*ctxt->cur != 0) {
7457 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7458 comp = NULL;
7459 } else {
7460 comp = ctxt->comp;
7461 ctxt->comp = NULL;
7462 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007463 xmlXPathFreeParserContext(ctxt);
7464 return(comp);
7465}
7466
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007467/**
7468 * xmlXPathCompiledEval:
7469 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00007470 * @ctx: the XPath context
7471 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007472 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00007473 *
7474 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7475 * the caller has to free the object.
7476 */
7477xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007478xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00007479 xmlXPathParserContextPtr ctxt;
7480 xmlXPathObjectPtr res, tmp, init = NULL;
7481 int stack = 0;
7482
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007483 if ((comp == NULL) || (ctx == NULL))
7484 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007485 xmlXPathInit();
7486
7487 CHECK_CONTEXT(ctx)
7488
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007489 ctxt = xmlXPathCompParserContext(comp, ctx);
7490 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007491
7492 if (ctxt->value == NULL) {
7493 xmlGenericError(xmlGenericErrorContext,
7494 "xmlXPathEval: evaluation failed\n");
7495 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007496 } else {
7497 res = valuePop(ctxt);
7498 }
7499
7500 do {
7501 tmp = valuePop(ctxt);
7502 if (tmp != NULL) {
7503 if (tmp != init)
7504 stack++;
7505 xmlXPathFreeObject(tmp);
7506 }
7507 } while (tmp != NULL);
7508 if ((stack != 0) && (res != NULL)) {
7509 xmlGenericError(xmlGenericErrorContext,
7510 "xmlXPathEval: %d object left on the stack\n",
7511 stack);
7512 }
7513 if (ctxt->error != XPATH_EXPRESSION_OK) {
7514 xmlXPathFreeObject(res);
7515 res = NULL;
7516 }
7517
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007518
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007519 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007520 xmlXPathFreeParserContext(ctxt);
7521 return(res);
7522}
7523
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007524/**
7525 * xmlXPathEvalExpr:
7526 * @ctxt: the XPath Parser context
7527 *
7528 * Parse and evaluate an XPath expression in the given context,
7529 * then push the result on the context stack
7530 */
7531void
7532xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
7533 xmlXPathCompileExpr(ctxt);
7534 xmlXPathRunEval(ctxt);
7535}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007536
7537/**
7538 * xmlXPathEval:
7539 * @str: the XPath expression
7540 * @ctx: the XPath context
7541 *
7542 * Evaluate the XPath Location Path in the given context.
7543 *
7544 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7545 * the caller has to free the object.
7546 */
7547xmlXPathObjectPtr
7548xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
7549 xmlXPathParserContextPtr ctxt;
7550 xmlXPathObjectPtr res, tmp, init = NULL;
7551 int stack = 0;
7552
7553 xmlXPathInit();
7554
7555 CHECK_CONTEXT(ctx)
7556
7557 ctxt = xmlXPathNewParserContext(str, ctx);
7558 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007559
7560 if (ctxt->value == NULL) {
7561 xmlGenericError(xmlGenericErrorContext,
7562 "xmlXPathEval: evaluation failed\n");
7563 res = NULL;
7564 } else if (*ctxt->cur != 0) {
7565 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7566 res = NULL;
7567 } else {
7568 res = valuePop(ctxt);
7569 }
7570
7571 do {
7572 tmp = valuePop(ctxt);
7573 if (tmp != NULL) {
7574 if (tmp != init)
7575 stack++;
7576 xmlXPathFreeObject(tmp);
7577 }
7578 } while (tmp != NULL);
7579 if ((stack != 0) && (res != NULL)) {
7580 xmlGenericError(xmlGenericErrorContext,
7581 "xmlXPathEval: %d object left on the stack\n",
7582 stack);
7583 }
7584 if (ctxt->error != XPATH_EXPRESSION_OK) {
7585 xmlXPathFreeObject(res);
7586 res = NULL;
7587 }
7588
Owen Taylor3473f882001-02-23 17:55:21 +00007589 xmlXPathFreeParserContext(ctxt);
7590 return(res);
7591}
7592
7593/**
7594 * xmlXPathEvalExpression:
7595 * @str: the XPath expression
7596 * @ctxt: the XPath context
7597 *
7598 * Evaluate the XPath expression in the given context.
7599 *
7600 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
7601 * the caller has to free the object.
7602 */
7603xmlXPathObjectPtr
7604xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
7605 xmlXPathParserContextPtr pctxt;
7606 xmlXPathObjectPtr res, tmp;
7607 int stack = 0;
7608
7609 xmlXPathInit();
7610
7611 CHECK_CONTEXT(ctxt)
7612
7613 pctxt = xmlXPathNewParserContext(str, ctxt);
7614 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007615
7616 if (*pctxt->cur != 0) {
7617 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7618 res = NULL;
7619 } else {
7620 res = valuePop(pctxt);
7621 }
7622 do {
7623 tmp = valuePop(pctxt);
7624 if (tmp != NULL) {
7625 xmlXPathFreeObject(tmp);
7626 stack++;
7627 }
7628 } while (tmp != NULL);
7629 if ((stack != 0) && (res != NULL)) {
7630 xmlGenericError(xmlGenericErrorContext,
7631 "xmlXPathEvalExpression: %d object left on the stack\n",
7632 stack);
7633 }
7634 xmlXPathFreeParserContext(pctxt);
7635 return(res);
7636}
7637
7638/**
7639 * xmlXPathRegisterAllFunctions:
7640 * @ctxt: the XPath context
7641 *
7642 * Registers all default XPath functions in this context
7643 */
7644void
7645xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
7646{
7647 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
7648 xmlXPathBooleanFunction);
7649 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
7650 xmlXPathCeilingFunction);
7651 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
7652 xmlXPathCountFunction);
7653 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
7654 xmlXPathConcatFunction);
7655 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
7656 xmlXPathContainsFunction);
7657 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
7658 xmlXPathIdFunction);
7659 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
7660 xmlXPathFalseFunction);
7661 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
7662 xmlXPathFloorFunction);
7663 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
7664 xmlXPathLastFunction);
7665 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
7666 xmlXPathLangFunction);
7667 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
7668 xmlXPathLocalNameFunction);
7669 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
7670 xmlXPathNotFunction);
7671 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
7672 xmlXPathNameFunction);
7673 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
7674 xmlXPathNamespaceURIFunction);
7675 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
7676 xmlXPathNormalizeFunction);
7677 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
7678 xmlXPathNumberFunction);
7679 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
7680 xmlXPathPositionFunction);
7681 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
7682 xmlXPathRoundFunction);
7683 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
7684 xmlXPathStringFunction);
7685 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
7686 xmlXPathStringLengthFunction);
7687 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
7688 xmlXPathStartsWithFunction);
7689 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
7690 xmlXPathSubstringFunction);
7691 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
7692 xmlXPathSubstringBeforeFunction);
7693 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
7694 xmlXPathSubstringAfterFunction);
7695 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
7696 xmlXPathSumFunction);
7697 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
7698 xmlXPathTrueFunction);
7699 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
7700 xmlXPathTranslateFunction);
7701}
7702
7703#endif /* LIBXML_XPATH_ENABLED */