blob: 5c83a8d8f87b92c2327cf8b23d0da9b9e7abc2b3 [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
Daniel Veillard5792e162001-04-30 17:44:45 +000042#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000043#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000044#endif
Owen Taylor3473f882001-02-23 17:55:21 +000045
46#include <libxml/xmlmemory.h>
47#include <libxml/tree.h>
48#include <libxml/valid.h>
49#include <libxml/xpath.h>
50#include <libxml/xpathInternals.h>
51#include <libxml/parserInternals.h>
52#include <libxml/hash.h>
53#ifdef LIBXML_XPTR_ENABLED
54#include <libxml/xpointer.h>
55#endif
56#ifdef LIBXML_DEBUG_ENABLED
57#include <libxml/debugXML.h>
58#endif
59#include <libxml/xmlerror.h>
60
61/* #define DEBUG */
62/* #define DEBUG_STEP */
63/* #define DEBUG_EXPR */
64
65void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
66double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000067double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000068
Daniel Veillard9e7160d2001-03-18 23:17:47 +000069/************************************************************************
70 * *
71 * Floating point stuff *
72 * *
73 ************************************************************************/
74
Owen Taylor3473f882001-02-23 17:55:21 +000075/*
Owen Taylor3473f882001-02-23 17:55:21 +000076 * The lack of portability of this section of the libc is annoying !
77 */
78double xmlXPathNAN = 0;
79double xmlXPathPINF = 1;
80double xmlXPathNINF = -1;
81
82#ifndef isinf
83#ifndef HAVE_ISINF
84
85#if HAVE_FPCLASS
86
87int isinf(double d) {
88 fpclass_t type = fpclass(d);
89 switch (type) {
90 case FP_NINF:
91 return(-1);
92 case FP_PINF:
93 return(1);
94 }
95 return(0);
96}
97
98#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
99
100#if HAVE_FP_CLASS_H
101#include <fp_class.h>
102#endif
103
104int isinf(double d) {
105#if HAVE_FP_CLASS
106 int fpclass = fp_class(d);
107#else
108 int fpclass = fp_class_d(d);
109#endif
110 if (fpclass == FP_POS_INF)
111 return(1);
112 if (fpclass == FP_NEG_INF)
113 return(-1);
114 return(0);
115}
116
117#elif defined(HAVE_CLASS)
118
119int isinf(double d) {
120 int fpclass = class(d);
121 if (fpclass == FP_PLUS_INF)
122 return(1);
123 if (fpclass == FP_MINUS_INF)
124 return(-1);
125 return(0);
126}
127#elif defined(finite) || defined(HAVE_FINITE)
128int isinf(double x) { return !finite(x) && x==x; }
129#elif defined(HUGE_VAL)
130int isinf(double x)
131{
132 if (x == HUGE_VAL)
133 return(1);
134 if (x == -HUGE_VAL)
135 return(-1);
136 return(0);
137}
138#endif
139
140#endif /* ! HAVE_ISINF */
141#endif /* ! defined(isinf) */
142
143#ifndef isnan
144#ifndef HAVE_ISNAN
145
146#ifdef HAVE_ISNAND
147#define isnan(f) isnand(f)
148#endif /* HAVE_iSNAND */
149
150#endif /* ! HAVE_iSNAN */
151#endif /* ! defined(isnan) */
152
Daniel Veillard5792e162001-04-30 17:44:45 +0000153
154/**
155 * xmlXPathDivideBy:
156 *
157 * The best way found so far to generate the NAN, +-INF
158 * without hitting a compiler bug or optimization :-\
159 *
160 * Returns the double resulting from the division
161 */
162double
163xmlXPathDivideBy(double f, double fzero) {
164 float ret;
165#ifdef HAVE_SIGNAL
166#ifdef SIGFPE
167#ifdef SIG_IGN
168 void (*sighandler)(int);
169 sighandler = signal(SIGFPE, SIG_IGN);
170#endif
171#endif
172#endif
173 ret = f / fzero;
174#ifdef HAVE_SIGNAL
175#ifdef SIGFPE
176#ifdef SIG_IGN
177 signal(SIGFPE, sighandler);
178#endif
179#endif
180#endif
181 return(ret);
182}
183
Owen Taylor3473f882001-02-23 17:55:21 +0000184/**
185 * xmlXPathInit:
186 *
187 * Initialize the XPath environment
188 */
189void
190xmlXPathInit(void) {
191 static int initialized = 0;
192
193 if (initialized) return;
194
Daniel Veillard5792e162001-04-30 17:44:45 +0000195 xmlXPathNAN = xmlXPathDivideBy(0.0, 0.0);
196 xmlXPathPINF = xmlXPathDivideBy(1.0, 0.0);
197 xmlXPathPINF = xmlXPathDivideBy(-1.0, 0.0);
Owen Taylor3473f882001-02-23 17:55:21 +0000198
199 initialized = 1;
200}
201
202/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000203 * *
204 * Parser Types *
205 * *
206 ************************************************************************/
207
208/*
209 * Types are private:
210 */
211
212typedef enum {
213 XPATH_OP_END=0,
214 XPATH_OP_AND,
215 XPATH_OP_OR,
216 XPATH_OP_EQUAL,
217 XPATH_OP_CMP,
218 XPATH_OP_PLUS,
219 XPATH_OP_MULT,
220 XPATH_OP_UNION,
221 XPATH_OP_ROOT,
222 XPATH_OP_NODE,
223 XPATH_OP_RESET,
224 XPATH_OP_COLLECT,
225 XPATH_OP_VALUE,
226 XPATH_OP_VARIABLE,
227 XPATH_OP_FUNCTION,
228 XPATH_OP_ARG,
229 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000230 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000231 XPATH_OP_SORT
232#ifdef LIBXML_XPTR_ENABLED
233 ,XPATH_OP_RANGETO
234#endif
235} xmlXPathOp;
236
237typedef enum {
238 AXIS_ANCESTOR = 1,
239 AXIS_ANCESTOR_OR_SELF,
240 AXIS_ATTRIBUTE,
241 AXIS_CHILD,
242 AXIS_DESCENDANT,
243 AXIS_DESCENDANT_OR_SELF,
244 AXIS_FOLLOWING,
245 AXIS_FOLLOWING_SIBLING,
246 AXIS_NAMESPACE,
247 AXIS_PARENT,
248 AXIS_PRECEDING,
249 AXIS_PRECEDING_SIBLING,
250 AXIS_SELF
251} xmlXPathAxisVal;
252
253typedef enum {
254 NODE_TEST_NONE = 0,
255 NODE_TEST_TYPE = 1,
256 NODE_TEST_PI = 2,
257 NODE_TEST_ALL = 3,
258 NODE_TEST_NS = 4,
259 NODE_TEST_NAME = 5
260} xmlXPathTestVal;
261
262typedef enum {
263 NODE_TYPE_NODE = 0,
264 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
265 NODE_TYPE_TEXT = XML_TEXT_NODE,
266 NODE_TYPE_PI = XML_PI_NODE
267} xmlXPathTypeVal;
268
269
270typedef struct _xmlXPathStepOp xmlXPathStepOp;
271typedef xmlXPathStepOp *xmlXPathStepOpPtr;
272struct _xmlXPathStepOp {
273 xmlXPathOp op;
274 int ch1;
275 int ch2;
276 int value;
277 int value2;
278 int value3;
279 void *value4;
280 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000281 void *cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000282};
283
284struct _xmlXPathCompExpr {
285 int nbStep;
286 int maxStep;
287 xmlXPathStepOp *steps; /* ops for computation */
288 int last;
289};
290
291/************************************************************************
292 * *
293 * Parser Type functions *
294 * *
295 ************************************************************************/
296
297/**
298 * xmlXPathNewCompExpr:
299 *
300 * Create a new Xpath component
301 *
302 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
303 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000304static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000305xmlXPathNewCompExpr(void) {
306 xmlXPathCompExprPtr cur;
307
308 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
309 if (cur == NULL) {
310 xmlGenericError(xmlGenericErrorContext,
311 "xmlXPathNewCompExpr : malloc failed\n");
312 return(NULL);
313 }
314 memset(cur, 0, sizeof(xmlXPathCompExpr));
315 cur->maxStep = 10;
316 cur->nbStep = 0;
317 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
318 sizeof(xmlXPathStepOp));
319 if (cur->steps == NULL) {
320 xmlGenericError(xmlGenericErrorContext,
321 "xmlXPathNewCompExpr : malloc failed\n");
322 xmlFree(cur);
323 return(NULL);
324 }
325 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
326 cur->last = -1;
327 return(cur);
328}
329
330/**
331 * xmlXPathFreeCompExpr:
332 * @comp: an XPATH comp
333 *
334 * Free up the memory allocated by @comp
335 */
336void
337xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) {
338 xmlXPathStepOpPtr op;
339 int i;
340
341 if (comp == NULL)
342 return;
343 for (i = 0;i < comp->nbStep;i++) {
344 op = &comp->steps[i];
345 if (op->value4 != NULL) {
346 if (op->op == XPATH_OP_VALUE)
347 xmlXPathFreeObject(op->value4);
348 else
349 xmlFree(op->value4);
350 }
351 if (op->value5 != NULL)
352 xmlFree(op->value5);
353 }
354 if (comp->steps != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000355 xmlFree(comp->steps);
356 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000357 xmlFree(comp);
358}
359
360/**
361 * xmlXPathCompExprAdd:
362 * @comp: the compiled expression
363 * @ch1: first child index
364 * @ch2: second child index
365 * @op: an op
366 * @value: the first int value
367 * @value2: the second int value
368 * @value3: the third int value
369 * @value4: the first string value
370 * @value5: the second string value
371 *
372 * Add an step to an XPath Compiled Expression
373 *
374 * Returns -1 in case of failure, the index otherwise
375 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000376static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000377xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
378 xmlXPathOp op, int value,
379 int value2, int value3, void *value4, void *value5) {
380 if (comp->nbStep >= comp->maxStep) {
381 xmlXPathStepOp *real;
382
383 comp->maxStep *= 2;
384 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
385 comp->maxStep * sizeof(xmlXPathStepOp));
386 if (real == NULL) {
387 comp->maxStep /= 2;
388 xmlGenericError(xmlGenericErrorContext,
389 "xmlXPathCompExprAdd : realloc failed\n");
390 return(-1);
391 }
392 comp->steps = real;
393 }
394 comp->last = comp->nbStep;
395 comp->steps[comp->nbStep].ch1 = ch1;
396 comp->steps[comp->nbStep].ch2 = ch2;
397 comp->steps[comp->nbStep].op = op;
398 comp->steps[comp->nbStep].value = value;
399 comp->steps[comp->nbStep].value2 = value2;
400 comp->steps[comp->nbStep].value3 = value3;
401 comp->steps[comp->nbStep].value4 = value4;
402 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000403 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000404 return(comp->nbStep++);
405}
406
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000407#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
408 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
409 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000410#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
411 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
412 (op), (val), (val2), (val3), (val4), (val5))
413
414#define PUSH_LEAVE_EXPR(op, val, val2) \
415xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
416
417#define PUSH_UNARY_EXPR(op, ch, val, val2) \
418xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
419
420#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
421xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
422
423/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000424 * *
425 * Debugging related functions *
426 * *
427 ************************************************************************/
428
429#define TODO \
430 xmlGenericError(xmlGenericErrorContext, \
431 "Unimplemented block at %s:%d\n", \
432 __FILE__, __LINE__);
433
434#define STRANGE \
435 xmlGenericError(xmlGenericErrorContext, \
436 "Internal error at %s:%d\n", \
437 __FILE__, __LINE__);
438
439#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000440static void
441xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000442 int i;
443 char shift[100];
444
445 for (i = 0;((i < depth) && (i < 25));i++)
446 shift[2 * i] = shift[2 * i + 1] = ' ';
447 shift[2 * i] = shift[2 * i + 1] = 0;
448 if (cur == NULL) {
449 fprintf(output, shift);
450 fprintf(output, "Node is NULL !\n");
451 return;
452
453 }
454
455 if ((cur->type == XML_DOCUMENT_NODE) ||
456 (cur->type == XML_HTML_DOCUMENT_NODE)) {
457 fprintf(output, shift);
458 fprintf(output, " /\n");
459 } else if (cur->type == XML_ATTRIBUTE_NODE)
460 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
461 else
462 xmlDebugDumpOneNode(output, cur, depth);
463}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000464static void
465xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000466 xmlNodePtr tmp;
467 int i;
468 char shift[100];
469
470 for (i = 0;((i < depth) && (i < 25));i++)
471 shift[2 * i] = shift[2 * i + 1] = ' ';
472 shift[2 * i] = shift[2 * i + 1] = 0;
473 if (cur == NULL) {
474 fprintf(output, shift);
475 fprintf(output, "Node is NULL !\n");
476 return;
477
478 }
479
480 while (cur != NULL) {
481 tmp = cur;
482 cur = cur->next;
483 xmlDebugDumpOneNode(output, tmp, depth);
484 }
485}
Owen Taylor3473f882001-02-23 17:55:21 +0000486
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000487static void
488xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000489 int i;
490 char shift[100];
491
492 for (i = 0;((i < depth) && (i < 25));i++)
493 shift[2 * i] = shift[2 * i + 1] = ' ';
494 shift[2 * i] = shift[2 * i + 1] = 0;
495
496 if (cur == NULL) {
497 fprintf(output, shift);
498 fprintf(output, "NodeSet is NULL !\n");
499 return;
500
501 }
502
Daniel Veillard911f49a2001-04-07 15:39:35 +0000503 if (cur != NULL) {
504 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
505 for (i = 0;i < cur->nodeNr;i++) {
506 fprintf(output, shift);
507 fprintf(output, "%d", i + 1);
508 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
509 }
Owen Taylor3473f882001-02-23 17:55:21 +0000510 }
511}
512
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000513static void
514xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000515 int i;
516 char shift[100];
517
518 for (i = 0;((i < depth) && (i < 25));i++)
519 shift[2 * i] = shift[2 * i + 1] = ' ';
520 shift[2 * i] = shift[2 * i + 1] = 0;
521
522 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
523 fprintf(output, shift);
524 fprintf(output, "Value Tree is NULL !\n");
525 return;
526
527 }
528
529 fprintf(output, shift);
530 fprintf(output, "%d", i + 1);
531 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
532}
Owen Taylor3473f882001-02-23 17:55:21 +0000533#if defined(LIBXML_XPTR_ENABLED)
534void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000535static void
536xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000537 int i;
538 char shift[100];
539
540 for (i = 0;((i < depth) && (i < 25));i++)
541 shift[2 * i] = shift[2 * i + 1] = ' ';
542 shift[2 * i] = shift[2 * i + 1] = 0;
543
544 if (cur == NULL) {
545 fprintf(output, shift);
546 fprintf(output, "LocationSet is NULL !\n");
547 return;
548
549 }
550
551 for (i = 0;i < cur->locNr;i++) {
552 fprintf(output, shift);
553 fprintf(output, "%d : ", i + 1);
554 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
555 }
556}
557#endif
558
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000559/**
560 * xmlXPathDebugDumpObject:
561 * @output: the FILE * to dump the output
562 * @cur: the object to inspect
563 * @depth: indentation level
564 *
565 * Dump the content of the object for debugging purposes
566 */
567void
568xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000569 int i;
570 char shift[100];
571
572 for (i = 0;((i < depth) && (i < 25));i++)
573 shift[2 * i] = shift[2 * i + 1] = ' ';
574 shift[2 * i] = shift[2 * i + 1] = 0;
575
576 fprintf(output, shift);
577
578 if (cur == NULL) {
579 fprintf(output, "Object is empty (NULL)\n");
580 return;
581 }
582 switch(cur->type) {
583 case XPATH_UNDEFINED:
584 fprintf(output, "Object is uninitialized\n");
585 break;
586 case XPATH_NODESET:
587 fprintf(output, "Object is a Node Set :\n");
588 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
589 break;
590 case XPATH_XSLT_TREE:
591 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000592 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000593 break;
594 case XPATH_BOOLEAN:
595 fprintf(output, "Object is a Boolean : ");
596 if (cur->boolval) fprintf(output, "true\n");
597 else fprintf(output, "false\n");
598 break;
599 case XPATH_NUMBER:
600 fprintf(output, "Object is a number : %0g\n", cur->floatval);
601 break;
602 case XPATH_STRING:
603 fprintf(output, "Object is a string : ");
604 xmlDebugDumpString(output, cur->stringval);
605 fprintf(output, "\n");
606 break;
607 case XPATH_POINT:
608 fprintf(output, "Object is a point : index %d in node", cur->index);
609 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
610 fprintf(output, "\n");
611 break;
612 case XPATH_RANGE:
613 if ((cur->user2 == NULL) ||
614 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
615 fprintf(output, "Object is a collapsed range :\n");
616 fprintf(output, shift);
617 if (cur->index >= 0)
618 fprintf(output, "index %d in ", cur->index);
619 fprintf(output, "node\n");
620 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
621 depth + 1);
622 } else {
623 fprintf(output, "Object is a range :\n");
624 fprintf(output, shift);
625 fprintf(output, "From ");
626 if (cur->index >= 0)
627 fprintf(output, "index %d in ", cur->index);
628 fprintf(output, "node\n");
629 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
630 depth + 1);
631 fprintf(output, shift);
632 fprintf(output, "To ");
633 if (cur->index2 >= 0)
634 fprintf(output, "index %d in ", cur->index2);
635 fprintf(output, "node\n");
636 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
637 depth + 1);
638 fprintf(output, "\n");
639 }
640 break;
641 case XPATH_LOCATIONSET:
642#if defined(LIBXML_XPTR_ENABLED)
643 fprintf(output, "Object is a Location Set:\n");
644 xmlXPathDebugDumpLocationSet(output,
645 (xmlLocationSetPtr) cur->user, depth);
646#endif
647 break;
648 case XPATH_USERS:
649 fprintf(output, "Object is user defined\n");
650 break;
651 }
652}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000653
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000654static void
655xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000656 xmlXPathStepOpPtr op, int depth) {
657 int i;
658 char shift[100];
659
660 for (i = 0;((i < depth) && (i < 25));i++)
661 shift[2 * i] = shift[2 * i + 1] = ' ';
662 shift[2 * i] = shift[2 * i + 1] = 0;
663
664 fprintf(output, shift);
665 if (op == NULL) {
666 fprintf(output, "Step is NULL\n");
667 return;
668 }
669 switch (op->op) {
670 case XPATH_OP_END:
671 fprintf(output, "END"); break;
672 case XPATH_OP_AND:
673 fprintf(output, "AND"); break;
674 case XPATH_OP_OR:
675 fprintf(output, "OR"); break;
676 case XPATH_OP_EQUAL:
677 if (op->value)
678 fprintf(output, "EQUAL =");
679 else
680 fprintf(output, "EQUAL !=");
681 break;
682 case XPATH_OP_CMP:
683 if (op->value)
684 fprintf(output, "CMP <");
685 else
686 fprintf(output, "CMP >");
687 if (!op->value2)
688 fprintf(output, "=");
689 break;
690 case XPATH_OP_PLUS:
691 if (op->value == 0)
692 fprintf(output, "PLUS -");
693 else if (op->value == 1)
694 fprintf(output, "PLUS +");
695 else if (op->value == 2)
696 fprintf(output, "PLUS unary -");
697 else if (op->value == 3)
698 fprintf(output, "PLUS unary - -");
699 break;
700 case XPATH_OP_MULT:
701 if (op->value == 0)
702 fprintf(output, "MULT *");
703 else if (op->value == 1)
704 fprintf(output, "MULT div");
705 else
706 fprintf(output, "MULT mod");
707 break;
708 case XPATH_OP_UNION:
709 fprintf(output, "UNION"); break;
710 case XPATH_OP_ROOT:
711 fprintf(output, "ROOT"); break;
712 case XPATH_OP_NODE:
713 fprintf(output, "NODE"); break;
714 case XPATH_OP_RESET:
715 fprintf(output, "RESET"); break;
716 case XPATH_OP_SORT:
717 fprintf(output, "SORT"); break;
718 case XPATH_OP_COLLECT: {
719 xmlXPathAxisVal axis = op->value;
720 xmlXPathTestVal test = op->value2;
721 xmlXPathTypeVal type = op->value3;
722 const xmlChar *prefix = op->value4;
723 const xmlChar *name = op->value5;
724
725 fprintf(output, "COLLECT ");
726 switch (axis) {
727 case AXIS_ANCESTOR:
728 fprintf(output, " 'ancestors' "); break;
729 case AXIS_ANCESTOR_OR_SELF:
730 fprintf(output, " 'ancestors-or-self' "); break;
731 case AXIS_ATTRIBUTE:
732 fprintf(output, " 'attributes' "); break;
733 case AXIS_CHILD:
734 fprintf(output, " 'child' "); break;
735 case AXIS_DESCENDANT:
736 fprintf(output, " 'descendant' "); break;
737 case AXIS_DESCENDANT_OR_SELF:
738 fprintf(output, " 'descendant-or-self' "); break;
739 case AXIS_FOLLOWING:
740 fprintf(output, " 'following' "); break;
741 case AXIS_FOLLOWING_SIBLING:
742 fprintf(output, " 'following-siblings' "); break;
743 case AXIS_NAMESPACE:
744 fprintf(output, " 'namespace' "); break;
745 case AXIS_PARENT:
746 fprintf(output, " 'parent' "); break;
747 case AXIS_PRECEDING:
748 fprintf(output, " 'preceding' "); break;
749 case AXIS_PRECEDING_SIBLING:
750 fprintf(output, " 'preceding-sibling' "); break;
751 case AXIS_SELF:
752 fprintf(output, " 'self' "); break;
753 }
754 switch (test) {
755 case NODE_TEST_NONE:
756 fprintf(output, "'none' "); break;
757 case NODE_TEST_TYPE:
758 fprintf(output, "'type' "); break;
759 case NODE_TEST_PI:
760 fprintf(output, "'PI' "); break;
761 case NODE_TEST_ALL:
762 fprintf(output, "'all' "); break;
763 case NODE_TEST_NS:
764 fprintf(output, "'namespace' "); break;
765 case NODE_TEST_NAME:
766 fprintf(output, "'name' "); break;
767 }
768 switch (type) {
769 case NODE_TYPE_NODE:
770 fprintf(output, "'node' "); break;
771 case NODE_TYPE_COMMENT:
772 fprintf(output, "'comment' "); break;
773 case NODE_TYPE_TEXT:
774 fprintf(output, "'text' "); break;
775 case NODE_TYPE_PI:
776 fprintf(output, "'PI' "); break;
777 }
778 if (prefix != NULL)
779 fprintf(output, "%s:", prefix);
780 if (name != NULL)
781 fprintf(output, "%s", name);
782 break;
783
784 }
785 case XPATH_OP_VALUE: {
786 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
787
788 fprintf(output, "ELEM ");
789 xmlXPathDebugDumpObject(output, object, 0);
790 goto finish;
791 }
792 case XPATH_OP_VARIABLE: {
793 const xmlChar *prefix = op->value5;
794 const xmlChar *name = op->value4;
795
796 if (prefix != NULL)
797 fprintf(output, "VARIABLE %s:%s", prefix, name);
798 else
799 fprintf(output, "VARIABLE %s", name);
800 break;
801 }
802 case XPATH_OP_FUNCTION: {
803 int nbargs = op->value;
804 const xmlChar *prefix = op->value5;
805 const xmlChar *name = op->value4;
806
807 if (prefix != NULL)
808 fprintf(output, "FUNCTION %s:%s(%d args)",
809 prefix, name, nbargs);
810 else
811 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
812 break;
813 }
814 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
815 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000816 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000817#ifdef LIBXML_XPTR_ENABLED
818 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
819#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000820 default:
821 fprintf(output, "UNKNOWN %d\n", op->op); return;
822 }
823 fprintf(output, "\n");
824finish:
825 if (op->ch1 >= 0)
826 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
827 if (op->ch2 >= 0)
828 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
829}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000830
831void
832xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
833 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000834 int i;
835 char shift[100];
836
837 for (i = 0;((i < depth) && (i < 25));i++)
838 shift[2 * i] = shift[2 * i + 1] = ' ';
839 shift[2 * i] = shift[2 * i + 1] = 0;
840
841 fprintf(output, shift);
842
843 if (comp == NULL) {
844 fprintf(output, "Compiled Expression is NULL\n");
845 return;
846 }
847 fprintf(output, "Compiled Expression : %d elements\n",
848 comp->nbStep);
849 i = comp->last;
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
851}
Owen Taylor3473f882001-02-23 17:55:21 +0000852#endif
853
854/************************************************************************
855 * *
856 * Parser stacks related functions and macros *
857 * *
858 ************************************************************************/
859
860/*
861 * Generic function for accessing stacks in the Parser Context
862 */
863
864#define PUSH_AND_POP(type, name) \
865extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
866 if (ctxt->name##Nr >= ctxt->name##Max) { \
867 ctxt->name##Max *= 2; \
868 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
869 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
870 if (ctxt->name##Tab == NULL) { \
871 xmlGenericError(xmlGenericErrorContext, \
872 "realloc failed !\n"); \
873 return(0); \
874 } \
875 } \
876 ctxt->name##Tab[ctxt->name##Nr] = value; \
877 ctxt->name = value; \
878 return(ctxt->name##Nr++); \
879} \
880extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
881 type ret; \
882 if (ctxt->name##Nr <= 0) return(0); \
883 ctxt->name##Nr--; \
884 if (ctxt->name##Nr > 0) \
885 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
886 else \
887 ctxt->name = NULL; \
888 ret = ctxt->name##Tab[ctxt->name##Nr]; \
889 ctxt->name##Tab[ctxt->name##Nr] = 0; \
890 return(ret); \
891} \
892
893PUSH_AND_POP(xmlXPathObjectPtr, value)
894
895/*
896 * Macros for accessing the content. Those should be used only by the parser,
897 * and not exported.
898 *
899 * Dirty macros, i.e. one need to make assumption on the context to use them
900 *
901 * CUR_PTR return the current pointer to the xmlChar to be parsed.
902 * CUR returns the current xmlChar value, i.e. a 8 bit value
903 * in ISO-Latin or UTF-8.
904 * This should be used internally by the parser
905 * only to compare to ASCII values otherwise it would break when
906 * running with UTF-8 encoding.
907 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
908 * to compare on ASCII based substring.
909 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
910 * strings within the parser.
911 * CURRENT Returns the current char value, with the full decoding of
912 * UTF-8 if we are using this mode. It returns an int.
913 * NEXT Skip to the next character, this does the proper decoding
914 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
915 * It returns the pointer to the current xmlChar.
916 */
917
918#define CUR (*ctxt->cur)
919#define SKIP(val) ctxt->cur += (val)
920#define NXT(val) ctxt->cur[(val)]
921#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +0000922#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
923
924#define COPY_BUF(l,b,i,v) \
925 if (l == 1) b[i++] = (xmlChar) v; \
926 else i += xmlCopyChar(l,&b[i],v)
927
928#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +0000929
930#define SKIP_BLANKS \
931 while (IS_BLANK(*(ctxt->cur))) NEXT
932
933#define CURRENT (*ctxt->cur)
934#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
935
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000936
937#ifndef DBL_DIG
938#define DBL_DIG 16
939#endif
940#ifndef DBL_EPSILON
941#define DBL_EPSILON 1E-9
942#endif
943
944#define UPPER_DOUBLE 1E9
945#define LOWER_DOUBLE 1E-5
946
947#define INTEGER_DIGITS DBL_DIG
948#define FRACTION_DIGITS (DBL_DIG + 1)
949#define EXPONENT_DIGITS (3 + 2)
950
951/**
952 * xmlXPathFormatNumber:
953 * @number: number to format
954 * @buffer: output buffer
955 * @buffersize: size of output buffer
956 *
957 * Convert the number into a string representation.
958 */
959static void
960xmlXPathFormatNumber(double number, char buffer[], int buffersize)
961{
962 switch (isinf(number)) {
963 case 1:
964 if (buffersize > (int)sizeof("+Infinity"))
965 sprintf(buffer, "+Infinity");
966 break;
967 case -1:
968 if (buffersize > (int)sizeof("-Infinity"))
969 sprintf(buffer, "-Infinity");
970 break;
971 default:
972 if (isnan(number)) {
973 if (buffersize > (int)sizeof("NaN"))
974 sprintf(buffer, "NaN");
975 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000976 /* 3 is sign, decimal point, and terminating zero */
977 char work[DBL_DIG + EXPONENT_DIGITS + 3];
978 int integer_place, fraction_place;
979 char *ptr;
980 char *after_fraction;
981 double absolute_value;
982 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000983
Bjorn Reese70a9da52001-04-21 16:57:29 +0000984 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000985
Bjorn Reese70a9da52001-04-21 16:57:29 +0000986 /*
987 * First choose format - scientific or regular floating point.
988 * In either case, result is in work, and after_fraction points
989 * just past the fractional part.
990 */
991 if ( ((absolute_value > UPPER_DOUBLE) ||
992 (absolute_value < LOWER_DOUBLE)) &&
993 (absolute_value != 0.0) ) {
994 /* Use scientific notation */
995 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
996 fraction_place = DBL_DIG - 1;
997 snprintf(work, sizeof(work),"%*.*e",
998 integer_place, fraction_place, number);
999 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001000 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001001 else {
1002 /* Use regular notation */
1003 integer_place = 1 + (int)log10(absolute_value);
1004 fraction_place = (integer_place > 0)
1005 ? DBL_DIG - integer_place
1006 : DBL_DIG;
1007 size = snprintf(work, sizeof(work), "%0.*f",
1008 fraction_place, number);
1009 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001010 }
1011
Bjorn Reese70a9da52001-04-21 16:57:29 +00001012 /* Remove fractional trailing zeroes */
1013 ptr = after_fraction;
1014 while (*(--ptr) == '0')
1015 ;
1016 if (*ptr != '.')
1017 ptr++;
1018 strcpy(ptr, after_fraction);
1019
1020 /* Finally copy result back to caller */
1021 size = strlen(work) + 1;
1022 if (size > buffersize) {
1023 work[buffersize - 1] = 0;
1024 size = buffersize;
1025 }
1026 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001027 }
1028 break;
1029 }
1030}
1031
Owen Taylor3473f882001-02-23 17:55:21 +00001032/************************************************************************
1033 * *
1034 * Error handling routines *
1035 * *
1036 ************************************************************************/
1037
1038
1039const char *xmlXPathErrorMessages[] = {
1040 "Ok",
1041 "Number encoding",
1042 "Unfinished litteral",
1043 "Start of litteral",
1044 "Expected $ for variable reference",
1045 "Undefined variable",
1046 "Invalid predicate",
1047 "Invalid expression",
1048 "Missing closing curly brace",
1049 "Unregistered function",
1050 "Invalid operand",
1051 "Invalid type",
1052 "Invalid number of arguments",
1053 "Invalid context size",
1054 "Invalid context position",
1055 "Memory allocation error",
1056 "Syntax error",
1057 "Resource error",
1058 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001059 "Undefined namespace prefix",
1060 "Encoding error",
1061 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001062};
1063
1064/**
1065 * xmlXPathError:
1066 * @ctxt: the XPath Parser context
1067 * @file: the file name
1068 * @line: the line number
1069 * @no: the error number
1070 *
1071 * Create a new xmlNodeSetPtr of type double and of value @val
1072 *
1073 * Returns the newly created object.
1074 */
1075void
1076xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1077 int line, int no) {
1078 int n;
1079 const xmlChar *cur;
1080 const xmlChar *base;
1081
1082 xmlGenericError(xmlGenericErrorContext,
1083 "Error %s:%d: %s\n", file, line,
1084 xmlXPathErrorMessages[no]);
1085
1086 cur = ctxt->cur;
1087 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001088 if ((cur == NULL) || (base == NULL))
1089 return;
1090
Owen Taylor3473f882001-02-23 17:55:21 +00001091 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1092 cur--;
1093 }
1094 n = 0;
1095 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1096 cur--;
1097 if ((*cur == '\n') || (*cur == '\r')) cur++;
1098 base = cur;
1099 n = 0;
1100 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1101 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1102 n++;
1103 }
1104 xmlGenericError(xmlGenericErrorContext, "\n");
1105 cur = ctxt->cur;
1106 while ((*cur == '\n') || (*cur == '\r'))
1107 cur--;
1108 n = 0;
1109 while ((cur != base) && (n++ < 80)) {
1110 xmlGenericError(xmlGenericErrorContext, " ");
1111 base++;
1112 }
1113 xmlGenericError(xmlGenericErrorContext,"^\n");
1114}
1115
1116
1117/************************************************************************
1118 * *
1119 * Routines to handle NodeSets *
1120 * *
1121 ************************************************************************/
1122
1123/**
1124 * xmlXPathCmpNodes:
1125 * @node1: the first node
1126 * @node2: the second node
1127 *
1128 * Compare two nodes w.r.t document order
1129 *
1130 * Returns -2 in case of error 1 if first point < second point, 0 if
1131 * that's the same node, -1 otherwise
1132 */
1133int
1134xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1135 int depth1, depth2;
1136 xmlNodePtr cur, root;
1137
1138 if ((node1 == NULL) || (node2 == NULL))
1139 return(-2);
1140 /*
1141 * a couple of optimizations which will avoid computations in most cases
1142 */
1143 if (node1 == node2)
1144 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001145 if ((node1->type == XML_NAMESPACE_DECL) ||
1146 (node2->type == XML_NAMESPACE_DECL))
1147 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001148 if (node1 == node2->prev)
1149 return(1);
1150 if (node1 == node2->next)
1151 return(-1);
1152
1153 /*
1154 * compute depth to root
1155 */
1156 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1157 if (cur == node1)
1158 return(1);
1159 depth2++;
1160 }
1161 root = cur;
1162 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1163 if (cur == node2)
1164 return(-1);
1165 depth1++;
1166 }
1167 /*
1168 * Distinct document (or distinct entities :-( ) case.
1169 */
1170 if (root != cur) {
1171 return(-2);
1172 }
1173 /*
1174 * get the nearest common ancestor.
1175 */
1176 while (depth1 > depth2) {
1177 depth1--;
1178 node1 = node1->parent;
1179 }
1180 while (depth2 > depth1) {
1181 depth2--;
1182 node2 = node2->parent;
1183 }
1184 while (node1->parent != node2->parent) {
1185 node1 = node1->parent;
1186 node2 = node2->parent;
1187 /* should not happen but just in case ... */
1188 if ((node1 == NULL) || (node2 == NULL))
1189 return(-2);
1190 }
1191 /*
1192 * Find who's first.
1193 */
1194 if (node1 == node2->next)
1195 return(-1);
1196 for (cur = node1->next;cur != NULL;cur = cur->next)
1197 if (cur == node2)
1198 return(1);
1199 return(-1); /* assume there is no sibling list corruption */
1200}
1201
1202/**
1203 * xmlXPathNodeSetSort:
1204 * @set: the node set
1205 *
1206 * Sort the node set in document order
1207 */
1208void
1209xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001210 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001211 xmlNodePtr tmp;
1212
1213 if (set == NULL)
1214 return;
1215
1216 /* Use Shell's sort to sort the node-set */
1217 len = set->nodeNr;
1218 for (incr = len / 2; incr > 0; incr /= 2) {
1219 for (i = incr; i < len; i++) {
1220 j = i - incr;
1221 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001222 if (xmlXPathCmpNodes(set->nodeTab[j],
1223 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001224 tmp = set->nodeTab[j];
1225 set->nodeTab[j] = set->nodeTab[j + incr];
1226 set->nodeTab[j + incr] = tmp;
1227 j -= incr;
1228 } else
1229 break;
1230 }
1231 }
1232 }
1233}
1234
1235#define XML_NODESET_DEFAULT 10
1236/**
1237 * xmlXPathNodeSetCreate:
1238 * @val: an initial xmlNodePtr, or NULL
1239 *
1240 * Create a new xmlNodeSetPtr of type double and of value @val
1241 *
1242 * Returns the newly created object.
1243 */
1244xmlNodeSetPtr
1245xmlXPathNodeSetCreate(xmlNodePtr val) {
1246 xmlNodeSetPtr ret;
1247
1248 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1249 if (ret == NULL) {
1250 xmlGenericError(xmlGenericErrorContext,
1251 "xmlXPathNewNodeSet: out of memory\n");
1252 return(NULL);
1253 }
1254 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1255 if (val != NULL) {
1256 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1257 sizeof(xmlNodePtr));
1258 if (ret->nodeTab == NULL) {
1259 xmlGenericError(xmlGenericErrorContext,
1260 "xmlXPathNewNodeSet: out of memory\n");
1261 return(NULL);
1262 }
1263 memset(ret->nodeTab, 0 ,
1264 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1265 ret->nodeMax = XML_NODESET_DEFAULT;
1266 ret->nodeTab[ret->nodeNr++] = val;
1267 }
1268 return(ret);
1269}
1270
1271/**
1272 * xmlXPathNodeSetAdd:
1273 * @cur: the initial node set
1274 * @val: a new xmlNodePtr
1275 *
1276 * add a new xmlNodePtr ot an existing NodeSet
1277 */
1278void
1279xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1280 int i;
1281
1282 if (val == NULL) return;
1283
1284 /*
1285 * check against doublons
1286 */
1287 for (i = 0;i < cur->nodeNr;i++)
1288 if (cur->nodeTab[i] == val) return;
1289
1290 /*
1291 * grow the nodeTab if needed
1292 */
1293 if (cur->nodeMax == 0) {
1294 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1295 sizeof(xmlNodePtr));
1296 if (cur->nodeTab == NULL) {
1297 xmlGenericError(xmlGenericErrorContext,
1298 "xmlXPathNodeSetAdd: out of memory\n");
1299 return;
1300 }
1301 memset(cur->nodeTab, 0 ,
1302 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1303 cur->nodeMax = XML_NODESET_DEFAULT;
1304 } else if (cur->nodeNr == cur->nodeMax) {
1305 xmlNodePtr *temp;
1306
1307 cur->nodeMax *= 2;
1308 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1309 sizeof(xmlNodePtr));
1310 if (temp == NULL) {
1311 xmlGenericError(xmlGenericErrorContext,
1312 "xmlXPathNodeSetAdd: out of memory\n");
1313 return;
1314 }
1315 cur->nodeTab = temp;
1316 }
1317 cur->nodeTab[cur->nodeNr++] = val;
1318}
1319
1320/**
1321 * xmlXPathNodeSetAddUnique:
1322 * @cur: the initial node set
1323 * @val: a new xmlNodePtr
1324 *
1325 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1326 * when we are sure the node is not already in the set.
1327 */
1328void
1329xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1330 if (val == NULL) return;
1331
1332 /*
1333 * grow the nodeTab if needed
1334 */
1335 if (cur->nodeMax == 0) {
1336 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1337 sizeof(xmlNodePtr));
1338 if (cur->nodeTab == NULL) {
1339 xmlGenericError(xmlGenericErrorContext,
1340 "xmlXPathNodeSetAddUnique: out of memory\n");
1341 return;
1342 }
1343 memset(cur->nodeTab, 0 ,
1344 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1345 cur->nodeMax = XML_NODESET_DEFAULT;
1346 } else if (cur->nodeNr == cur->nodeMax) {
1347 xmlNodePtr *temp;
1348
1349 cur->nodeMax *= 2;
1350 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1351 sizeof(xmlNodePtr));
1352 if (temp == NULL) {
1353 xmlGenericError(xmlGenericErrorContext,
1354 "xmlXPathNodeSetAddUnique: out of memory\n");
1355 return;
1356 }
1357 cur->nodeTab = temp;
1358 }
1359 cur->nodeTab[cur->nodeNr++] = val;
1360}
1361
1362/**
1363 * xmlXPathNodeSetMerge:
1364 * @val1: the first NodeSet or NULL
1365 * @val2: the second NodeSet
1366 *
1367 * Merges two nodesets, all nodes from @val2 are added to @val1
1368 * if @val1 is NULL, a new set is created and copied from @val2
1369 *
1370 * Returns val1 once extended or NULL in case of error.
1371 */
1372xmlNodeSetPtr
1373xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001374 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001375
1376 if (val2 == NULL) return(val1);
1377 if (val1 == NULL) {
1378 val1 = xmlXPathNodeSetCreate(NULL);
1379 }
1380
1381 initNr = val1->nodeNr;
1382
1383 for (i = 0;i < val2->nodeNr;i++) {
1384 /*
1385 * check against doublons
1386 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001387 skip = 0;
1388 for (j = 0; j < initNr; j++) {
1389 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1390 skip = 1;
1391 break;
1392 }
1393 }
1394 if (skip)
1395 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001396
1397 /*
1398 * grow the nodeTab if needed
1399 */
1400 if (val1->nodeMax == 0) {
1401 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1402 sizeof(xmlNodePtr));
1403 if (val1->nodeTab == NULL) {
1404 xmlGenericError(xmlGenericErrorContext,
1405 "xmlXPathNodeSetMerge: out of memory\n");
1406 return(NULL);
1407 }
1408 memset(val1->nodeTab, 0 ,
1409 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1410 val1->nodeMax = XML_NODESET_DEFAULT;
1411 } else if (val1->nodeNr == val1->nodeMax) {
1412 xmlNodePtr *temp;
1413
1414 val1->nodeMax *= 2;
1415 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1416 sizeof(xmlNodePtr));
1417 if (temp == NULL) {
1418 xmlGenericError(xmlGenericErrorContext,
1419 "xmlXPathNodeSetMerge: out of memory\n");
1420 return(NULL);
1421 }
1422 val1->nodeTab = temp;
1423 }
1424 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1425 }
1426
1427 return(val1);
1428}
1429
1430/**
1431 * xmlXPathNodeSetDel:
1432 * @cur: the initial node set
1433 * @val: an xmlNodePtr
1434 *
1435 * Removes an xmlNodePtr from an existing NodeSet
1436 */
1437void
1438xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1439 int i;
1440
1441 if (cur == NULL) return;
1442 if (val == NULL) return;
1443
1444 /*
1445 * check against doublons
1446 */
1447 for (i = 0;i < cur->nodeNr;i++)
1448 if (cur->nodeTab[i] == val) break;
1449
1450 if (i >= cur->nodeNr) {
1451#ifdef DEBUG
1452 xmlGenericError(xmlGenericErrorContext,
1453 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1454 val->name);
1455#endif
1456 return;
1457 }
1458 cur->nodeNr--;
1459 for (;i < cur->nodeNr;i++)
1460 cur->nodeTab[i] = cur->nodeTab[i + 1];
1461 cur->nodeTab[cur->nodeNr] = NULL;
1462}
1463
1464/**
1465 * xmlXPathNodeSetRemove:
1466 * @cur: the initial node set
1467 * @val: the index to remove
1468 *
1469 * Removes an entry from an existing NodeSet list.
1470 */
1471void
1472xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1473 if (cur == NULL) return;
1474 if (val >= cur->nodeNr) return;
1475 cur->nodeNr--;
1476 for (;val < cur->nodeNr;val++)
1477 cur->nodeTab[val] = cur->nodeTab[val + 1];
1478 cur->nodeTab[cur->nodeNr] = NULL;
1479}
1480
1481/**
1482 * xmlXPathFreeNodeSet:
1483 * @obj: the xmlNodeSetPtr to free
1484 *
1485 * Free the NodeSet compound (not the actual nodes !).
1486 */
1487void
1488xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1489 if (obj == NULL) return;
1490 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001491 xmlFree(obj->nodeTab);
1492 }
Owen Taylor3473f882001-02-23 17:55:21 +00001493 xmlFree(obj);
1494}
1495
1496/**
1497 * xmlXPathFreeValueTree:
1498 * @obj: the xmlNodeSetPtr to free
1499 *
1500 * Free the NodeSet compound and the actual tree, this is different
1501 * from xmlXPathFreeNodeSet()
1502 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001503static void
Owen Taylor3473f882001-02-23 17:55:21 +00001504xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1505 int i;
1506
1507 if (obj == NULL) return;
1508 for (i = 0;i < obj->nodeNr;i++)
1509 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001510 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001511
1512 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001513 xmlFree(obj->nodeTab);
1514 }
Owen Taylor3473f882001-02-23 17:55:21 +00001515 xmlFree(obj);
1516}
1517
1518#if defined(DEBUG) || defined(DEBUG_STEP)
1519/**
1520 * xmlGenericErrorContextNodeSet:
1521 * @output: a FILE * for the output
1522 * @obj: the xmlNodeSetPtr to free
1523 *
1524 * Quick display of a NodeSet
1525 */
1526void
1527xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1528 int i;
1529
1530 if (output == NULL) output = xmlGenericErrorContext;
1531 if (obj == NULL) {
1532 fprintf(output, "NodeSet == NULL !\n");
1533 return;
1534 }
1535 if (obj->nodeNr == 0) {
1536 fprintf(output, "NodeSet is empty\n");
1537 return;
1538 }
1539 if (obj->nodeTab == NULL) {
1540 fprintf(output, " nodeTab == NULL !\n");
1541 return;
1542 }
1543 for (i = 0; i < obj->nodeNr; i++) {
1544 if (obj->nodeTab[i] == NULL) {
1545 fprintf(output, " NULL !\n");
1546 return;
1547 }
1548 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1549 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1550 fprintf(output, " /");
1551 else if (obj->nodeTab[i]->name == NULL)
1552 fprintf(output, " noname!");
1553 else fprintf(output, " %s", obj->nodeTab[i]->name);
1554 }
1555 fprintf(output, "\n");
1556}
1557#endif
1558
1559/**
1560 * xmlXPathNewNodeSet:
1561 * @val: the NodePtr value
1562 *
1563 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1564 * it with the single Node @val
1565 *
1566 * Returns the newly created object.
1567 */
1568xmlXPathObjectPtr
1569xmlXPathNewNodeSet(xmlNodePtr val) {
1570 xmlXPathObjectPtr ret;
1571
1572 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1573 if (ret == NULL) {
1574 xmlGenericError(xmlGenericErrorContext,
1575 "xmlXPathNewNodeSet: out of memory\n");
1576 return(NULL);
1577 }
1578 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1579 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001580 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001581 ret->nodesetval = xmlXPathNodeSetCreate(val);
1582 return(ret);
1583}
1584
1585/**
1586 * xmlXPathNewValueTree:
1587 * @val: the NodePtr value
1588 *
1589 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1590 * it with the tree root @val
1591 *
1592 * Returns the newly created object.
1593 */
1594xmlXPathObjectPtr
1595xmlXPathNewValueTree(xmlNodePtr val) {
1596 xmlXPathObjectPtr ret;
1597
1598 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1599 if (ret == NULL) {
1600 xmlGenericError(xmlGenericErrorContext,
1601 "xmlXPathNewNodeSet: out of memory\n");
1602 return(NULL);
1603 }
1604 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1605 ret->type = XPATH_XSLT_TREE;
1606 ret->nodesetval = xmlXPathNodeSetCreate(val);
1607 return(ret);
1608}
1609
1610/**
1611 * xmlXPathNewNodeSetList:
1612 * @val: an existing NodeSet
1613 *
1614 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1615 * it with the Nodeset @val
1616 *
1617 * Returns the newly created object.
1618 */
1619xmlXPathObjectPtr
1620xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1621 xmlXPathObjectPtr ret;
1622 int i;
1623
1624 if (val == NULL)
1625 ret = NULL;
1626 else if (val->nodeTab == NULL)
1627 ret = xmlXPathNewNodeSet(NULL);
1628 else
1629 {
1630 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1631 for (i = 1; i < val->nodeNr; ++i)
1632 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1633 }
1634
1635 return(ret);
1636}
1637
1638/**
1639 * xmlXPathWrapNodeSet:
1640 * @val: the NodePtr value
1641 *
1642 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1643 *
1644 * Returns the newly created object.
1645 */
1646xmlXPathObjectPtr
1647xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1648 xmlXPathObjectPtr ret;
1649
1650 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1651 if (ret == NULL) {
1652 xmlGenericError(xmlGenericErrorContext,
1653 "xmlXPathWrapNodeSet: out of memory\n");
1654 return(NULL);
1655 }
1656 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1657 ret->type = XPATH_NODESET;
1658 ret->nodesetval = val;
1659 return(ret);
1660}
1661
1662/**
1663 * xmlXPathFreeNodeSetList:
1664 * @obj: an existing NodeSetList object
1665 *
1666 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1667 * the list contrary to xmlXPathFreeObject().
1668 */
1669void
1670xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1671 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001672 xmlFree(obj);
1673}
1674
1675/************************************************************************
1676 * *
1677 * Routines to handle extra functions *
1678 * *
1679 ************************************************************************/
1680
1681/**
1682 * xmlXPathRegisterFunc:
1683 * @ctxt: the XPath context
1684 * @name: the function name
1685 * @f: the function implementation or NULL
1686 *
1687 * Register a new function. If @f is NULL it unregisters the function
1688 *
1689 * Returns 0 in case of success, -1 in case of error
1690 */
1691int
1692xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1693 xmlXPathFunction f) {
1694 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1695}
1696
1697/**
1698 * xmlXPathRegisterFuncNS:
1699 * @ctxt: the XPath context
1700 * @name: the function name
1701 * @ns_uri: the function namespace URI
1702 * @f: the function implementation or NULL
1703 *
1704 * Register a new function. If @f is NULL it unregisters the function
1705 *
1706 * Returns 0 in case of success, -1 in case of error
1707 */
1708int
1709xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1710 const xmlChar *ns_uri, xmlXPathFunction f) {
1711 if (ctxt == NULL)
1712 return(-1);
1713 if (name == NULL)
1714 return(-1);
1715
1716 if (ctxt->funcHash == NULL)
1717 ctxt->funcHash = xmlHashCreate(0);
1718 if (ctxt->funcHash == NULL)
1719 return(-1);
1720 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1721}
1722
1723/**
1724 * xmlXPathFunctionLookup:
1725 * @ctxt: the XPath context
1726 * @name: the function name
1727 *
1728 * Search in the Function array of the context for the given
1729 * function.
1730 *
1731 * Returns the xmlXPathFunction or NULL if not found
1732 */
1733xmlXPathFunction
1734xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1735 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1736}
1737
1738/**
1739 * xmlXPathFunctionLookupNS:
1740 * @ctxt: the XPath context
1741 * @name: the function name
1742 * @ns_uri: the function namespace URI
1743 *
1744 * Search in the Function array of the context for the given
1745 * function.
1746 *
1747 * Returns the xmlXPathFunction or NULL if not found
1748 */
1749xmlXPathFunction
1750xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1751 const xmlChar *ns_uri) {
1752 if (ctxt == NULL)
1753 return(NULL);
1754 if (ctxt->funcHash == NULL)
1755 return(NULL);
1756 if (name == NULL)
1757 return(NULL);
1758
1759 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1760}
1761
1762/**
1763 * xmlXPathRegisteredFuncsCleanup:
1764 * @ctxt: the XPath context
1765 *
1766 * Cleanup the XPath context data associated to registered functions
1767 */
1768void
1769xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1770 if (ctxt == NULL)
1771 return;
1772
1773 xmlHashFree(ctxt->funcHash, NULL);
1774 ctxt->funcHash = NULL;
1775}
1776
1777/************************************************************************
1778 * *
1779 * Routines to handle Variable *
1780 * *
1781 ************************************************************************/
1782
1783/**
1784 * xmlXPathRegisterVariable:
1785 * @ctxt: the XPath context
1786 * @name: the variable name
1787 * @value: the variable value or NULL
1788 *
1789 * Register a new variable value. If @value is NULL it unregisters
1790 * the variable
1791 *
1792 * Returns 0 in case of success, -1 in case of error
1793 */
1794int
1795xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1796 xmlXPathObjectPtr value) {
1797 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1798}
1799
1800/**
1801 * xmlXPathRegisterVariableNS:
1802 * @ctxt: the XPath context
1803 * @name: the variable name
1804 * @ns_uri: the variable namespace URI
1805 * @value: the variable value or NULL
1806 *
1807 * Register a new variable value. If @value is NULL it unregisters
1808 * the variable
1809 *
1810 * Returns 0 in case of success, -1 in case of error
1811 */
1812int
1813xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1814 const xmlChar *ns_uri,
1815 xmlXPathObjectPtr value) {
1816 if (ctxt == NULL)
1817 return(-1);
1818 if (name == NULL)
1819 return(-1);
1820
1821 if (ctxt->varHash == NULL)
1822 ctxt->varHash = xmlHashCreate(0);
1823 if (ctxt->varHash == NULL)
1824 return(-1);
1825 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1826 (void *) value,
1827 (xmlHashDeallocator)xmlXPathFreeObject));
1828}
1829
1830/**
1831 * xmlXPathRegisterVariableLookup:
1832 * @ctxt: the XPath context
1833 * @f: the lookup function
1834 * @data: the lookup data
1835 *
1836 * register an external mechanism to do variable lookup
1837 */
1838void
1839xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1840 xmlXPathVariableLookupFunc f, void *data) {
1841 if (ctxt == NULL)
1842 return;
1843 ctxt->varLookupFunc = (void *) f;
1844 ctxt->varLookupData = data;
1845}
1846
1847/**
1848 * xmlXPathVariableLookup:
1849 * @ctxt: the XPath context
1850 * @name: the variable name
1851 *
1852 * Search in the Variable array of the context for the given
1853 * variable value.
1854 *
1855 * Returns the value or NULL if not found
1856 */
1857xmlXPathObjectPtr
1858xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1859 if (ctxt == NULL)
1860 return(NULL);
1861
1862 if (ctxt->varLookupFunc != NULL) {
1863 xmlXPathObjectPtr ret;
1864
1865 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1866 (ctxt->varLookupData, name, NULL);
1867 if (ret != NULL) return(ret);
1868 }
1869 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1870}
1871
1872/**
1873 * xmlXPathVariableLookupNS:
1874 * @ctxt: the XPath context
1875 * @name: the variable name
1876 * @ns_uri: the variable namespace URI
1877 *
1878 * Search in the Variable array of the context for the given
1879 * variable value.
1880 *
1881 * Returns the value or NULL if not found
1882 */
1883xmlXPathObjectPtr
1884xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1885 const xmlChar *ns_uri) {
1886 if (ctxt == NULL)
1887 return(NULL);
1888
1889 if (ctxt->varLookupFunc != NULL) {
1890 xmlXPathObjectPtr ret;
1891
1892 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1893 (ctxt->varLookupData, name, ns_uri);
1894 if (ret != NULL) return(ret);
1895 }
1896
1897 if (ctxt->varHash == NULL)
1898 return(NULL);
1899 if (name == NULL)
1900 return(NULL);
1901
1902 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1903}
1904
1905/**
1906 * xmlXPathRegisteredVariablesCleanup:
1907 * @ctxt: the XPath context
1908 *
1909 * Cleanup the XPath context data associated to registered variables
1910 */
1911void
1912xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1913 if (ctxt == NULL)
1914 return;
1915
1916 xmlHashFree(ctxt->varHash, NULL);
1917 ctxt->varHash = NULL;
1918}
1919
1920/**
1921 * xmlXPathRegisterNs:
1922 * @ctxt: the XPath context
1923 * @prefix: the namespace prefix
1924 * @ns_uri: the namespace name
1925 *
1926 * Register a new namespace. If @ns_uri is NULL it unregisters
1927 * the namespace
1928 *
1929 * Returns 0 in case of success, -1 in case of error
1930 */
1931int
1932xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1933 const xmlChar *ns_uri) {
1934 if (ctxt == NULL)
1935 return(-1);
1936 if (prefix == NULL)
1937 return(-1);
1938
1939 if (ctxt->nsHash == NULL)
1940 ctxt->nsHash = xmlHashCreate(10);
1941 if (ctxt->nsHash == NULL)
1942 return(-1);
1943 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1944 (xmlHashDeallocator)xmlFree));
1945}
1946
1947/**
1948 * xmlXPathNsLookup:
1949 * @ctxt: the XPath context
1950 * @prefix: the namespace prefix value
1951 *
1952 * Search in the namespace declaration array of the context for the given
1953 * namespace name associated to the given prefix
1954 *
1955 * Returns the value or NULL if not found
1956 */
1957const xmlChar *
1958xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1959 if (ctxt == NULL)
1960 return(NULL);
1961 if (prefix == NULL)
1962 return(NULL);
1963
1964#ifdef XML_XML_NAMESPACE
1965 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1966 return(XML_XML_NAMESPACE);
1967#endif
1968
Daniel Veillardc8f620b2001-04-30 20:31:33 +00001969 if (ctxt->namespaces != NULL) {
1970 int i;
1971
1972 for (i = 0;i < ctxt->nsNr;i++) {
1973 if ((ctxt->namespaces[i] != NULL) &&
1974 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
1975 return(ctxt->namespaces[i]->href);
1976 }
1977 }
Owen Taylor3473f882001-02-23 17:55:21 +00001978
1979 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1980}
1981
1982/**
1983 * xmlXPathRegisteredVariablesCleanup:
1984 * @ctxt: the XPath context
1985 *
1986 * Cleanup the XPath context data associated to registered variables
1987 */
1988void
1989xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
1990 if (ctxt == NULL)
1991 return;
1992
1993 xmlHashFree(ctxt->nsHash, NULL);
1994 ctxt->nsHash = NULL;
1995}
1996
1997/************************************************************************
1998 * *
1999 * Routines to handle Values *
2000 * *
2001 ************************************************************************/
2002
2003/* Allocations are terrible, one need to optimize all this !!! */
2004
2005/**
2006 * xmlXPathNewFloat:
2007 * @val: the double value
2008 *
2009 * Create a new xmlXPathObjectPtr of type double and of value @val
2010 *
2011 * Returns the newly created object.
2012 */
2013xmlXPathObjectPtr
2014xmlXPathNewFloat(double val) {
2015 xmlXPathObjectPtr ret;
2016
2017 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2018 if (ret == NULL) {
2019 xmlGenericError(xmlGenericErrorContext,
2020 "xmlXPathNewFloat: out of memory\n");
2021 return(NULL);
2022 }
2023 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2024 ret->type = XPATH_NUMBER;
2025 ret->floatval = val;
2026 return(ret);
2027}
2028
2029/**
2030 * xmlXPathNewBoolean:
2031 * @val: the boolean value
2032 *
2033 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2034 *
2035 * Returns the newly created object.
2036 */
2037xmlXPathObjectPtr
2038xmlXPathNewBoolean(int val) {
2039 xmlXPathObjectPtr ret;
2040
2041 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2042 if (ret == NULL) {
2043 xmlGenericError(xmlGenericErrorContext,
2044 "xmlXPathNewBoolean: out of memory\n");
2045 return(NULL);
2046 }
2047 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2048 ret->type = XPATH_BOOLEAN;
2049 ret->boolval = (val != 0);
2050 return(ret);
2051}
2052
2053/**
2054 * xmlXPathNewString:
2055 * @val: the xmlChar * value
2056 *
2057 * Create a new xmlXPathObjectPtr of type string and of value @val
2058 *
2059 * Returns the newly created object.
2060 */
2061xmlXPathObjectPtr
2062xmlXPathNewString(const xmlChar *val) {
2063 xmlXPathObjectPtr ret;
2064
2065 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2066 if (ret == NULL) {
2067 xmlGenericError(xmlGenericErrorContext,
2068 "xmlXPathNewString: out of memory\n");
2069 return(NULL);
2070 }
2071 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2072 ret->type = XPATH_STRING;
2073 if (val != NULL)
2074 ret->stringval = xmlStrdup(val);
2075 else
2076 ret->stringval = xmlStrdup((const xmlChar *)"");
2077 return(ret);
2078}
2079
2080/**
2081 * xmlXPathNewCString:
2082 * @val: the char * value
2083 *
2084 * Create a new xmlXPathObjectPtr of type string and of value @val
2085 *
2086 * Returns the newly created object.
2087 */
2088xmlXPathObjectPtr
2089xmlXPathNewCString(const char *val) {
2090 xmlXPathObjectPtr ret;
2091
2092 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2093 if (ret == NULL) {
2094 xmlGenericError(xmlGenericErrorContext,
2095 "xmlXPathNewCString: out of memory\n");
2096 return(NULL);
2097 }
2098 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2099 ret->type = XPATH_STRING;
2100 ret->stringval = xmlStrdup(BAD_CAST val);
2101 return(ret);
2102}
2103
2104/**
2105 * xmlXPathObjectCopy:
2106 * @val: the original object
2107 *
2108 * allocate a new copy of a given object
2109 *
2110 * Returns the newly created object.
2111 */
2112xmlXPathObjectPtr
2113xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2114 xmlXPathObjectPtr ret;
2115
2116 if (val == NULL)
2117 return(NULL);
2118
2119 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2120 if (ret == NULL) {
2121 xmlGenericError(xmlGenericErrorContext,
2122 "xmlXPathObjectCopy: out of memory\n");
2123 return(NULL);
2124 }
2125 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2126 switch (val->type) {
2127 case XPATH_BOOLEAN:
2128 case XPATH_NUMBER:
2129 case XPATH_POINT:
2130 case XPATH_RANGE:
2131 break;
2132 case XPATH_STRING:
2133 ret->stringval = xmlStrdup(val->stringval);
2134 break;
2135 case XPATH_XSLT_TREE:
2136 if ((val->nodesetval != NULL) &&
2137 (val->nodesetval->nodeTab != NULL))
2138 ret->nodesetval = xmlXPathNodeSetCreate(
2139 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2140 else
2141 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2142 break;
2143 case XPATH_NODESET:
2144 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2145 break;
2146 case XPATH_LOCATIONSET:
2147#ifdef LIBXML_XPTR_ENABLED
2148 {
2149 xmlLocationSetPtr loc = val->user;
2150 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2151 break;
2152 }
2153#endif
2154 case XPATH_UNDEFINED:
2155 case XPATH_USERS:
2156 xmlGenericError(xmlGenericErrorContext,
2157 "xmlXPathObjectCopy: unsupported type %d\n",
2158 val->type);
2159 break;
2160 }
2161 return(ret);
2162}
2163
2164/**
2165 * xmlXPathFreeObject:
2166 * @obj: the object to free
2167 *
2168 * Free up an xmlXPathObjectPtr object.
2169 */
2170void
2171xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2172 if (obj == NULL) return;
2173 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002174 if (obj->boolval) {
2175 obj->type = XPATH_XSLT_TREE;
2176 if (obj->nodesetval != NULL)
2177 xmlXPathFreeValueTree(obj->nodesetval);
2178 } else {
2179 if (obj->nodesetval != NULL)
2180 xmlXPathFreeNodeSet(obj->nodesetval);
2181 }
Owen Taylor3473f882001-02-23 17:55:21 +00002182#ifdef LIBXML_XPTR_ENABLED
2183 } else if (obj->type == XPATH_LOCATIONSET) {
2184 if (obj->user != NULL)
2185 xmlXPtrFreeLocationSet(obj->user);
2186#endif
2187 } else if (obj->type == XPATH_STRING) {
2188 if (obj->stringval != NULL)
2189 xmlFree(obj->stringval);
2190 } else if (obj->type == XPATH_XSLT_TREE) {
2191 if (obj->nodesetval != NULL)
2192 xmlXPathFreeValueTree(obj->nodesetval);
2193 }
2194
Owen Taylor3473f882001-02-23 17:55:21 +00002195 xmlFree(obj);
2196}
2197
2198/************************************************************************
2199 * *
2200 * Routines to handle XPath contexts *
2201 * *
2202 ************************************************************************/
2203
2204/**
2205 * xmlXPathNewContext:
2206 * @doc: the XML document
2207 *
2208 * Create a new xmlXPathContext
2209 *
2210 * Returns the xmlXPathContext just allocated.
2211 */
2212xmlXPathContextPtr
2213xmlXPathNewContext(xmlDocPtr doc) {
2214 xmlXPathContextPtr ret;
2215
2216 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2217 if (ret == NULL) {
2218 xmlGenericError(xmlGenericErrorContext,
2219 "xmlXPathNewContext: out of memory\n");
2220 return(NULL);
2221 }
2222 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2223 ret->doc = doc;
2224 ret->node = NULL;
2225
2226 ret->varHash = NULL;
2227
2228 ret->nb_types = 0;
2229 ret->max_types = 0;
2230 ret->types = NULL;
2231
2232 ret->funcHash = xmlHashCreate(0);
2233
2234 ret->nb_axis = 0;
2235 ret->max_axis = 0;
2236 ret->axis = NULL;
2237
2238 ret->nsHash = NULL;
2239 ret->user = NULL;
2240
2241 ret->contextSize = -1;
2242 ret->proximityPosition = -1;
2243
2244 xmlXPathRegisterAllFunctions(ret);
2245
2246 return(ret);
2247}
2248
2249/**
2250 * xmlXPathFreeContext:
2251 * @ctxt: the context to free
2252 *
2253 * Free up an xmlXPathContext
2254 */
2255void
2256xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2257 xmlXPathRegisteredNsCleanup(ctxt);
2258 xmlXPathRegisteredFuncsCleanup(ctxt);
2259 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002260 xmlFree(ctxt);
2261}
2262
2263/************************************************************************
2264 * *
2265 * Routines to handle XPath parser contexts *
2266 * *
2267 ************************************************************************/
2268
2269#define CHECK_CTXT(ctxt) \
2270 if (ctxt == NULL) { \
2271 xmlGenericError(xmlGenericErrorContext, \
2272 "%s:%d Internal error: ctxt == NULL\n", \
2273 __FILE__, __LINE__); \
2274 } \
2275
2276
2277#define CHECK_CONTEXT(ctxt) \
2278 if (ctxt == NULL) { \
2279 xmlGenericError(xmlGenericErrorContext, \
2280 "%s:%d Internal error: no context\n", \
2281 __FILE__, __LINE__); \
2282 } \
2283 else if (ctxt->doc == NULL) { \
2284 xmlGenericError(xmlGenericErrorContext, \
2285 "%s:%d Internal error: no document\n", \
2286 __FILE__, __LINE__); \
2287 } \
2288 else if (ctxt->doc->children == NULL) { \
2289 xmlGenericError(xmlGenericErrorContext, \
2290 "%s:%d Internal error: document without root\n", \
2291 __FILE__, __LINE__); \
2292 } \
2293
2294
2295/**
2296 * xmlXPathNewParserContext:
2297 * @str: the XPath expression
2298 * @ctxt: the XPath context
2299 *
2300 * Create a new xmlXPathParserContext
2301 *
2302 * Returns the xmlXPathParserContext just allocated.
2303 */
2304xmlXPathParserContextPtr
2305xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2306 xmlXPathParserContextPtr ret;
2307
2308 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2309 if (ret == NULL) {
2310 xmlGenericError(xmlGenericErrorContext,
2311 "xmlXPathNewParserContext: out of memory\n");
2312 return(NULL);
2313 }
2314 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2315 ret->cur = ret->base = str;
2316 ret->context = ctxt;
2317
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002318 ret->comp = xmlXPathNewCompExpr();
2319 if (ret->comp == NULL) {
2320 xmlFree(ret->valueTab);
2321 xmlFree(ret);
2322 return(NULL);
2323 }
2324
2325 return(ret);
2326}
2327
2328/**
2329 * xmlXPathCompParserContext:
2330 * @comp: the XPath compiled expression
2331 * @ctxt: the XPath context
2332 *
2333 * Create a new xmlXPathParserContext when processing a compiled expression
2334 *
2335 * Returns the xmlXPathParserContext just allocated.
2336 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002337static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002338xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2339 xmlXPathParserContextPtr ret;
2340
2341 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2342 if (ret == NULL) {
2343 xmlGenericError(xmlGenericErrorContext,
2344 "xmlXPathNewParserContext: out of memory\n");
2345 return(NULL);
2346 }
2347 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2348
Owen Taylor3473f882001-02-23 17:55:21 +00002349 /* Allocate the value stack */
2350 ret->valueTab = (xmlXPathObjectPtr *)
2351 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002352 if (ret->valueTab == NULL) {
2353 xmlFree(ret);
2354 xmlGenericError(xmlGenericErrorContext,
2355 "xmlXPathNewParserContext: out of memory\n");
2356 return(NULL);
2357 }
Owen Taylor3473f882001-02-23 17:55:21 +00002358 ret->valueNr = 0;
2359 ret->valueMax = 10;
2360 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002361
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002362 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002363 ret->comp = comp;
2364
Owen Taylor3473f882001-02-23 17:55:21 +00002365 return(ret);
2366}
2367
2368/**
2369 * xmlXPathFreeParserContext:
2370 * @ctxt: the context to free
2371 *
2372 * Free up an xmlXPathParserContext
2373 */
2374void
2375xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2376 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002377 xmlFree(ctxt->valueTab);
2378 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002379 if (ctxt->comp)
2380 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002381 xmlFree(ctxt);
2382}
2383
2384/************************************************************************
2385 * *
2386 * The implicit core function library *
2387 * *
2388 ************************************************************************/
2389
2390/*
2391 * Auto-pop and cast to a number
2392 */
2393void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
2394
2395
2396#define POP_FLOAT \
2397 arg = valuePop(ctxt); \
2398 if (arg == NULL) { \
2399 XP_ERROR(XPATH_INVALID_OPERAND); \
2400 } \
2401 if (arg->type != XPATH_NUMBER) { \
2402 valuePush(ctxt, arg); \
2403 xmlXPathNumberFunction(ctxt, 1); \
2404 arg = valuePop(ctxt); \
2405 }
2406
2407/**
2408 * xmlXPathCompareNodeSetFloat:
2409 * @ctxt: the XPath Parser context
2410 * @inf: less than (1) or greater than (0)
2411 * @strict: is the comparison strict
2412 * @arg: the node set
2413 * @f: the value
2414 *
2415 * Implement the compare operation between a nodeset and a number
2416 * @ns < @val (1, 1, ...
2417 * @ns <= @val (1, 0, ...
2418 * @ns > @val (0, 1, ...
2419 * @ns >= @val (0, 0, ...
2420 *
2421 * If one object to be compared is a node-set and the other is a number,
2422 * then the comparison will be true if and only if there is a node in the
2423 * node-set such that the result of performing the comparison on the number
2424 * to be compared and on the result of converting the string-value of that
2425 * node to a number using the number function is true.
2426 *
2427 * Returns 0 or 1 depending on the results of the test.
2428 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002429static int
Owen Taylor3473f882001-02-23 17:55:21 +00002430xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2431 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2432 int i, ret = 0;
2433 xmlNodeSetPtr ns;
2434 xmlChar *str2;
2435
2436 if ((f == NULL) || (arg == NULL) ||
2437 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2438 xmlXPathFreeObject(arg);
2439 xmlXPathFreeObject(f);
2440 return(0);
2441 }
2442 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002443 if (ns != NULL) {
2444 for (i = 0;i < ns->nodeNr;i++) {
2445 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2446 if (str2 != NULL) {
2447 valuePush(ctxt,
2448 xmlXPathNewString(str2));
2449 xmlFree(str2);
2450 xmlXPathNumberFunction(ctxt, 1);
2451 valuePush(ctxt, xmlXPathObjectCopy(f));
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(f);
2460 return(ret);
2461}
2462
2463/**
2464 * xmlXPathCompareNodeSetString:
2465 * @ctxt: the XPath Parser context
2466 * @inf: less than (1) or greater than (0)
2467 * @strict: is the comparison strict
2468 * @arg: the node set
2469 * @s: the value
2470 *
2471 * Implement the compare operation between a nodeset and a string
2472 * @ns < @val (1, 1, ...
2473 * @ns <= @val (1, 0, ...
2474 * @ns > @val (0, 1, ...
2475 * @ns >= @val (0, 0, ...
2476 *
2477 * If one object to be compared is a node-set and the other is a string,
2478 * then the comparison will be true if and only if there is a node in
2479 * the node-set such that the result of performing the comparison on the
2480 * string-value of the node and the other string is true.
2481 *
2482 * Returns 0 or 1 depending on the results of the test.
2483 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002484static int
Owen Taylor3473f882001-02-23 17:55:21 +00002485xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2486 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2487 int i, ret = 0;
2488 xmlNodeSetPtr ns;
2489 xmlChar *str2;
2490
2491 if ((s == NULL) || (arg == NULL) ||
2492 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2493 xmlXPathFreeObject(arg);
2494 xmlXPathFreeObject(s);
2495 return(0);
2496 }
2497 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002498 if (ns != NULL) {
2499 for (i = 0;i < ns->nodeNr;i++) {
2500 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2501 if (str2 != NULL) {
2502 valuePush(ctxt,
2503 xmlXPathNewString(str2));
2504 xmlFree(str2);
2505 valuePush(ctxt, xmlXPathObjectCopy(s));
2506 ret = xmlXPathCompareValues(ctxt, inf, strict);
2507 if (ret)
2508 break;
2509 }
2510 }
Owen Taylor3473f882001-02-23 17:55:21 +00002511 }
2512 xmlXPathFreeObject(arg);
2513 xmlXPathFreeObject(s);
2514 return(ret);
2515}
2516
2517/**
2518 * xmlXPathCompareNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00002519 * @op: less than (-1), equal (0) or greater than (1)
2520 * @strict: is the comparison strict
2521 * @arg1: the fist node set object
2522 * @arg2: the second node set object
2523 *
2524 * Implement the compare operation on nodesets:
2525 *
2526 * If both objects to be compared are node-sets, then the comparison
2527 * will be true if and only if there is a node in the first node-set
2528 * and a node in the second node-set such that the result of performing
2529 * the comparison on the string-values of the two nodes is true.
2530 * ....
2531 * When neither object to be compared is a node-set and the operator
2532 * is <=, <, >= or >, then the objects are compared by converting both
2533 * objects to numbers and comparing the numbers according to IEEE 754.
2534 * ....
2535 * The number function converts its argument to a number as follows:
2536 * - a string that consists of optional whitespace followed by an
2537 * optional minus sign followed by a Number followed by whitespace
2538 * is converted to the IEEE 754 number that is nearest (according
2539 * to the IEEE 754 round-to-nearest rule) to the mathematical value
2540 * represented by the string; any other string is converted to NaN
2541 *
2542 * Conclusion all nodes need to be converted first to their string value
2543 * and then the comparison must be done when possible
2544 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002545static int
2546xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00002547 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2548 int i, j, init = 0;
2549 double val1;
2550 double *values2;
2551 int ret = 0;
2552 xmlChar *str;
2553 xmlNodeSetPtr ns1;
2554 xmlNodeSetPtr ns2;
2555
2556 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002557 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
2558 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002559 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002560 }
Owen Taylor3473f882001-02-23 17:55:21 +00002561 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00002562 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
2563 xmlXPathFreeObject(arg1);
2564 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002565 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002566 }
Owen Taylor3473f882001-02-23 17:55:21 +00002567
2568 ns1 = arg1->nodesetval;
2569 ns2 = arg2->nodesetval;
2570
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002571 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002572 xmlXPathFreeObject(arg1);
2573 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002574 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002575 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002576 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002577 xmlXPathFreeObject(arg1);
2578 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002579 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002580 }
Owen Taylor3473f882001-02-23 17:55:21 +00002581
2582 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
2583 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00002584 xmlXPathFreeObject(arg1);
2585 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002586 return(0);
2587 }
2588 for (i = 0;i < ns1->nodeNr;i++) {
2589 str = xmlNodeGetContent(ns1->nodeTab[i]);
2590 if (str == NULL)
2591 continue;
2592 val1 = xmlXPathStringEvalNumber(str);
2593 xmlFree(str);
2594 if (isnan(val1))
2595 continue;
2596 for (j = 0;j < ns2->nodeNr;j++) {
2597 if (init == 0) {
2598 str = xmlNodeGetContent(ns2->nodeTab[j]);
2599 if (str == NULL) {
2600 values2[j] = xmlXPathNAN;
2601 } else {
2602 values2[j] = xmlXPathStringEvalNumber(str);
2603 xmlFree(str);
2604 }
2605 }
2606 if (isnan(values2[j]))
2607 continue;
2608 if (inf && strict)
2609 ret = (val1 < values2[j]);
2610 else if (inf && !strict)
2611 ret = (val1 <= values2[j]);
2612 else if (!inf && strict)
2613 ret = (val1 > values2[j]);
2614 else if (!inf && !strict)
2615 ret = (val1 >= values2[j]);
2616 if (ret)
2617 break;
2618 }
2619 if (ret)
2620 break;
2621 init = 1;
2622 }
2623 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00002624 xmlXPathFreeObject(arg1);
2625 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00002626 return(ret);
2627 return(0);
2628}
2629
2630/**
2631 * xmlXPathCompareNodeSetValue:
2632 * @ctxt: the XPath Parser context
2633 * @inf: less than (1) or greater than (0)
2634 * @strict: is the comparison strict
2635 * @arg: the node set
2636 * @val: the value
2637 *
2638 * Implement the compare operation between a nodeset and a value
2639 * @ns < @val (1, 1, ...
2640 * @ns <= @val (1, 0, ...
2641 * @ns > @val (0, 1, ...
2642 * @ns >= @val (0, 0, ...
2643 *
2644 * If one object to be compared is a node-set and the other is a boolean,
2645 * then the comparison will be true if and only if the result of performing
2646 * the comparison on the boolean and on the result of converting
2647 * the node-set to a boolean using the boolean function is true.
2648 *
2649 * Returns 0 or 1 depending on the results of the test.
2650 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002651static int
Owen Taylor3473f882001-02-23 17:55:21 +00002652xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
2653 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
2654 if ((val == NULL) || (arg == NULL) ||
2655 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2656 return(0);
2657
2658 switch(val->type) {
2659 case XPATH_NUMBER:
2660 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
2661 case XPATH_NODESET:
2662 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002663 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00002664 case XPATH_STRING:
2665 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
2666 case XPATH_BOOLEAN:
2667 valuePush(ctxt, arg);
2668 xmlXPathBooleanFunction(ctxt, 1);
2669 valuePush(ctxt, val);
2670 return(xmlXPathCompareValues(ctxt, inf, strict));
2671 default:
2672 TODO
2673 return(0);
2674 }
2675 return(0);
2676}
2677
2678/**
2679 * xmlXPathEqualNodeSetString
2680 * @arg: the nodeset object argument
2681 * @str: the string to compare to.
2682 *
2683 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2684 * If one object to be compared is a node-set and the other is a string,
2685 * then the comparison will be true if and only if there is a node in
2686 * the node-set such that the result of performing the comparison on the
2687 * string-value of the node and the other string is true.
2688 *
2689 * Returns 0 or 1 depending on the results of the test.
2690 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002691static int
Owen Taylor3473f882001-02-23 17:55:21 +00002692xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
2693 int i;
2694 xmlNodeSetPtr ns;
2695 xmlChar *str2;
2696
2697 if ((str == NULL) || (arg == NULL) ||
2698 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2699 return(0);
2700 ns = arg->nodesetval;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002701 if (ns == NULL)
2702 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002703 if (ns->nodeNr <= 0)
2704 return(0);
2705 for (i = 0;i < ns->nodeNr;i++) {
2706 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2707 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
2708 xmlFree(str2);
2709 return(1);
2710 }
2711 if (str2 != NULL)
2712 xmlFree(str2);
2713 }
2714 return(0);
2715}
2716
2717/**
2718 * xmlXPathEqualNodeSetFloat
2719 * @arg: the nodeset object argument
2720 * @f: the float to compare to
2721 *
2722 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2723 * If one object to be compared is a node-set and the other is a number,
2724 * then the comparison will be true if and only if there is a node in
2725 * the node-set such that the result of performing the comparison on the
2726 * number to be compared and on the result of converting the string-value
2727 * of that node to a number using the number function is true.
2728 *
2729 * Returns 0 or 1 depending on the results of the test.
2730 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002731static int
Owen Taylor3473f882001-02-23 17:55:21 +00002732xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
2733 char buf[100] = "";
2734
2735 if ((arg == NULL) ||
2736 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2737 return(0);
2738
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002739 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00002740 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
2741}
2742
2743
2744/**
2745 * xmlXPathEqualNodeSets
2746 * @arg1: first nodeset object argument
2747 * @arg2: second nodeset object argument
2748 *
2749 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
2750 * If both objects to be compared are node-sets, then the comparison
2751 * will be true if and only if there is a node in the first node-set and
2752 * a node in the second node-set such that the result of performing the
2753 * comparison on the string-values of the two nodes is true.
2754 *
2755 * (needless to say, this is a costly operation)
2756 *
2757 * Returns 0 or 1 depending on the results of the test.
2758 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002759static int
Owen Taylor3473f882001-02-23 17:55:21 +00002760xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2761 int i, j;
2762 xmlChar **values1;
2763 xmlChar **values2;
2764 int ret = 0;
2765 xmlNodeSetPtr ns1;
2766 xmlNodeSetPtr ns2;
2767
2768 if ((arg1 == NULL) ||
2769 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
2770 return(0);
2771 if ((arg2 == NULL) ||
2772 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
2773 return(0);
2774
2775 ns1 = arg1->nodesetval;
2776 ns2 = arg2->nodesetval;
2777
Daniel Veillard911f49a2001-04-07 15:39:35 +00002778 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00002779 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002780 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00002781 return(0);
2782
2783 /*
2784 * check if there is a node pertaining to both sets
2785 */
2786 for (i = 0;i < ns1->nodeNr;i++)
2787 for (j = 0;j < ns2->nodeNr;j++)
2788 if (ns1->nodeTab[i] == ns2->nodeTab[j])
2789 return(1);
2790
2791 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
2792 if (values1 == NULL)
2793 return(0);
2794 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
2795 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
2796 if (values2 == NULL) {
2797 xmlFree(values1);
2798 return(0);
2799 }
2800 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
2801 for (i = 0;i < ns1->nodeNr;i++) {
2802 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
2803 for (j = 0;j < ns2->nodeNr;j++) {
2804 if (i == 0)
2805 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
2806 ret = xmlStrEqual(values1[i], values2[j]);
2807 if (ret)
2808 break;
2809 }
2810 if (ret)
2811 break;
2812 }
2813 for (i = 0;i < ns1->nodeNr;i++)
2814 if (values1[i] != NULL)
2815 xmlFree(values1[i]);
2816 for (j = 0;j < ns2->nodeNr;j++)
2817 if (values2[j] != NULL)
2818 xmlFree(values2[j]);
2819 xmlFree(values1);
2820 xmlFree(values2);
2821 return(ret);
2822}
2823
2824/**
2825 * xmlXPathEqualValues:
2826 * @ctxt: the XPath Parser context
2827 *
2828 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2829 *
2830 * Returns 0 or 1 depending on the results of the test.
2831 */
2832int
2833xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
2834 xmlXPathObjectPtr arg1, arg2;
2835 int ret = 0;
2836
2837 arg1 = valuePop(ctxt);
2838 if (arg1 == NULL)
2839 XP_ERROR0(XPATH_INVALID_OPERAND);
2840
2841 arg2 = valuePop(ctxt);
2842 if (arg2 == NULL) {
2843 xmlXPathFreeObject(arg1);
2844 XP_ERROR0(XPATH_INVALID_OPERAND);
2845 }
2846
2847 if (arg1 == arg2) {
2848#ifdef DEBUG_EXPR
2849 xmlGenericError(xmlGenericErrorContext,
2850 "Equal: by pointer\n");
2851#endif
2852 return(1);
2853 }
2854
2855 switch (arg1->type) {
2856 case XPATH_UNDEFINED:
2857#ifdef DEBUG_EXPR
2858 xmlGenericError(xmlGenericErrorContext,
2859 "Equal: undefined\n");
2860#endif
2861 break;
2862 case XPATH_XSLT_TREE:
2863 case XPATH_NODESET:
2864 switch (arg2->type) {
2865 case XPATH_UNDEFINED:
2866#ifdef DEBUG_EXPR
2867 xmlGenericError(xmlGenericErrorContext,
2868 "Equal: undefined\n");
2869#endif
2870 break;
2871 case XPATH_XSLT_TREE:
2872 case XPATH_NODESET:
2873 ret = xmlXPathEqualNodeSets(arg1, arg2);
2874 break;
2875 case XPATH_BOOLEAN:
2876 if ((arg1->nodesetval == NULL) ||
2877 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2878 else
2879 ret = 1;
2880 ret = (ret == arg2->boolval);
2881 break;
2882 case XPATH_NUMBER:
2883 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2884 break;
2885 case XPATH_STRING:
2886 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2887 break;
2888 case XPATH_USERS:
2889 case XPATH_POINT:
2890 case XPATH_RANGE:
2891 case XPATH_LOCATIONSET:
2892 TODO
2893 break;
2894 }
2895 break;
2896 case XPATH_BOOLEAN:
2897 switch (arg2->type) {
2898 case XPATH_UNDEFINED:
2899#ifdef DEBUG_EXPR
2900 xmlGenericError(xmlGenericErrorContext,
2901 "Equal: undefined\n");
2902#endif
2903 break;
2904 case XPATH_NODESET:
2905 case XPATH_XSLT_TREE:
2906 if ((arg2->nodesetval == NULL) ||
2907 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2908 else
2909 ret = 1;
2910 break;
2911 case XPATH_BOOLEAN:
2912#ifdef DEBUG_EXPR
2913 xmlGenericError(xmlGenericErrorContext,
2914 "Equal: %d boolean %d \n",
2915 arg1->boolval, arg2->boolval);
2916#endif
2917 ret = (arg1->boolval == arg2->boolval);
2918 break;
2919 case XPATH_NUMBER:
2920 if (arg2->floatval) ret = 1;
2921 else ret = 0;
2922 ret = (arg1->boolval == ret);
2923 break;
2924 case XPATH_STRING:
2925 if ((arg2->stringval == NULL) ||
2926 (arg2->stringval[0] == 0)) ret = 0;
2927 else
2928 ret = 1;
2929 ret = (arg1->boolval == ret);
2930 break;
2931 case XPATH_USERS:
2932 case XPATH_POINT:
2933 case XPATH_RANGE:
2934 case XPATH_LOCATIONSET:
2935 TODO
2936 break;
2937 }
2938 break;
2939 case XPATH_NUMBER:
2940 switch (arg2->type) {
2941 case XPATH_UNDEFINED:
2942#ifdef DEBUG_EXPR
2943 xmlGenericError(xmlGenericErrorContext,
2944 "Equal: undefined\n");
2945#endif
2946 break;
2947 case XPATH_NODESET:
2948 case XPATH_XSLT_TREE:
2949 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2950 break;
2951 case XPATH_BOOLEAN:
2952 if (arg1->floatval) ret = 1;
2953 else ret = 0;
2954 ret = (arg2->boolval == ret);
2955 break;
2956 case XPATH_STRING:
2957 valuePush(ctxt, arg2);
2958 xmlXPathNumberFunction(ctxt, 1);
2959 arg2 = valuePop(ctxt);
2960 /* no break on purpose */
2961 case XPATH_NUMBER:
2962 ret = (arg1->floatval == arg2->floatval);
2963 break;
2964 case XPATH_USERS:
2965 case XPATH_POINT:
2966 case XPATH_RANGE:
2967 case XPATH_LOCATIONSET:
2968 TODO
2969 break;
2970 }
2971 break;
2972 case XPATH_STRING:
2973 switch (arg2->type) {
2974 case XPATH_UNDEFINED:
2975#ifdef DEBUG_EXPR
2976 xmlGenericError(xmlGenericErrorContext,
2977 "Equal: undefined\n");
2978#endif
2979 break;
2980 case XPATH_NODESET:
2981 case XPATH_XSLT_TREE:
2982 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2983 break;
2984 case XPATH_BOOLEAN:
2985 if ((arg1->stringval == NULL) ||
2986 (arg1->stringval[0] == 0)) ret = 0;
2987 else
2988 ret = 1;
2989 ret = (arg2->boolval == ret);
2990 break;
2991 case XPATH_STRING:
2992 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
2993 break;
2994 case XPATH_NUMBER:
2995 valuePush(ctxt, arg1);
2996 xmlXPathNumberFunction(ctxt, 1);
2997 arg1 = valuePop(ctxt);
2998 ret = (arg1->floatval == arg2->floatval);
2999 break;
3000 case XPATH_USERS:
3001 case XPATH_POINT:
3002 case XPATH_RANGE:
3003 case XPATH_LOCATIONSET:
3004 TODO
3005 break;
3006 }
3007 break;
3008 case XPATH_USERS:
3009 case XPATH_POINT:
3010 case XPATH_RANGE:
3011 case XPATH_LOCATIONSET:
3012 TODO
3013 break;
3014 }
3015 xmlXPathFreeObject(arg1);
3016 xmlXPathFreeObject(arg2);
3017 return(ret);
3018}
3019
3020
3021/**
3022 * xmlXPathCompareValues:
3023 * @ctxt: the XPath Parser context
3024 * @inf: less than (1) or greater than (0)
3025 * @strict: is the comparison strict
3026 *
3027 * Implement the compare operation on XPath objects:
3028 * @arg1 < @arg2 (1, 1, ...
3029 * @arg1 <= @arg2 (1, 0, ...
3030 * @arg1 > @arg2 (0, 1, ...
3031 * @arg1 >= @arg2 (0, 0, ...
3032 *
3033 * When neither object to be compared is a node-set and the operator is
3034 * <=, <, >=, >, then the objects are compared by converted both objects
3035 * to numbers and comparing the numbers according to IEEE 754. The <
3036 * comparison will be true if and only if the first number is less than the
3037 * second number. The <= comparison will be true if and only if the first
3038 * number is less than or equal to the second number. The > comparison
3039 * will be true if and only if the first number is greater than the second
3040 * number. The >= comparison will be true if and only if the first number
3041 * is greater than or equal to the second number.
3042 *
3043 * Returns 1 if the comparaison succeeded, 0 if it failed
3044 */
3045int
3046xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3047 int ret = 0;
3048 xmlXPathObjectPtr arg1, arg2;
3049
3050 arg2 = valuePop(ctxt);
3051 if (arg2 == NULL) {
3052 XP_ERROR0(XPATH_INVALID_OPERAND);
3053 }
3054
3055 arg1 = valuePop(ctxt);
3056 if (arg1 == NULL) {
3057 xmlXPathFreeObject(arg2);
3058 XP_ERROR0(XPATH_INVALID_OPERAND);
3059 }
3060
3061 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3062 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003063 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003064 } else {
3065 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003066 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3067 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003068 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003069 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3070 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003071 }
3072 }
3073 return(ret);
3074 }
3075
3076 if (arg1->type != XPATH_NUMBER) {
3077 valuePush(ctxt, arg1);
3078 xmlXPathNumberFunction(ctxt, 1);
3079 arg1 = valuePop(ctxt);
3080 }
3081 if (arg1->type != XPATH_NUMBER) {
3082 xmlXPathFreeObject(arg1);
3083 xmlXPathFreeObject(arg2);
3084 XP_ERROR0(XPATH_INVALID_OPERAND);
3085 }
3086 if (arg2->type != XPATH_NUMBER) {
3087 valuePush(ctxt, arg2);
3088 xmlXPathNumberFunction(ctxt, 1);
3089 arg2 = valuePop(ctxt);
3090 }
3091 if (arg2->type != XPATH_NUMBER) {
3092 xmlXPathFreeObject(arg1);
3093 xmlXPathFreeObject(arg2);
3094 XP_ERROR0(XPATH_INVALID_OPERAND);
3095 }
3096 /*
3097 * Add tests for infinity and nan
3098 * => feedback on 3.4 for Inf and NaN
3099 */
3100 if (inf && strict)
3101 ret = (arg1->floatval < arg2->floatval);
3102 else if (inf && !strict)
3103 ret = (arg1->floatval <= arg2->floatval);
3104 else if (!inf && strict)
3105 ret = (arg1->floatval > arg2->floatval);
3106 else if (!inf && !strict)
3107 ret = (arg1->floatval >= arg2->floatval);
3108 xmlXPathFreeObject(arg1);
3109 xmlXPathFreeObject(arg2);
3110 return(ret);
3111}
3112
3113/**
3114 * xmlXPathValueFlipSign:
3115 * @ctxt: the XPath Parser context
3116 *
3117 * Implement the unary - operation on an XPath object
3118 * The numeric operators convert their operands to numbers as if
3119 * by calling the number function.
3120 */
3121void
3122xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
3123 xmlXPathObjectPtr arg;
3124
3125 POP_FLOAT
3126 arg->floatval = -arg->floatval;
3127 valuePush(ctxt, arg);
3128}
3129
3130/**
3131 * xmlXPathAddValues:
3132 * @ctxt: the XPath Parser context
3133 *
3134 * Implement the add operation on XPath objects:
3135 * The numeric operators convert their operands to numbers as if
3136 * by calling the number function.
3137 */
3138void
3139xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3140 xmlXPathObjectPtr arg;
3141 double val;
3142
3143 POP_FLOAT
3144 val = arg->floatval;
3145 xmlXPathFreeObject(arg);
3146
3147 POP_FLOAT
3148 arg->floatval += val;
3149 valuePush(ctxt, arg);
3150}
3151
3152/**
3153 * xmlXPathSubValues:
3154 * @ctxt: the XPath Parser context
3155 *
3156 * Implement the substraction operation on XPath objects:
3157 * The numeric operators convert their operands to numbers as if
3158 * by calling the number function.
3159 */
3160void
3161xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3162 xmlXPathObjectPtr arg;
3163 double val;
3164
3165 POP_FLOAT
3166 val = arg->floatval;
3167 xmlXPathFreeObject(arg);
3168
3169 POP_FLOAT
3170 arg->floatval -= val;
3171 valuePush(ctxt, arg);
3172}
3173
3174/**
3175 * xmlXPathMultValues:
3176 * @ctxt: the XPath Parser context
3177 *
3178 * Implement the multiply operation on XPath objects:
3179 * The numeric operators convert their operands to numbers as if
3180 * by calling the number function.
3181 */
3182void
3183xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3184 xmlXPathObjectPtr arg;
3185 double val;
3186
3187 POP_FLOAT
3188 val = arg->floatval;
3189 xmlXPathFreeObject(arg);
3190
3191 POP_FLOAT
3192 arg->floatval *= val;
3193 valuePush(ctxt, arg);
3194}
3195
3196/**
3197 * xmlXPathDivValues:
3198 * @ctxt: the XPath Parser context
3199 *
3200 * Implement the div operation on XPath objects @arg1 / @arg2:
3201 * The numeric operators convert their operands to numbers as if
3202 * by calling the number function.
3203 */
3204void
3205xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3206 xmlXPathObjectPtr arg;
3207 double val;
3208
3209 POP_FLOAT
3210 val = arg->floatval;
3211 xmlXPathFreeObject(arg);
3212
3213 POP_FLOAT
3214 arg->floatval /= val;
3215 valuePush(ctxt, arg);
3216}
3217
3218/**
3219 * xmlXPathModValues:
3220 * @ctxt: the XPath Parser context
3221 *
3222 * Implement the mod operation on XPath objects: @arg1 / @arg2
3223 * The numeric operators convert their operands to numbers as if
3224 * by calling the number function.
3225 */
3226void
3227xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3228 xmlXPathObjectPtr arg;
3229 int arg1, arg2;
3230
3231 POP_FLOAT
3232 arg2 = (int) arg->floatval;
3233 xmlXPathFreeObject(arg);
3234
3235 POP_FLOAT
3236 arg1 = (int) arg->floatval;
3237 arg->floatval = arg1 % arg2;
3238 valuePush(ctxt, arg);
3239}
3240
3241/************************************************************************
3242 * *
3243 * The traversal functions *
3244 * *
3245 ************************************************************************/
3246
Owen Taylor3473f882001-02-23 17:55:21 +00003247/*
3248 * A traversal function enumerates nodes along an axis.
3249 * Initially it must be called with NULL, and it indicates
3250 * termination on the axis by returning NULL.
3251 */
3252typedef xmlNodePtr (*xmlXPathTraversalFunction)
3253 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3254
3255/**
3256 * xmlXPathNextSelf:
3257 * @ctxt: the XPath Parser context
3258 * @cur: the current node in the traversal
3259 *
3260 * Traversal function for the "self" direction
3261 * The self axis contains just the context node itself
3262 *
3263 * Returns the next element following that axis
3264 */
3265xmlNodePtr
3266xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3267 if (cur == NULL)
3268 return(ctxt->context->node);
3269 return(NULL);
3270}
3271
3272/**
3273 * xmlXPathNextChild:
3274 * @ctxt: the XPath Parser context
3275 * @cur: the current node in the traversal
3276 *
3277 * Traversal function for the "child" direction
3278 * The child axis contains the children of the context node in document order.
3279 *
3280 * Returns the next element following that axis
3281 */
3282xmlNodePtr
3283xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3284 if (cur == NULL) {
3285 if (ctxt->context->node == NULL) return(NULL);
3286 switch (ctxt->context->node->type) {
3287 case XML_ELEMENT_NODE:
3288 case XML_TEXT_NODE:
3289 case XML_CDATA_SECTION_NODE:
3290 case XML_ENTITY_REF_NODE:
3291 case XML_ENTITY_NODE:
3292 case XML_PI_NODE:
3293 case XML_COMMENT_NODE:
3294 case XML_NOTATION_NODE:
3295 case XML_DTD_NODE:
3296 return(ctxt->context->node->children);
3297 case XML_DOCUMENT_NODE:
3298 case XML_DOCUMENT_TYPE_NODE:
3299 case XML_DOCUMENT_FRAG_NODE:
3300 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003301#ifdef LIBXML_DOCB_ENABLED
3302 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003303#endif
3304 return(((xmlDocPtr) ctxt->context->node)->children);
3305 case XML_ELEMENT_DECL:
3306 case XML_ATTRIBUTE_DECL:
3307 case XML_ENTITY_DECL:
3308 case XML_ATTRIBUTE_NODE:
3309 case XML_NAMESPACE_DECL:
3310 case XML_XINCLUDE_START:
3311 case XML_XINCLUDE_END:
3312 return(NULL);
3313 }
3314 return(NULL);
3315 }
3316 if ((cur->type == XML_DOCUMENT_NODE) ||
3317 (cur->type == XML_HTML_DOCUMENT_NODE))
3318 return(NULL);
3319 return(cur->next);
3320}
3321
3322/**
3323 * xmlXPathNextDescendant:
3324 * @ctxt: the XPath Parser context
3325 * @cur: the current node in the traversal
3326 *
3327 * Traversal function for the "descendant" direction
3328 * the descendant axis contains the descendants of the context node in document
3329 * order; a descendant is a child or a child of a child and so on.
3330 *
3331 * Returns the next element following that axis
3332 */
3333xmlNodePtr
3334xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3335 if (cur == NULL) {
3336 if (ctxt->context->node == NULL)
3337 return(NULL);
3338 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3339 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3340 return(NULL);
3341
3342 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3343 return(ctxt->context->doc->children);
3344 return(ctxt->context->node->children);
3345 }
3346
3347 if (cur->children != NULL)
3348 {
3349 if (cur->children->type != XML_ENTITY_DECL)
3350 return(cur->children);
3351 }
3352 if (cur->next != NULL) return(cur->next);
3353
3354 do {
3355 cur = cur->parent;
3356 if (cur == NULL) return(NULL);
3357 if (cur == ctxt->context->node) return(NULL);
3358 if (cur->next != NULL) {
3359 cur = cur->next;
3360 return(cur);
3361 }
3362 } while (cur != NULL);
3363 return(cur);
3364}
3365
3366/**
3367 * xmlXPathNextDescendantOrSelf:
3368 * @ctxt: the XPath Parser context
3369 * @cur: the current node in the traversal
3370 *
3371 * Traversal function for the "descendant-or-self" direction
3372 * the descendant-or-self axis contains the context node and the descendants
3373 * of the context node in document order; thus the context node is the first
3374 * node on the axis, and the first child of the context node is the second node
3375 * on the axis
3376 *
3377 * Returns the next element following that axis
3378 */
3379xmlNodePtr
3380xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3381 if (cur == NULL) {
3382 if (ctxt->context->node == NULL)
3383 return(NULL);
3384 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3385 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3386 return(NULL);
3387 return(ctxt->context->node);
3388 }
3389
3390 return(xmlXPathNextDescendant(ctxt, cur));
3391}
3392
3393/**
3394 * xmlXPathNextParent:
3395 * @ctxt: the XPath Parser context
3396 * @cur: the current node in the traversal
3397 *
3398 * Traversal function for the "parent" direction
3399 * The parent axis contains the parent of the context node, if there is one.
3400 *
3401 * Returns the next element following that axis
3402 */
3403xmlNodePtr
3404xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3405 /*
3406 * the parent of an attribute or namespace node is the element
3407 * to which the attribute or namespace node is attached
3408 * Namespace handling !!!
3409 */
3410 if (cur == NULL) {
3411 if (ctxt->context->node == NULL) return(NULL);
3412 switch (ctxt->context->node->type) {
3413 case XML_ELEMENT_NODE:
3414 case XML_TEXT_NODE:
3415 case XML_CDATA_SECTION_NODE:
3416 case XML_ENTITY_REF_NODE:
3417 case XML_ENTITY_NODE:
3418 case XML_PI_NODE:
3419 case XML_COMMENT_NODE:
3420 case XML_NOTATION_NODE:
3421 case XML_DTD_NODE:
3422 case XML_ELEMENT_DECL:
3423 case XML_ATTRIBUTE_DECL:
3424 case XML_XINCLUDE_START:
3425 case XML_XINCLUDE_END:
3426 case XML_ENTITY_DECL:
3427 if (ctxt->context->node->parent == NULL)
3428 return((xmlNodePtr) ctxt->context->doc);
3429 return(ctxt->context->node->parent);
3430 case XML_ATTRIBUTE_NODE: {
3431 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3432
3433 return(att->parent);
3434 }
3435 case XML_DOCUMENT_NODE:
3436 case XML_DOCUMENT_TYPE_NODE:
3437 case XML_DOCUMENT_FRAG_NODE:
3438 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003439#ifdef LIBXML_DOCB_ENABLED
3440 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003441#endif
3442 return(NULL);
3443 case XML_NAMESPACE_DECL:
3444 /*
3445 * TODO !!! may require extending struct _xmlNs with
3446 * parent field
3447 * C.f. Infoset case...
3448 */
3449 return(NULL);
3450 }
3451 }
3452 return(NULL);
3453}
3454
3455/**
3456 * xmlXPathNextAncestor:
3457 * @ctxt: the XPath Parser context
3458 * @cur: the current node in the traversal
3459 *
3460 * Traversal function for the "ancestor" direction
3461 * the ancestor axis contains the ancestors of the context node; the ancestors
3462 * of the context node consist of the parent of context node and the parent's
3463 * parent and so on; the nodes are ordered in reverse document order; thus the
3464 * parent is the first node on the axis, and the parent's parent is the second
3465 * node on the axis
3466 *
3467 * Returns the next element following that axis
3468 */
3469xmlNodePtr
3470xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3471 /*
3472 * the parent of an attribute or namespace node is the element
3473 * to which the attribute or namespace node is attached
3474 * !!!!!!!!!!!!!
3475 */
3476 if (cur == NULL) {
3477 if (ctxt->context->node == NULL) return(NULL);
3478 switch (ctxt->context->node->type) {
3479 case XML_ELEMENT_NODE:
3480 case XML_TEXT_NODE:
3481 case XML_CDATA_SECTION_NODE:
3482 case XML_ENTITY_REF_NODE:
3483 case XML_ENTITY_NODE:
3484 case XML_PI_NODE:
3485 case XML_COMMENT_NODE:
3486 case XML_DTD_NODE:
3487 case XML_ELEMENT_DECL:
3488 case XML_ATTRIBUTE_DECL:
3489 case XML_ENTITY_DECL:
3490 case XML_NOTATION_NODE:
3491 case XML_XINCLUDE_START:
3492 case XML_XINCLUDE_END:
3493 if (ctxt->context->node->parent == NULL)
3494 return((xmlNodePtr) ctxt->context->doc);
3495 return(ctxt->context->node->parent);
3496 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003497 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00003498
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003499 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003500 }
3501 case XML_DOCUMENT_NODE:
3502 case XML_DOCUMENT_TYPE_NODE:
3503 case XML_DOCUMENT_FRAG_NODE:
3504 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003505#ifdef LIBXML_DOCB_ENABLED
3506 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003507#endif
3508 return(NULL);
3509 case XML_NAMESPACE_DECL:
3510 /*
3511 * TODO !!! may require extending struct _xmlNs with
3512 * parent field
3513 * C.f. Infoset case...
3514 */
3515 return(NULL);
3516 }
3517 return(NULL);
3518 }
3519 if (cur == ctxt->context->doc->children)
3520 return((xmlNodePtr) ctxt->context->doc);
3521 if (cur == (xmlNodePtr) ctxt->context->doc)
3522 return(NULL);
3523 switch (cur->type) {
3524 case XML_ELEMENT_NODE:
3525 case XML_TEXT_NODE:
3526 case XML_CDATA_SECTION_NODE:
3527 case XML_ENTITY_REF_NODE:
3528 case XML_ENTITY_NODE:
3529 case XML_PI_NODE:
3530 case XML_COMMENT_NODE:
3531 case XML_NOTATION_NODE:
3532 case XML_DTD_NODE:
3533 case XML_ELEMENT_DECL:
3534 case XML_ATTRIBUTE_DECL:
3535 case XML_ENTITY_DECL:
3536 case XML_XINCLUDE_START:
3537 case XML_XINCLUDE_END:
3538 return(cur->parent);
3539 case XML_ATTRIBUTE_NODE: {
3540 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3541
3542 return(att->parent);
3543 }
3544 case XML_DOCUMENT_NODE:
3545 case XML_DOCUMENT_TYPE_NODE:
3546 case XML_DOCUMENT_FRAG_NODE:
3547 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003548#ifdef LIBXML_DOCB_ENABLED
3549 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003550#endif
3551 return(NULL);
3552 case XML_NAMESPACE_DECL:
3553 /*
3554 * TODO !!! may require extending struct _xmlNs with
3555 * parent field
3556 * C.f. Infoset case...
3557 */
3558 return(NULL);
3559 }
3560 return(NULL);
3561}
3562
3563/**
3564 * xmlXPathNextAncestorOrSelf:
3565 * @ctxt: the XPath Parser context
3566 * @cur: the current node in the traversal
3567 *
3568 * Traversal function for the "ancestor-or-self" direction
3569 * he ancestor-or-self axis contains the context node and ancestors of
3570 * the context node in reverse document order; thus the context node is
3571 * the first node on the axis, and the context node's parent the second;
3572 * parent here is defined the same as with the parent axis.
3573 *
3574 * Returns the next element following that axis
3575 */
3576xmlNodePtr
3577xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3578 if (cur == NULL)
3579 return(ctxt->context->node);
3580 return(xmlXPathNextAncestor(ctxt, cur));
3581}
3582
3583/**
3584 * xmlXPathNextFollowingSibling:
3585 * @ctxt: the XPath Parser context
3586 * @cur: the current node in the traversal
3587 *
3588 * Traversal function for the "following-sibling" direction
3589 * The following-sibling axis contains the following siblings of the context
3590 * node in document order.
3591 *
3592 * Returns the next element following that axis
3593 */
3594xmlNodePtr
3595xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3596 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3597 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3598 return(NULL);
3599 if (cur == (xmlNodePtr) ctxt->context->doc)
3600 return(NULL);
3601 if (cur == NULL)
3602 return(ctxt->context->node->next);
3603 return(cur->next);
3604}
3605
3606/**
3607 * xmlXPathNextPrecedingSibling:
3608 * @ctxt: the XPath Parser context
3609 * @cur: the current node in the traversal
3610 *
3611 * Traversal function for the "preceding-sibling" direction
3612 * The preceding-sibling axis contains the preceding siblings of the context
3613 * node in reverse document order; the first preceding sibling is first on the
3614 * axis; the sibling preceding that node is the second on the axis and so on.
3615 *
3616 * Returns the next element following that axis
3617 */
3618xmlNodePtr
3619xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3620 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3621 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3622 return(NULL);
3623 if (cur == (xmlNodePtr) ctxt->context->doc)
3624 return(NULL);
3625 if (cur == NULL)
3626 return(ctxt->context->node->prev);
3627 return(cur->prev);
3628}
3629
3630/**
3631 * xmlXPathNextFollowing:
3632 * @ctxt: the XPath Parser context
3633 * @cur: the current node in the traversal
3634 *
3635 * Traversal function for the "following" direction
3636 * The following axis contains all nodes in the same document as the context
3637 * node that are after the context node in document order, excluding any
3638 * descendants and excluding attribute nodes and namespace nodes; the nodes
3639 * are ordered in document order
3640 *
3641 * Returns the next element following that axis
3642 */
3643xmlNodePtr
3644xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3645 if (cur != NULL && cur->children != NULL)
3646 return cur->children ;
3647 if (cur == NULL) cur = ctxt->context->node;
3648 if (cur == NULL) return(NULL) ; /* ERROR */
3649 if (cur->next != NULL) return(cur->next) ;
3650 do {
3651 cur = cur->parent;
3652 if (cur == NULL) return(NULL);
3653 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
3654 if (cur->next != NULL) return(cur->next);
3655 } while (cur != NULL);
3656 return(cur);
3657}
3658
3659/*
3660 * xmlXPathIsAncestor:
3661 * @ancestor: the ancestor node
3662 * @node: the current node
3663 *
3664 * Check that @ancestor is a @node's ancestor
3665 *
3666 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
3667 */
3668static int
3669xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
3670 if ((ancestor == NULL) || (node == NULL)) return(0);
3671 /* nodes need to be in the same document */
3672 if (ancestor->doc != node->doc) return(0);
3673 /* avoid searching if ancestor or node is the root node */
3674 if (ancestor == (xmlNodePtr) node->doc) return(1);
3675 if (node == (xmlNodePtr) ancestor->doc) return(0);
3676 while (node->parent != NULL) {
3677 if (node->parent == ancestor)
3678 return(1);
3679 node = node->parent;
3680 }
3681 return(0);
3682}
3683
3684/**
3685 * xmlXPathNextPreceding:
3686 * @ctxt: the XPath Parser context
3687 * @cur: the current node in the traversal
3688 *
3689 * Traversal function for the "preceding" direction
3690 * the preceding axis contains all nodes in the same document as the context
3691 * node that are before the context node in document order, excluding any
3692 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
3693 * ordered in reverse document order
3694 *
3695 * Returns the next element following that axis
3696 */
3697xmlNodePtr
3698xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3699 if (cur == NULL)
3700 cur = ctxt->context->node ;
3701 do {
3702 if (cur->prev != NULL) {
3703 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
3704 ;
3705 return(cur) ;
3706 }
3707
3708 cur = cur->parent;
3709 if (cur == NULL) return(NULL);
3710 if (cur == ctxt->context->doc->children) return(NULL);
3711 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
3712 return(cur);
3713}
3714
3715/**
3716 * xmlXPathNextNamespace:
3717 * @ctxt: the XPath Parser context
3718 * @cur: the current attribute in the traversal
3719 *
3720 * Traversal function for the "namespace" direction
3721 * the namespace axis contains the namespace nodes of the context node;
3722 * the order of nodes on this axis is implementation-defined; the axis will
3723 * be empty unless the context node is an element
3724 *
3725 * Returns the next element following that axis
3726 */
3727xmlNodePtr
3728xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3729 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3730 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
3731 if (ctxt->context->namespaces != NULL)
3732 xmlFree(ctxt->context->namespaces);
3733 ctxt->context->namespaces =
3734 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
3735 if (ctxt->context->namespaces == NULL) return(NULL);
3736 ctxt->context->nsNr = 0;
3737 }
3738 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
3739}
3740
3741/**
3742 * xmlXPathNextAttribute:
3743 * @ctxt: the XPath Parser context
3744 * @cur: the current attribute in the traversal
3745 *
3746 * Traversal function for the "attribute" direction
3747 * TODO: support DTD inherited default attributes
3748 *
3749 * Returns the next element following that axis
3750 */
3751xmlNodePtr
3752xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00003753 if (ctxt->context->node == NULL)
3754 return(NULL);
3755 if (ctxt->context->node->type != XML_ELEMENT_NODE)
3756 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003757 if (cur == NULL) {
3758 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3759 return(NULL);
3760 return((xmlNodePtr)ctxt->context->node->properties);
3761 }
3762 return((xmlNodePtr)cur->next);
3763}
3764
3765/************************************************************************
3766 * *
3767 * NodeTest Functions *
3768 * *
3769 ************************************************************************/
3770
Owen Taylor3473f882001-02-23 17:55:21 +00003771#define IS_FUNCTION 200
3772
Owen Taylor3473f882001-02-23 17:55:21 +00003773
3774/************************************************************************
3775 * *
3776 * Implicit tree core function library *
3777 * *
3778 ************************************************************************/
3779
3780/**
3781 * xmlXPathRoot:
3782 * @ctxt: the XPath Parser context
3783 *
3784 * Initialize the context to the root of the document
3785 */
3786void
3787xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
3788 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
3789 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3790}
3791
3792/************************************************************************
3793 * *
3794 * The explicit core function library *
3795 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
3796 * *
3797 ************************************************************************/
3798
3799
3800/**
3801 * xmlXPathLastFunction:
3802 * @ctxt: the XPath Parser context
3803 * @nargs: the number of arguments
3804 *
3805 * Implement the last() XPath function
3806 * number last()
3807 * The last function returns the number of nodes in the context node list.
3808 */
3809void
3810xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3811 CHECK_ARITY(0);
3812 if (ctxt->context->contextSize >= 0) {
3813 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
3814#ifdef DEBUG_EXPR
3815 xmlGenericError(xmlGenericErrorContext,
3816 "last() : %d\n", ctxt->context->contextSize);
3817#endif
3818 } else {
3819 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
3820 }
3821}
3822
3823/**
3824 * xmlXPathPositionFunction:
3825 * @ctxt: the XPath Parser context
3826 * @nargs: the number of arguments
3827 *
3828 * Implement the position() XPath function
3829 * number position()
3830 * The position function returns the position of the context node in the
3831 * context node list. The first position is 1, and so the last positionr
3832 * will be equal to last().
3833 */
3834void
3835xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3836 CHECK_ARITY(0);
3837 if (ctxt->context->proximityPosition >= 0) {
3838 valuePush(ctxt,
3839 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
3840#ifdef DEBUG_EXPR
3841 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
3842 ctxt->context->proximityPosition);
3843#endif
3844 } else {
3845 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
3846 }
3847}
3848
3849/**
3850 * xmlXPathCountFunction:
3851 * @ctxt: the XPath Parser context
3852 * @nargs: the number of arguments
3853 *
3854 * Implement the count() XPath function
3855 * number count(node-set)
3856 */
3857void
3858xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3859 xmlXPathObjectPtr cur;
3860
3861 CHECK_ARITY(1);
3862 if ((ctxt->value == NULL) ||
3863 ((ctxt->value->type != XPATH_NODESET) &&
3864 (ctxt->value->type != XPATH_XSLT_TREE)))
3865 XP_ERROR(XPATH_INVALID_TYPE);
3866 cur = valuePop(ctxt);
3867
Daniel Veillard911f49a2001-04-07 15:39:35 +00003868 if ((cur == NULL) || (cur->nodesetval == NULL))
3869 valuePush(ctxt, xmlXPathNewFloat((double) 0));
3870 else
3871 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00003872 xmlXPathFreeObject(cur);
3873}
3874
3875/**
3876 * xmlXPathIdFunction:
3877 * @ctxt: the XPath Parser context
3878 * @nargs: the number of arguments
3879 *
3880 * Implement the id() XPath function
3881 * node-set id(object)
3882 * The id function selects elements by their unique ID
3883 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
3884 * then the result is the union of the result of applying id to the
3885 * string value of each of the nodes in the argument node-set. When the
3886 * argument to id is of any other type, the argument is converted to a
3887 * string as if by a call to the string function; the string is split
3888 * into a whitespace-separated list of tokens (whitespace is any sequence
3889 * of characters matching the production S); the result is a node-set
3890 * containing the elements in the same document as the context node that
3891 * have a unique ID equal to any of the tokens in the list.
3892 */
3893void
3894xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3895 const xmlChar *tokens;
3896 const xmlChar *cur;
3897 xmlChar *ID;
3898 xmlAttrPtr attr;
3899 xmlNodePtr elem = NULL;
3900 xmlXPathObjectPtr ret, obj;
3901
3902 CHECK_ARITY(1);
3903 obj = valuePop(ctxt);
3904 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3905 if (obj->type == XPATH_NODESET) {
3906 xmlXPathObjectPtr newobj;
3907 int i;
3908
3909 ret = xmlXPathNewNodeSet(NULL);
3910
Daniel Veillard911f49a2001-04-07 15:39:35 +00003911 if (obj->nodesetval != NULL) {
3912 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
3913 valuePush(ctxt,
3914 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
3915 xmlXPathStringFunction(ctxt, 1);
3916 xmlXPathIdFunction(ctxt, 1);
3917 newobj = valuePop(ctxt);
3918 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
3919 newobj->nodesetval);
3920 xmlXPathFreeObject(newobj);
3921 }
Owen Taylor3473f882001-02-23 17:55:21 +00003922 }
3923
3924 xmlXPathFreeObject(obj);
3925 valuePush(ctxt, ret);
3926 return;
3927 }
3928 if (obj->type != XPATH_STRING) {
3929 valuePush(ctxt, obj);
3930 xmlXPathStringFunction(ctxt, 1);
3931 obj = valuePop(ctxt);
3932 if (obj->type != XPATH_STRING) {
3933 xmlXPathFreeObject(obj);
3934 return;
3935 }
3936 }
3937 tokens = obj->stringval;
3938
3939 ret = xmlXPathNewNodeSet(NULL);
3940 valuePush(ctxt, ret);
3941 if (tokens == NULL) {
3942 xmlXPathFreeObject(obj);
3943 return;
3944 }
3945
3946 cur = tokens;
3947
3948 while (IS_BLANK(*cur)) cur++;
3949 while (*cur != 0) {
3950 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
3951 (*cur == '.') || (*cur == '-') ||
3952 (*cur == '_') || (*cur == ':') ||
3953 (IS_COMBINING(*cur)) ||
3954 (IS_EXTENDER(*cur)))
3955 cur++;
3956
3957 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
3958
3959 ID = xmlStrndup(tokens, cur - tokens);
3960 attr = xmlGetID(ctxt->context->doc, ID);
3961 if (attr != NULL) {
3962 elem = attr->parent;
3963 xmlXPathNodeSetAdd(ret->nodesetval, elem);
3964 }
3965 if (ID != NULL)
3966 xmlFree(ID);
3967
3968 while (IS_BLANK(*cur)) cur++;
3969 tokens = cur;
3970 }
3971 xmlXPathFreeObject(obj);
3972 return;
3973}
3974
3975/**
3976 * xmlXPathLocalNameFunction:
3977 * @ctxt: the XPath Parser context
3978 * @nargs: the number of arguments
3979 *
3980 * Implement the local-name() XPath function
3981 * string local-name(node-set?)
3982 * The local-name function returns a string containing the local part
3983 * of the name of the node in the argument node-set that is first in
3984 * document order. If the node-set is empty or the first node has no
3985 * name, an empty string is returned. If the argument is omitted it
3986 * defaults to the context node.
3987 */
3988void
3989xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3990 xmlXPathObjectPtr cur;
3991
3992 if (nargs == 0) {
3993 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3994 nargs = 1;
3995 }
3996
3997 CHECK_ARITY(1);
3998 if ((ctxt->value == NULL) ||
3999 ((ctxt->value->type != XPATH_NODESET) &&
4000 (ctxt->value->type != XPATH_XSLT_TREE)))
4001 XP_ERROR(XPATH_INVALID_TYPE);
4002 cur = valuePop(ctxt);
4003
Daniel Veillard911f49a2001-04-07 15:39:35 +00004004 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004005 valuePush(ctxt, xmlXPathNewCString(""));
4006 } else {
4007 int i = 0; /* Should be first in document order !!!!! */
4008 switch (cur->nodesetval->nodeTab[i]->type) {
4009 case XML_ELEMENT_NODE:
4010 case XML_ATTRIBUTE_NODE:
4011 case XML_PI_NODE:
4012 valuePush(ctxt,
4013 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4014 break;
4015 case XML_NAMESPACE_DECL:
4016 valuePush(ctxt, xmlXPathNewString(
4017 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4018 break;
4019 default:
4020 valuePush(ctxt, xmlXPathNewCString(""));
4021 }
4022 }
4023 xmlXPathFreeObject(cur);
4024}
4025
4026/**
4027 * xmlXPathNamespaceURIFunction:
4028 * @ctxt: the XPath Parser context
4029 * @nargs: the number of arguments
4030 *
4031 * Implement the namespace-uri() XPath function
4032 * string namespace-uri(node-set?)
4033 * The namespace-uri function returns a string containing the
4034 * namespace URI of the expanded name of the node in the argument
4035 * node-set that is first in document order. If the node-set is empty,
4036 * the first node has no name, or the expanded name has no namespace
4037 * URI, an empty string is returned. If the argument is omitted it
4038 * defaults to the context node.
4039 */
4040void
4041xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4042 xmlXPathObjectPtr cur;
4043
4044 if (nargs == 0) {
4045 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4046 nargs = 1;
4047 }
4048 CHECK_ARITY(1);
4049 if ((ctxt->value == NULL) ||
4050 ((ctxt->value->type != XPATH_NODESET) &&
4051 (ctxt->value->type != XPATH_XSLT_TREE)))
4052 XP_ERROR(XPATH_INVALID_TYPE);
4053 cur = valuePop(ctxt);
4054
Daniel Veillard911f49a2001-04-07 15:39:35 +00004055 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004056 valuePush(ctxt, xmlXPathNewCString(""));
4057 } else {
4058 int i = 0; /* Should be first in document order !!!!! */
4059 switch (cur->nodesetval->nodeTab[i]->type) {
4060 case XML_ELEMENT_NODE:
4061 case XML_ATTRIBUTE_NODE:
4062 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4063 valuePush(ctxt, xmlXPathNewCString(""));
4064 else
4065 valuePush(ctxt, xmlXPathNewString(
4066 cur->nodesetval->nodeTab[i]->ns->href));
4067 break;
4068 default:
4069 valuePush(ctxt, xmlXPathNewCString(""));
4070 }
4071 }
4072 xmlXPathFreeObject(cur);
4073}
4074
4075/**
4076 * xmlXPathNameFunction:
4077 * @ctxt: the XPath Parser context
4078 * @nargs: the number of arguments
4079 *
4080 * Implement the name() XPath function
4081 * string name(node-set?)
4082 * The name function returns a string containing a QName representing
4083 * the name of the node in the argument node-set that is first in documenti
4084 * order. The QName must represent the name with respect to the namespace
4085 * declarations in effect on the node whose name is being represented.
4086 * Typically, this will be the form in which the name occurred in the XML
4087 * source. This need not be the case if there are namespace declarations
4088 * in effect on the node that associate multiple prefixes with the same
4089 * namespace. However, an implementation may include information about
4090 * the original prefix in its representation of nodes; in this case, an
4091 * implementation can ensure that the returned string is always the same
4092 * as the QName used in the XML source. If the argument it omitted it
4093 * defaults to the context node.
4094 * Libxml keep the original prefix so the "real qualified name" used is
4095 * returned.
4096 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004097static void
Owen Taylor3473f882001-02-23 17:55:21 +00004098xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4099 xmlXPathObjectPtr cur;
4100
4101 if (nargs == 0) {
4102 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4103 nargs = 1;
4104 }
4105
4106 CHECK_ARITY(1);
4107 if ((ctxt->value == NULL) ||
4108 ((ctxt->value->type != XPATH_NODESET) &&
4109 (ctxt->value->type != XPATH_XSLT_TREE)))
4110 XP_ERROR(XPATH_INVALID_TYPE);
4111 cur = valuePop(ctxt);
4112
Daniel Veillard911f49a2001-04-07 15:39:35 +00004113 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004114 valuePush(ctxt, xmlXPathNewCString(""));
4115 } else {
4116 int i = 0; /* Should be first in document order !!!!! */
4117
4118 switch (cur->nodesetval->nodeTab[i]->type) {
4119 case XML_ELEMENT_NODE:
4120 case XML_ATTRIBUTE_NODE:
4121 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4122 valuePush(ctxt, xmlXPathNewString(
4123 cur->nodesetval->nodeTab[i]->name));
4124
4125 else {
4126 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004127 snprintf(name, sizeof(name), "%s:%s",
4128 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4129 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004130 name[sizeof(name) - 1] = 0;
4131 valuePush(ctxt, xmlXPathNewCString(name));
4132 }
4133 break;
4134 default:
4135 valuePush(ctxt,
4136 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4137 xmlXPathLocalNameFunction(ctxt, 1);
4138 }
4139 }
4140 xmlXPathFreeObject(cur);
4141}
4142
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004143
4144/**
4145 * xmlXPathConvertString:
4146 * @val: an XPath object
4147 *
4148 * Converts an existing object to its string() equivalent
4149 *
4150 * Returns the new object, the old one is freed (or the operation
4151 * is done directly on @val)
4152 */
4153xmlXPathObjectPtr
4154xmlXPathConvertString(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004155 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004156
4157 if (val == NULL)
4158 return(xmlXPathNewCString(""));
4159 switch (val->type) {
4160 case XPATH_UNDEFINED:
4161#ifdef DEBUG_EXPR
4162 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
4163#endif
4164 ret = xmlXPathNewCString("");
4165 break;
4166 case XPATH_XSLT_TREE:
4167 case XPATH_NODESET:
Daniel Veillard911f49a2001-04-07 15:39:35 +00004168 if ((val->nodesetval == NULL) || (val->nodesetval->nodeNr == 0)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004169 ret = xmlXPathNewCString("");
4170 } else {
4171 xmlChar *res;
4172
4173 xmlXPathNodeSetSort(val->nodesetval);
4174 res = xmlNodeGetContent(val->nodesetval->nodeTab[0]);
4175 /* TODO: avoid allocating res to free it */
4176 ret = xmlXPathNewString(res);
4177 if (res != NULL)
4178 xmlFree(res);
4179 }
4180 break;
4181 case XPATH_STRING:
4182 return(val);
4183 case XPATH_BOOLEAN:
4184 if (val->boolval) ret = xmlXPathNewCString("true");
4185 else ret = xmlXPathNewCString("false");
4186 break;
4187 case XPATH_NUMBER: {
4188 char buf[100];
4189
4190 xmlXPathFormatNumber(val->floatval, buf, sizeof(buf));
4191 ret = xmlXPathNewCString(buf);
4192 break;
4193 }
4194 case XPATH_USERS:
4195 case XPATH_POINT:
4196 case XPATH_RANGE:
4197 case XPATH_LOCATIONSET:
4198 TODO
4199 ret = xmlXPathNewCString("");
4200 break;
4201 }
4202 xmlXPathFreeObject(val);
4203 return(ret);
4204}
4205
Owen Taylor3473f882001-02-23 17:55:21 +00004206/**
4207 * xmlXPathStringFunction:
4208 * @ctxt: the XPath Parser context
4209 * @nargs: the number of arguments
4210 *
4211 * Implement the string() XPath function
4212 * string string(object?)
4213 * he string function converts an object to a string as follows:
4214 * - A node-set is converted to a string by returning the value of
4215 * the node in the node-set that is first in document order.
4216 * If the node-set is empty, an empty string is returned.
4217 * - A number is converted to a string as follows
4218 * + NaN is converted to the string NaN
4219 * + positive zero is converted to the string 0
4220 * + negative zero is converted to the string 0
4221 * + positive infinity is converted to the string Infinity
4222 * + negative infinity is converted to the string -Infinity
4223 * + if the number is an integer, the number is represented in
4224 * decimal form as a Number with no decimal point and no leading
4225 * zeros, preceded by a minus sign (-) if the number is negative
4226 * + otherwise, the number is represented in decimal form as a
4227 * Number including a decimal point with at least one digit
4228 * before the decimal point and at least one digit after the
4229 * decimal point, preceded by a minus sign (-) if the number
4230 * is negative; there must be no leading zeros before the decimal
4231 * point apart possibly from the one required digit immediatelyi
4232 * before the decimal point; beyond the one required digit
4233 * after the decimal point there must be as many, but only as
4234 * many, more digits as are needed to uniquely distinguish the
4235 * number from all other IEEE 754 numeric values.
4236 * - The boolean false value is converted to the string false.
4237 * The boolean true value is converted to the string true.
4238 *
4239 * If the argument is omitted, it defaults to a node-set with the
4240 * context node as its only member.
4241 */
4242void
4243xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4244 xmlXPathObjectPtr cur;
4245
4246 if (nargs == 0) {
4247 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4248 nargs = 1;
4249 }
4250
4251 CHECK_ARITY(1);
4252 cur = valuePop(ctxt);
4253 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004254 cur = xmlXPathConvertString(cur);
4255 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004256}
4257
4258/**
4259 * xmlXPathStringLengthFunction:
4260 * @ctxt: the XPath Parser context
4261 * @nargs: the number of arguments
4262 *
4263 * Implement the string-length() XPath function
4264 * number string-length(string?)
4265 * The string-length returns the number of characters in the string
4266 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4267 * the context node converted to a string, in other words the value
4268 * of the context node.
4269 */
4270void
4271xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4272 xmlXPathObjectPtr cur;
4273
4274 if (nargs == 0) {
4275 if (ctxt->context->node == NULL) {
4276 valuePush(ctxt, xmlXPathNewFloat(0));
4277 } else {
4278 xmlChar *content;
4279
4280 content = xmlNodeGetContent(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004281 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004282 xmlFree(content);
4283 }
4284 return;
4285 }
4286 CHECK_ARITY(1);
4287 CAST_TO_STRING;
4288 CHECK_TYPE(XPATH_STRING);
4289 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004290 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004291 xmlXPathFreeObject(cur);
4292}
4293
4294/**
4295 * xmlXPathConcatFunction:
4296 * @ctxt: the XPath Parser context
4297 * @nargs: the number of arguments
4298 *
4299 * Implement the concat() XPath function
4300 * string concat(string, string, string*)
4301 * The concat function returns the concatenation of its arguments.
4302 */
4303void
4304xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4305 xmlXPathObjectPtr cur, newobj;
4306 xmlChar *tmp;
4307
4308 if (nargs < 2) {
4309 CHECK_ARITY(2);
4310 }
4311
4312 CAST_TO_STRING;
4313 cur = valuePop(ctxt);
4314 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4315 xmlXPathFreeObject(cur);
4316 return;
4317 }
4318 nargs--;
4319
4320 while (nargs > 0) {
4321 CAST_TO_STRING;
4322 newobj = valuePop(ctxt);
4323 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4324 xmlXPathFreeObject(newobj);
4325 xmlXPathFreeObject(cur);
4326 XP_ERROR(XPATH_INVALID_TYPE);
4327 }
4328 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4329 newobj->stringval = cur->stringval;
4330 cur->stringval = tmp;
4331
4332 xmlXPathFreeObject(newobj);
4333 nargs--;
4334 }
4335 valuePush(ctxt, cur);
4336}
4337
4338/**
4339 * xmlXPathContainsFunction:
4340 * @ctxt: the XPath Parser context
4341 * @nargs: the number of arguments
4342 *
4343 * Implement the contains() XPath function
4344 * boolean contains(string, string)
4345 * The contains function returns true if the first argument string
4346 * contains the second argument string, and otherwise returns false.
4347 */
4348void
4349xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4350 xmlXPathObjectPtr hay, needle;
4351
4352 CHECK_ARITY(2);
4353 CAST_TO_STRING;
4354 CHECK_TYPE(XPATH_STRING);
4355 needle = valuePop(ctxt);
4356 CAST_TO_STRING;
4357 hay = valuePop(ctxt);
4358 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4359 xmlXPathFreeObject(hay);
4360 xmlXPathFreeObject(needle);
4361 XP_ERROR(XPATH_INVALID_TYPE);
4362 }
4363 if (xmlStrstr(hay->stringval, needle->stringval))
4364 valuePush(ctxt, xmlXPathNewBoolean(1));
4365 else
4366 valuePush(ctxt, xmlXPathNewBoolean(0));
4367 xmlXPathFreeObject(hay);
4368 xmlXPathFreeObject(needle);
4369}
4370
4371/**
4372 * xmlXPathStartsWithFunction:
4373 * @ctxt: the XPath Parser context
4374 * @nargs: the number of arguments
4375 *
4376 * Implement the starts-with() XPath function
4377 * boolean starts-with(string, string)
4378 * The starts-with function returns true if the first argument string
4379 * starts with the second argument string, and otherwise returns false.
4380 */
4381void
4382xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4383 xmlXPathObjectPtr hay, needle;
4384 int n;
4385
4386 CHECK_ARITY(2);
4387 CAST_TO_STRING;
4388 CHECK_TYPE(XPATH_STRING);
4389 needle = valuePop(ctxt);
4390 CAST_TO_STRING;
4391 hay = valuePop(ctxt);
4392 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4393 xmlXPathFreeObject(hay);
4394 xmlXPathFreeObject(needle);
4395 XP_ERROR(XPATH_INVALID_TYPE);
4396 }
4397 n = xmlStrlen(needle->stringval);
4398 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4399 valuePush(ctxt, xmlXPathNewBoolean(0));
4400 else
4401 valuePush(ctxt, xmlXPathNewBoolean(1));
4402 xmlXPathFreeObject(hay);
4403 xmlXPathFreeObject(needle);
4404}
4405
4406/**
4407 * xmlXPathSubstringFunction:
4408 * @ctxt: the XPath Parser context
4409 * @nargs: the number of arguments
4410 *
4411 * Implement the substring() XPath function
4412 * string substring(string, number, number?)
4413 * The substring function returns the substring of the first argument
4414 * starting at the position specified in the second argument with
4415 * length specified in the third argument. For example,
4416 * substring("12345",2,3) returns "234". If the third argument is not
4417 * specified, it returns the substring starting at the position specified
4418 * in the second argument and continuing to the end of the string. For
4419 * example, substring("12345",2) returns "2345". More precisely, each
4420 * character in the string (see [3.6 Strings]) is considered to have a
4421 * numeric position: the position of the first character is 1, the position
4422 * of the second character is 2 and so on. The returned substring contains
4423 * those characters for which the position of the character is greater than
4424 * or equal to the second argument and, if the third argument is specified,
4425 * less than the sum of the second and third arguments; the comparisons
4426 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4427 * - substring("12345", 1.5, 2.6) returns "234"
4428 * - substring("12345", 0, 3) returns "12"
4429 * - substring("12345", 0 div 0, 3) returns ""
4430 * - substring("12345", 1, 0 div 0) returns ""
4431 * - substring("12345", -42, 1 div 0) returns "12345"
4432 * - substring("12345", -1 div 0, 1 div 0) returns ""
4433 */
4434void
4435xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4436 xmlXPathObjectPtr str, start, len;
4437 double le, in;
4438 int i, l;
4439 xmlChar *ret;
4440
4441 /*
Daniel Veillarde043ee12001-04-16 14:08:07 +00004442 * TODO: need to be converted to UTF8 strings
Owen Taylor3473f882001-02-23 17:55:21 +00004443 */
4444 if (nargs < 2) {
4445 CHECK_ARITY(2);
4446 }
4447 if (nargs > 3) {
4448 CHECK_ARITY(3);
4449 }
4450 if (nargs == 3) {
4451 CAST_TO_NUMBER;
4452 CHECK_TYPE(XPATH_NUMBER);
4453 len = valuePop(ctxt);
4454 le = len->floatval;
4455 xmlXPathFreeObject(len);
4456 } else {
4457 le = 2000000000;
4458 }
4459 CAST_TO_NUMBER;
4460 CHECK_TYPE(XPATH_NUMBER);
4461 start = valuePop(ctxt);
4462 in = start->floatval;
4463 xmlXPathFreeObject(start);
4464 CAST_TO_STRING;
4465 CHECK_TYPE(XPATH_STRING);
4466 str = valuePop(ctxt);
4467 le += in;
4468
4469 /* integer index of the first char */
4470 i = (int) in;
4471 if (((double)i) != in) i++;
4472
4473 /* integer index of the last char */
4474 l = (int) le;
4475 if (((double)l) != le) l++;
4476
4477 /* back to a zero based len */
4478 i--;
4479 l--;
4480
4481 /* check against the string len */
4482 if (l > 1024) {
4483 l = xmlStrlen(str->stringval);
4484 }
4485 if (i < 0) {
4486 i = 0;
4487 }
4488
4489 /* number of chars to copy */
4490 l -= i;
4491
4492 ret = xmlStrsub(str->stringval, i, l);
4493 if (ret == NULL)
4494 valuePush(ctxt, xmlXPathNewCString(""));
4495 else {
4496 valuePush(ctxt, xmlXPathNewString(ret));
4497 xmlFree(ret);
4498 }
4499 xmlXPathFreeObject(str);
4500}
4501
4502/**
4503 * xmlXPathSubstringBeforeFunction:
4504 * @ctxt: the XPath Parser context
4505 * @nargs: the number of arguments
4506 *
4507 * Implement the substring-before() XPath function
4508 * string substring-before(string, string)
4509 * The substring-before function returns the substring of the first
4510 * argument string that precedes the first occurrence of the second
4511 * argument string in the first argument string, or the empty string
4512 * if the first argument string does not contain the second argument
4513 * string. For example, substring-before("1999/04/01","/") returns 1999.
4514 */
4515void
4516xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4517 xmlXPathObjectPtr str;
4518 xmlXPathObjectPtr find;
4519 xmlBufferPtr target;
4520 const xmlChar *point;
4521 int offset;
4522
4523 CHECK_ARITY(2);
4524 CAST_TO_STRING;
4525 find = valuePop(ctxt);
4526 CAST_TO_STRING;
4527 str = valuePop(ctxt);
4528
4529 target = xmlBufferCreate();
4530 if (target) {
4531 point = xmlStrstr(str->stringval, find->stringval);
4532 if (point) {
4533 offset = (int)(point - str->stringval);
4534 xmlBufferAdd(target, str->stringval, offset);
4535 }
4536 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4537 xmlBufferFree(target);
4538 }
4539
4540 xmlXPathFreeObject(str);
4541 xmlXPathFreeObject(find);
4542}
4543
4544/**
4545 * xmlXPathSubstringAfterFunction:
4546 * @ctxt: the XPath Parser context
4547 * @nargs: the number of arguments
4548 *
4549 * Implement the substring-after() XPath function
4550 * string substring-after(string, string)
4551 * The substring-after function returns the substring of the first
4552 * argument string that follows the first occurrence of the second
4553 * argument string in the first argument string, or the empty stringi
4554 * if the first argument string does not contain the second argument
4555 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4556 * and substring-after("1999/04/01","19") returns 99/04/01.
4557 */
4558void
4559xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4560 xmlXPathObjectPtr str;
4561 xmlXPathObjectPtr find;
4562 xmlBufferPtr target;
4563 const xmlChar *point;
4564 int offset;
4565
4566 CHECK_ARITY(2);
4567 CAST_TO_STRING;
4568 find = valuePop(ctxt);
4569 CAST_TO_STRING;
4570 str = valuePop(ctxt);
4571
4572 target = xmlBufferCreate();
4573 if (target) {
4574 point = xmlStrstr(str->stringval, find->stringval);
4575 if (point) {
4576 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4577 xmlBufferAdd(target, &str->stringval[offset],
4578 xmlStrlen(str->stringval) - offset);
4579 }
4580 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4581 xmlBufferFree(target);
4582 }
4583
4584 xmlXPathFreeObject(str);
4585 xmlXPathFreeObject(find);
4586}
4587
4588/**
4589 * xmlXPathNormalizeFunction:
4590 * @ctxt: the XPath Parser context
4591 * @nargs: the number of arguments
4592 *
4593 * Implement the normalize-space() XPath function
4594 * string normalize-space(string?)
4595 * The normalize-space function returns the argument string with white
4596 * space normalized by stripping leading and trailing whitespace
4597 * and replacing sequences of whitespace characters by a single
4598 * space. Whitespace characters are the same allowed by the S production
4599 * in XML. If the argument is omitted, it defaults to the context
4600 * node converted to a string, in other words the value of the context node.
4601 */
4602void
4603xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4604 xmlXPathObjectPtr obj = NULL;
4605 xmlChar *source = NULL;
4606 xmlBufferPtr target;
4607 xmlChar blank;
4608
4609 if (nargs == 0) {
4610 /* Use current context node */
4611 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4612 xmlXPathStringFunction(ctxt, 1);
4613 nargs = 1;
4614 }
4615
4616 CHECK_ARITY(1);
4617 CAST_TO_STRING;
4618 CHECK_TYPE(XPATH_STRING);
4619 obj = valuePop(ctxt);
4620 source = obj->stringval;
4621
4622 target = xmlBufferCreate();
4623 if (target && source) {
4624
4625 /* Skip leading whitespaces */
4626 while (IS_BLANK(*source))
4627 source++;
4628
4629 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4630 blank = 0;
4631 while (*source) {
4632 if (IS_BLANK(*source)) {
4633 blank = *source;
4634 } else {
4635 if (blank) {
4636 xmlBufferAdd(target, &blank, 1);
4637 blank = 0;
4638 }
4639 xmlBufferAdd(target, source, 1);
4640 }
4641 source++;
4642 }
4643
4644 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4645 xmlBufferFree(target);
4646 }
4647 xmlXPathFreeObject(obj);
4648}
4649
4650/**
4651 * xmlXPathTranslateFunction:
4652 * @ctxt: the XPath Parser context
4653 * @nargs: the number of arguments
4654 *
4655 * Implement the translate() XPath function
4656 * string translate(string, string, string)
4657 * The translate function returns the first argument string with
4658 * occurrences of characters in the second argument string replaced
4659 * by the character at the corresponding position in the third argument
4660 * string. For example, translate("bar","abc","ABC") returns the string
4661 * BAr. If there is a character in the second argument string with no
4662 * character at a corresponding position in the third argument string
4663 * (because the second argument string is longer than the third argument
4664 * string), then occurrences of that character in the first argument
4665 * string are removed. For example, translate("--aaa--","abc-","ABC")
4666 * returns "AAA". If a character occurs more than once in second
4667 * argument string, then the first occurrence determines the replacement
4668 * character. If the third argument string is longer than the second
4669 * argument string, then excess characters are ignored.
4670 */
4671void
4672xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00004673 xmlXPathObjectPtr str;
4674 xmlXPathObjectPtr from;
4675 xmlXPathObjectPtr to;
4676 xmlBufferPtr target;
4677 int i, offset, max;
4678 xmlChar ch;
4679 const xmlChar *point;
Owen Taylor3473f882001-02-23 17:55:21 +00004680
Daniel Veillarde043ee12001-04-16 14:08:07 +00004681 /*
4682 * TODO: need to be converted to UTF8 strings
4683 */
4684 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00004685
Daniel Veillarde043ee12001-04-16 14:08:07 +00004686 CAST_TO_STRING;
4687 to = valuePop(ctxt);
4688 CAST_TO_STRING;
4689 from = valuePop(ctxt);
4690 CAST_TO_STRING;
4691 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004692
Daniel Veillarde043ee12001-04-16 14:08:07 +00004693 target = xmlBufferCreate();
4694 if (target) {
4695 max = xmlStrlen(to->stringval);
4696 for (i = 0; (ch = str->stringval[i]); i++) {
4697 point = xmlStrchr(from->stringval, ch);
4698 if (point) {
4699 offset = (int)(point - from->stringval);
4700 if (offset < max)
4701 xmlBufferAdd(target, &to->stringval[offset], 1);
4702 } else
4703 xmlBufferAdd(target, &ch, 1);
4704 }
Owen Taylor3473f882001-02-23 17:55:21 +00004705 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00004706 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4707 xmlBufferFree(target);
4708 xmlXPathFreeObject(str);
4709 xmlXPathFreeObject(from);
4710 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00004711}
4712
4713/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004714 * xmlXPathConvertBoolean:
4715 * @val: an XPath object
4716 *
4717 * Converts an existing object to its boolean() equivalent
4718 *
4719 * Returns the new object, the old one is freed (or the operation
4720 * is done directly on @val)
4721 */
4722xmlXPathObjectPtr
4723xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4724 int res = 0;
4725
4726 if (val == NULL)
4727 return(NULL);
4728 switch (val->type) {
4729 case XPATH_NODESET:
4730 case XPATH_XSLT_TREE:
4731 if ((val->nodesetval == NULL) ||
4732 (val->nodesetval->nodeNr == 0)) res = 0;
4733 else
4734 res = 1;
4735 break;
4736 case XPATH_STRING:
4737 if ((val->stringval == NULL) ||
4738 (val->stringval[0] == 0)) res = 0;
4739 else
4740 res = 1;
4741 break;
4742 case XPATH_BOOLEAN:
4743 return(val);
4744 case XPATH_NUMBER:
4745 if (val->floatval) res = 1;
4746 break;
4747 default:
4748 STRANGE
4749 }
4750 xmlXPathFreeObject(val);
4751 return(xmlXPathNewBoolean(res));
4752}
4753
4754/**
Owen Taylor3473f882001-02-23 17:55:21 +00004755 * xmlXPathBooleanFunction:
4756 * @ctxt: the XPath Parser context
4757 * @nargs: the number of arguments
4758 *
4759 * Implement the boolean() XPath function
4760 * boolean boolean(object)
4761 * he boolean function converts its argument to a boolean as follows:
4762 * - a number is true if and only if it is neither positive or
4763 * negative zero nor NaN
4764 * - a node-set is true if and only if it is non-empty
4765 * - a string is true if and only if its length is non-zero
4766 */
4767void
4768xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4769 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00004770
4771 CHECK_ARITY(1);
4772 cur = valuePop(ctxt);
4773 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004774 cur = xmlXPathConvertBoolean(cur);
4775 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004776}
4777
4778/**
4779 * xmlXPathNotFunction:
4780 * @ctxt: the XPath Parser context
4781 * @nargs: the number of arguments
4782 *
4783 * Implement the not() XPath function
4784 * boolean not(boolean)
4785 * The not function returns true if its argument is false,
4786 * and false otherwise.
4787 */
4788void
4789xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4790 CHECK_ARITY(1);
4791 CAST_TO_BOOLEAN;
4792 CHECK_TYPE(XPATH_BOOLEAN);
4793 ctxt->value->boolval = ! ctxt->value->boolval;
4794}
4795
4796/**
4797 * xmlXPathTrueFunction:
4798 * @ctxt: the XPath Parser context
4799 * @nargs: the number of arguments
4800 *
4801 * Implement the true() XPath function
4802 * boolean true()
4803 */
4804void
4805xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4806 CHECK_ARITY(0);
4807 valuePush(ctxt, xmlXPathNewBoolean(1));
4808}
4809
4810/**
4811 * xmlXPathFalseFunction:
4812 * @ctxt: the XPath Parser context
4813 * @nargs: the number of arguments
4814 *
4815 * Implement the false() XPath function
4816 * boolean false()
4817 */
4818void
4819xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4820 CHECK_ARITY(0);
4821 valuePush(ctxt, xmlXPathNewBoolean(0));
4822}
4823
4824/**
4825 * xmlXPathLangFunction:
4826 * @ctxt: the XPath Parser context
4827 * @nargs: the number of arguments
4828 *
4829 * Implement the lang() XPath function
4830 * boolean lang(string)
4831 * The lang function returns true or false depending on whether the
4832 * language of the context node as specified by xml:lang attributes
4833 * is the same as or is a sublanguage of the language specified by
4834 * the argument string. The language of the context node is determined
4835 * by the value of the xml:lang attribute on the context node, or, if
4836 * the context node has no xml:lang attribute, by the value of the
4837 * xml:lang attribute on the nearest ancestor of the context node that
4838 * has an xml:lang attribute. If there is no such attribute, then lang
4839 * returns false. If there is such an attribute, then lang returns
4840 * true if the attribute value is equal to the argument ignoring case,
4841 * or if there is some suffix starting with - such that the attribute
4842 * value is equal to the argument ignoring that suffix of the attribute
4843 * value and ignoring case.
4844 */
4845void
4846xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4847 xmlXPathObjectPtr val;
4848 const xmlChar *theLang;
4849 const xmlChar *lang;
4850 int ret = 0;
4851 int i;
4852
4853 CHECK_ARITY(1);
4854 CAST_TO_STRING;
4855 CHECK_TYPE(XPATH_STRING);
4856 val = valuePop(ctxt);
4857 lang = val->stringval;
4858 theLang = xmlNodeGetLang(ctxt->context->node);
4859 if ((theLang != NULL) && (lang != NULL)) {
4860 for (i = 0;lang[i] != 0;i++)
4861 if (toupper(lang[i]) != toupper(theLang[i]))
4862 goto not_equal;
4863 ret = 1;
4864 }
4865not_equal:
4866 xmlXPathFreeObject(val);
4867 valuePush(ctxt, xmlXPathNewBoolean(ret));
4868}
4869
4870/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004871 * xmlXPathConvertNumber:
4872 * @val: an XPath object
4873 *
4874 * Converts an existing object to its number() equivalent
4875 *
4876 * Returns the new object, the old one is freed (or the operation
4877 * is done directly on @val)
4878 */
4879xmlXPathObjectPtr
4880xmlXPathConvertNumber(xmlXPathObjectPtr val) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004881 xmlXPathObjectPtr ret = NULL;
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004882 double res;
4883
4884 if (val == NULL)
4885 return(xmlXPathNewFloat(0.0));
4886 switch (val->type) {
4887 case XPATH_UNDEFINED:
4888#ifdef DEBUG_EXPR
4889 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
4890#endif
4891 ret = xmlXPathNewFloat(0.0);
4892 break;
4893 case XPATH_XSLT_TREE:
4894 case XPATH_NODESET:
4895 val = xmlXPathConvertString(val);
4896 /* no break on purpose */
4897 case XPATH_STRING:
4898 res = xmlXPathStringEvalNumber(val->stringval);
4899 ret = xmlXPathNewFloat(res);
4900 break;
4901 case XPATH_BOOLEAN:
4902 if (val->boolval) ret = xmlXPathNewFloat(1.0);
4903 else ret = xmlXPathNewFloat(0.0);
4904 break;
4905 case XPATH_NUMBER:
4906 return(val);
4907 case XPATH_USERS:
4908 case XPATH_POINT:
4909 case XPATH_RANGE:
4910 case XPATH_LOCATIONSET:
4911 TODO
4912 ret = xmlXPathNewFloat(0.0);
4913 break;
4914 }
4915 xmlXPathFreeObject(val);
4916 return(ret);
4917}
4918
4919/**
Owen Taylor3473f882001-02-23 17:55:21 +00004920 * xmlXPathNumberFunction:
4921 * @ctxt: the XPath Parser context
4922 * @nargs: the number of arguments
4923 *
4924 * Implement the number() XPath function
4925 * number number(object?)
4926 */
4927void
4928xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4929 xmlXPathObjectPtr cur;
4930 double res;
4931
4932 if (nargs == 0) {
4933 if (ctxt->context->node == NULL) {
4934 valuePush(ctxt, xmlXPathNewFloat(0.0));
4935 } else {
4936 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
4937
4938 res = xmlXPathStringEvalNumber(content);
4939 valuePush(ctxt, xmlXPathNewFloat(res));
4940 xmlFree(content);
4941 }
4942 return;
4943 }
4944
4945 CHECK_ARITY(1);
4946 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004947 cur = xmlXPathConvertNumber(cur);
4948 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004949}
4950
4951/**
4952 * xmlXPathSumFunction:
4953 * @ctxt: the XPath Parser context
4954 * @nargs: the number of arguments
4955 *
4956 * Implement the sum() XPath function
4957 * number sum(node-set)
4958 * The sum function returns the sum of the values of the nodes in
4959 * the argument node-set.
4960 */
4961void
4962xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4963 xmlXPathObjectPtr cur;
4964 int i;
4965
4966 CHECK_ARITY(1);
4967 if ((ctxt->value == NULL) ||
4968 ((ctxt->value->type != XPATH_NODESET) &&
4969 (ctxt->value->type != XPATH_XSLT_TREE)))
4970 XP_ERROR(XPATH_INVALID_TYPE);
4971 cur = valuePop(ctxt);
4972
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004973 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004974 valuePush(ctxt, xmlXPathNewFloat(0.0));
4975 } else {
4976 valuePush(ctxt,
4977 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
4978 xmlXPathNumberFunction(ctxt, 1);
4979 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
4980 valuePush(ctxt,
4981 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4982 xmlXPathAddValues(ctxt);
4983 }
4984 }
4985 xmlXPathFreeObject(cur);
4986}
4987
4988/**
4989 * xmlXPathFloorFunction:
4990 * @ctxt: the XPath Parser context
4991 * @nargs: the number of arguments
4992 *
4993 * Implement the floor() XPath function
4994 * number floor(number)
4995 * The floor function returns the largest (closest to positive infinity)
4996 * number that is not greater than the argument and that is an integer.
4997 */
4998void
4999xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5000 CHECK_ARITY(1);
5001 CAST_TO_NUMBER;
5002 CHECK_TYPE(XPATH_NUMBER);
5003#if 0
5004 ctxt->value->floatval = floor(ctxt->value->floatval);
5005#else
5006 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5007 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5008#endif
5009}
5010
5011/**
5012 * xmlXPathCeilingFunction:
5013 * @ctxt: the XPath Parser context
5014 * @nargs: the number of arguments
5015 *
5016 * Implement the ceiling() XPath function
5017 * number ceiling(number)
5018 * The ceiling function returns the smallest (closest to negative infinity)
5019 * number that is not less than the argument and that is an integer.
5020 */
5021void
5022xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5023 double f;
5024
5025 CHECK_ARITY(1);
5026 CAST_TO_NUMBER;
5027 CHECK_TYPE(XPATH_NUMBER);
5028
5029#if 0
5030 ctxt->value->floatval = ceil(ctxt->value->floatval);
5031#else
5032 f = (double)((int) ctxt->value->floatval);
5033 if (f != ctxt->value->floatval)
5034 ctxt->value->floatval = f + 1;
5035#endif
5036}
5037
5038/**
5039 * xmlXPathRoundFunction:
5040 * @ctxt: the XPath Parser context
5041 * @nargs: the number of arguments
5042 *
5043 * Implement the round() XPath function
5044 * number round(number)
5045 * The round function returns the number that is closest to the
5046 * argument and that is an integer. If there are two such numbers,
5047 * then the one that is even is returned.
5048 */
5049void
5050xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5051 double f;
5052
5053 CHECK_ARITY(1);
5054 CAST_TO_NUMBER;
5055 CHECK_TYPE(XPATH_NUMBER);
5056
5057 if ((ctxt->value->floatval == xmlXPathNAN) ||
5058 (ctxt->value->floatval == xmlXPathPINF) ||
5059 (ctxt->value->floatval == xmlXPathNINF) ||
5060 (ctxt->value->floatval == 0.0))
5061 return;
5062
5063#if 0
5064 f = floor(ctxt->value->floatval);
5065#else
5066 f = (double)((int) ctxt->value->floatval);
5067#endif
5068 if (ctxt->value->floatval < f + 0.5)
5069 ctxt->value->floatval = f;
5070 else
5071 ctxt->value->floatval = f + 1;
5072}
5073
5074/************************************************************************
5075 * *
5076 * The Parser *
5077 * *
5078 ************************************************************************/
5079
5080/*
5081 * a couple of forward declarations since we use a recursive call based
5082 * implementation.
5083 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005084static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005085static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005086static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005087#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005088static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5089#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005090#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005091static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005092#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005093static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5094 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005095
5096/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005097 * xmlXPathCurrentChar:
5098 * @ctxt: the XPath parser context
5099 * @cur: pointer to the beginning of the char
5100 * @len: pointer to the length of the char read
5101 *
5102 * The current char value, if using UTF-8 this may actaully span multiple
5103 * bytes in the input buffer.
5104 *
5105 * Returns the current char value and its lenght
5106 */
5107
5108static int
5109xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5110 unsigned char c;
5111 unsigned int val;
5112 const xmlChar *cur;
5113
5114 if (ctxt == NULL)
5115 return(0);
5116 cur = ctxt->cur;
5117
5118 /*
5119 * We are supposed to handle UTF8, check it's valid
5120 * From rfc2044: encoding of the Unicode values on UTF-8:
5121 *
5122 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5123 * 0000 0000-0000 007F 0xxxxxxx
5124 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5125 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5126 *
5127 * Check for the 0x110000 limit too
5128 */
5129 c = *cur;
5130 if (c & 0x80) {
5131 if ((cur[1] & 0xc0) != 0x80)
5132 goto encoding_error;
5133 if ((c & 0xe0) == 0xe0) {
5134
5135 if ((cur[2] & 0xc0) != 0x80)
5136 goto encoding_error;
5137 if ((c & 0xf0) == 0xf0) {
5138 if (((c & 0xf8) != 0xf0) ||
5139 ((cur[3] & 0xc0) != 0x80))
5140 goto encoding_error;
5141 /* 4-byte code */
5142 *len = 4;
5143 val = (cur[0] & 0x7) << 18;
5144 val |= (cur[1] & 0x3f) << 12;
5145 val |= (cur[2] & 0x3f) << 6;
5146 val |= cur[3] & 0x3f;
5147 } else {
5148 /* 3-byte code */
5149 *len = 3;
5150 val = (cur[0] & 0xf) << 12;
5151 val |= (cur[1] & 0x3f) << 6;
5152 val |= cur[2] & 0x3f;
5153 }
5154 } else {
5155 /* 2-byte code */
5156 *len = 2;
5157 val = (cur[0] & 0x1f) << 6;
5158 val |= cur[1] & 0x3f;
5159 }
5160 if (!IS_CHAR(val)) {
5161 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5162 }
5163 return(val);
5164 } else {
5165 /* 1-byte code */
5166 *len = 1;
5167 return((int) *cur);
5168 }
5169encoding_error:
5170 /*
5171 * If we detect an UTF8 error that probably mean that the
5172 * input encoding didn't get properly advertized in the
5173 * declaration header. Report the error and switch the encoding
5174 * to ISO-Latin-1 (if you don't like this policy, just declare the
5175 * encoding !)
5176 */
5177 XP_ERROR0(XPATH_ENCODING_ERROR);
5178 *len = 1;
5179 return((int) *cur);
5180}
5181
5182/**
Owen Taylor3473f882001-02-23 17:55:21 +00005183 * xmlXPathParseNCName:
5184 * @ctxt: the XPath Parser context
5185 *
5186 * parse an XML namespace non qualified name.
5187 *
5188 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5189 *
5190 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5191 * CombiningChar | Extender
5192 *
5193 * Returns the namespace name or NULL
5194 */
5195
5196xmlChar *
5197xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005198 const xmlChar *in;
5199 xmlChar *ret;
5200 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005201
Daniel Veillard2156a562001-04-28 12:24:34 +00005202 /*
5203 * Accelerator for simple ASCII names
5204 */
5205 in = ctxt->cur;
5206 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5207 ((*in >= 0x41) && (*in <= 0x5A)) ||
5208 (*in == '_')) {
5209 in++;
5210 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5211 ((*in >= 0x41) && (*in <= 0x5A)) ||
5212 ((*in >= 0x30) && (*in <= 0x39)) ||
5213 (*in == '_'))
5214 in++;
5215 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5216 (*in == '[') || (*in == ']') || (*in == ':') ||
5217 (*in == '@') || (*in == '*')) {
5218 count = in - ctxt->cur;
5219 if (count == 0)
5220 return(NULL);
5221 ret = xmlStrndup(ctxt->cur, count);
5222 ctxt->cur = in;
5223 return(ret);
5224 }
5225 }
5226 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005227}
5228
Daniel Veillard2156a562001-04-28 12:24:34 +00005229
Owen Taylor3473f882001-02-23 17:55:21 +00005230/**
5231 * xmlXPathParseQName:
5232 * @ctxt: the XPath Parser context
5233 * @prefix: a xmlChar **
5234 *
5235 * parse an XML qualified name
5236 *
5237 * [NS 5] QName ::= (Prefix ':')? LocalPart
5238 *
5239 * [NS 6] Prefix ::= NCName
5240 *
5241 * [NS 7] LocalPart ::= NCName
5242 *
5243 * Returns the function returns the local part, and prefix is updated
5244 * to get the Prefix if any.
5245 */
5246
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005247static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005248xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5249 xmlChar *ret = NULL;
5250
5251 *prefix = NULL;
5252 ret = xmlXPathParseNCName(ctxt);
5253 if (CUR == ':') {
5254 *prefix = ret;
5255 NEXT;
5256 ret = xmlXPathParseNCName(ctxt);
5257 }
5258 return(ret);
5259}
5260
5261/**
5262 * xmlXPathParseName:
5263 * @ctxt: the XPath Parser context
5264 *
5265 * parse an XML name
5266 *
5267 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5268 * CombiningChar | Extender
5269 *
5270 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5271 *
5272 * Returns the namespace name or NULL
5273 */
5274
5275xmlChar *
5276xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005277 const xmlChar *in;
5278 xmlChar *ret;
5279 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005280
Daniel Veillard61d80a22001-04-27 17:13:01 +00005281 /*
5282 * Accelerator for simple ASCII names
5283 */
5284 in = ctxt->cur;
5285 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5286 ((*in >= 0x41) && (*in <= 0x5A)) ||
5287 (*in == '_') || (*in == ':')) {
5288 in++;
5289 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5290 ((*in >= 0x41) && (*in <= 0x5A)) ||
5291 ((*in >= 0x30) && (*in <= 0x39)) ||
5292 (*in == '_') || (*in == ':'))
5293 in++;
5294 if ((*in == ' ') || (*in == '>') || (*in == '/')) {
5295 count = in - ctxt->cur;
5296 ret = xmlStrndup(ctxt->cur, count);
5297 ctxt->cur = in;
5298 return(ret);
5299 }
5300 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005301 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005302}
5303
Daniel Veillard61d80a22001-04-27 17:13:01 +00005304static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005305xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005306 xmlChar buf[XML_MAX_NAMELEN + 5];
5307 int len = 0, l;
5308 int c;
5309
5310 /*
5311 * Handler for more complex cases
5312 */
5313 c = CUR_CHAR(l);
5314 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005315 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5316 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005317 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005318 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005319 return(NULL);
5320 }
5321
5322 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5323 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5324 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005325 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005326 (IS_COMBINING(c)) ||
5327 (IS_EXTENDER(c)))) {
5328 COPY_BUF(l,buf,len,c);
5329 NEXTL(l);
5330 c = CUR_CHAR(l);
5331 if (len >= XML_MAX_NAMELEN) {
5332 /*
5333 * Okay someone managed to make a huge name, so he's ready to pay
5334 * for the processing speed.
5335 */
5336 xmlChar *buffer;
5337 int max = len * 2;
5338
5339 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5340 if (buffer == NULL) {
5341 XP_ERROR0(XPATH_MEMORY_ERROR);
5342 }
5343 memcpy(buffer, buf, len);
5344 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5345 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005346 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005347 (IS_COMBINING(c)) ||
5348 (IS_EXTENDER(c))) {
5349 if (len + 10 > max) {
5350 max *= 2;
5351 buffer = (xmlChar *) xmlRealloc(buffer,
5352 max * sizeof(xmlChar));
5353 XP_ERROR0(XPATH_MEMORY_ERROR);
5354 if (buffer == NULL) {
5355 XP_ERROR0(XPATH_MEMORY_ERROR);
5356 }
5357 }
5358 COPY_BUF(l,buffer,len,c);
5359 NEXTL(l);
5360 c = CUR_CHAR(l);
5361 }
5362 buffer[len] = 0;
5363 return(buffer);
5364 }
5365 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005366 if (len == 0)
5367 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005368 return(xmlStrndup(buf, len));
5369}
Owen Taylor3473f882001-02-23 17:55:21 +00005370/**
5371 * xmlXPathStringEvalNumber:
5372 * @str: A string to scan
5373 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005374 * [30a] Float ::= Number ('e' Digits?)?
5375 *
Owen Taylor3473f882001-02-23 17:55:21 +00005376 * [30] Number ::= Digits ('.' Digits?)?
5377 * | '.' Digits
5378 * [31] Digits ::= [0-9]+
5379 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005380 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005381 * In complement of the Number expression, this function also handles
5382 * negative values : '-' Number.
5383 *
5384 * Returns the double value.
5385 */
5386double
5387xmlXPathStringEvalNumber(const xmlChar *str) {
5388 const xmlChar *cur = str;
5389 double ret = 0.0;
5390 double mult = 1;
5391 int ok = 0;
5392 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005393 int exponent = 0;
5394 int is_exponent_negative = 0;
5395
Owen Taylor3473f882001-02-23 17:55:21 +00005396 while (IS_BLANK(*cur)) cur++;
5397 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5398 return(xmlXPathNAN);
5399 }
5400 if (*cur == '-') {
5401 isneg = 1;
5402 cur++;
5403 }
5404 while ((*cur >= '0') && (*cur <= '9')) {
5405 ret = ret * 10 + (*cur - '0');
5406 ok = 1;
5407 cur++;
5408 }
5409 if (*cur == '.') {
5410 cur++;
5411 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5412 return(xmlXPathNAN);
5413 }
5414 while ((*cur >= '0') && (*cur <= '9')) {
5415 mult /= 10;
5416 ret = ret + (*cur - '0') * mult;
5417 cur++;
5418 }
5419 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005420 if ((*cur == 'e') || (*cur == 'E')) {
5421 cur++;
5422 if (*cur == '-') {
5423 is_exponent_negative = 1;
5424 cur++;
5425 }
5426 while ((*cur >= '0') && (*cur <= '9')) {
5427 exponent = exponent * 10 + (*cur - '0');
5428 cur++;
5429 }
5430 }
Owen Taylor3473f882001-02-23 17:55:21 +00005431 while (IS_BLANK(*cur)) cur++;
5432 if (*cur != 0) return(xmlXPathNAN);
5433 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005434 if (is_exponent_negative) exponent = -exponent;
5435 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005436 return(ret);
5437}
5438
5439/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005440 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005441 * @ctxt: the XPath Parser context
5442 *
5443 * [30] Number ::= Digits ('.' Digits?)?
5444 * | '.' Digits
5445 * [31] Digits ::= [0-9]+
5446 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005447 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005448 *
5449 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005450static void
5451xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005452 double ret = 0.0;
5453 double mult = 1;
5454 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005455 int exponent = 0;
5456 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005457
5458 CHECK_ERROR;
5459 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5460 XP_ERROR(XPATH_NUMBER_ERROR);
5461 }
5462 while ((CUR >= '0') && (CUR <= '9')) {
5463 ret = ret * 10 + (CUR - '0');
5464 ok = 1;
5465 NEXT;
5466 }
5467 if (CUR == '.') {
5468 NEXT;
5469 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5470 XP_ERROR(XPATH_NUMBER_ERROR);
5471 }
5472 while ((CUR >= '0') && (CUR <= '9')) {
5473 mult /= 10;
5474 ret = ret + (CUR - '0') * mult;
5475 NEXT;
5476 }
5477 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005478 if ((CUR == 'e') || (CUR == 'E')) {
5479 NEXT;
5480 if (CUR == '-') {
5481 is_exponent_negative = 1;
5482 NEXT;
5483 }
5484 while ((CUR >= '0') && (CUR <= '9')) {
5485 exponent = exponent * 10 + (CUR - '0');
5486 NEXT;
5487 }
5488 }
5489 if (is_exponent_negative)
5490 exponent = -exponent;
5491 ret *= pow(10.0, (double)exponent);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005492 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5493 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005494}
5495
5496/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005497 * xmlXPathParseLiteral:
5498 * @ctxt: the XPath Parser context
5499 *
5500 * Parse a Literal
5501 *
5502 * [29] Literal ::= '"' [^"]* '"'
5503 * | "'" [^']* "'"
5504 *
5505 * Returns the value found or NULL in case of error
5506 */
5507static xmlChar *
5508xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5509 const xmlChar *q;
5510 xmlChar *ret = NULL;
5511
5512 if (CUR == '"') {
5513 NEXT;
5514 q = CUR_PTR;
5515 while ((IS_CHAR(CUR)) && (CUR != '"'))
5516 NEXT;
5517 if (!IS_CHAR(CUR)) {
5518 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5519 } else {
5520 ret = xmlStrndup(q, CUR_PTR - q);
5521 NEXT;
5522 }
5523 } else if (CUR == '\'') {
5524 NEXT;
5525 q = CUR_PTR;
5526 while ((IS_CHAR(CUR)) && (CUR != '\''))
5527 NEXT;
5528 if (!IS_CHAR(CUR)) {
5529 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5530 } else {
5531 ret = xmlStrndup(q, CUR_PTR - q);
5532 NEXT;
5533 }
5534 } else {
5535 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5536 }
5537 return(ret);
5538}
5539
5540/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005541 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005542 * @ctxt: the XPath Parser context
5543 *
5544 * Parse a Literal and push it on the stack.
5545 *
5546 * [29] Literal ::= '"' [^"]* '"'
5547 * | "'" [^']* "'"
5548 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005549 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005550 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005551static void
5552xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005553 const xmlChar *q;
5554 xmlChar *ret = NULL;
5555
5556 if (CUR == '"') {
5557 NEXT;
5558 q = CUR_PTR;
5559 while ((IS_CHAR(CUR)) && (CUR != '"'))
5560 NEXT;
5561 if (!IS_CHAR(CUR)) {
5562 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5563 } else {
5564 ret = xmlStrndup(q, CUR_PTR - q);
5565 NEXT;
5566 }
5567 } else if (CUR == '\'') {
5568 NEXT;
5569 q = CUR_PTR;
5570 while ((IS_CHAR(CUR)) && (CUR != '\''))
5571 NEXT;
5572 if (!IS_CHAR(CUR)) {
5573 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5574 } else {
5575 ret = xmlStrndup(q, CUR_PTR - q);
5576 NEXT;
5577 }
5578 } else {
5579 XP_ERROR(XPATH_START_LITERAL_ERROR);
5580 }
5581 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005582 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5583 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005584 xmlFree(ret);
5585}
5586
5587/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005588 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005589 * @ctxt: the XPath Parser context
5590 *
5591 * Parse a VariableReference, evaluate it and push it on the stack.
5592 *
5593 * The variable bindings consist of a mapping from variable names
5594 * to variable values. The value of a variable is an object, which
5595 * of any of the types that are possible for the value of an expression,
5596 * and may also be of additional types not specified here.
5597 *
5598 * Early evaluation is possible since:
5599 * The variable bindings [...] used to evaluate a subexpression are
5600 * always the same as those used to evaluate the containing expression.
5601 *
5602 * [36] VariableReference ::= '$' QName
5603 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005604static void
5605xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005606 xmlChar *name;
5607 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005608
5609 SKIP_BLANKS;
5610 if (CUR != '$') {
5611 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5612 }
5613 NEXT;
5614 name = xmlXPathParseQName(ctxt, &prefix);
5615 if (name == NULL) {
5616 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5617 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005618 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005619 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5620 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005621 SKIP_BLANKS;
5622}
5623
5624/**
5625 * xmlXPathIsNodeType:
5626 * @ctxt: the XPath Parser context
5627 * @name: a name string
5628 *
5629 * Is the name given a NodeType one.
5630 *
5631 * [38] NodeType ::= 'comment'
5632 * | 'text'
5633 * | 'processing-instruction'
5634 * | 'node'
5635 *
5636 * Returns 1 if true 0 otherwise
5637 */
5638int
5639xmlXPathIsNodeType(const xmlChar *name) {
5640 if (name == NULL)
5641 return(0);
5642
5643 if (xmlStrEqual(name, BAD_CAST "comment"))
5644 return(1);
5645 if (xmlStrEqual(name, BAD_CAST "text"))
5646 return(1);
5647 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5648 return(1);
5649 if (xmlStrEqual(name, BAD_CAST "node"))
5650 return(1);
5651 return(0);
5652}
5653
5654/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005655 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005656 * @ctxt: the XPath Parser context
5657 *
5658 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5659 * [17] Argument ::= Expr
5660 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005661 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00005662 * pushed on the stack
5663 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005664static void
5665xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005666 xmlChar *name;
5667 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005668 int nbargs = 0;
5669
5670 name = xmlXPathParseQName(ctxt, &prefix);
5671 if (name == NULL) {
5672 XP_ERROR(XPATH_EXPR_ERROR);
5673 }
5674 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005675#ifdef DEBUG_EXPR
5676 if (prefix == NULL)
5677 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5678 name);
5679 else
5680 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5681 prefix, name);
5682#endif
5683
Owen Taylor3473f882001-02-23 17:55:21 +00005684 if (CUR != '(') {
5685 XP_ERROR(XPATH_EXPR_ERROR);
5686 }
5687 NEXT;
5688 SKIP_BLANKS;
5689
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005690 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005691 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005692 int op1 = ctxt->comp->last;
5693 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005694 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005695 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005696 nbargs++;
5697 if (CUR == ')') break;
5698 if (CUR != ',') {
5699 XP_ERROR(XPATH_EXPR_ERROR);
5700 }
5701 NEXT;
5702 SKIP_BLANKS;
5703 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005704 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
5705 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005706 NEXT;
5707 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005708}
5709
5710/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005711 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005712 * @ctxt: the XPath Parser context
5713 *
5714 * [15] PrimaryExpr ::= VariableReference
5715 * | '(' Expr ')'
5716 * | Literal
5717 * | Number
5718 * | FunctionCall
5719 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005720 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005721 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005722static void
5723xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005724 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005725 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005726 else if (CUR == '(') {
5727 NEXT;
5728 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005729 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005730 if (CUR != ')') {
5731 XP_ERROR(XPATH_EXPR_ERROR);
5732 }
5733 NEXT;
5734 SKIP_BLANKS;
5735 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005736 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005737 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005738 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005739 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005740 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005741 }
5742 SKIP_BLANKS;
5743}
5744
5745/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005746 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005747 * @ctxt: the XPath Parser context
5748 *
5749 * [20] FilterExpr ::= PrimaryExpr
5750 * | FilterExpr Predicate
5751 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005752 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005753 * Square brackets are used to filter expressions in the same way that
5754 * they are used in location paths. It is an error if the expression to
5755 * be filtered does not evaluate to a node-set. The context node list
5756 * used for evaluating the expression in square brackets is the node-set
5757 * to be filtered listed in document order.
5758 */
5759
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005760static void
5761xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
5762 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005763 CHECK_ERROR;
5764 SKIP_BLANKS;
5765
5766 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005767 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00005768 SKIP_BLANKS;
5769 }
5770
5771
5772}
5773
5774/**
5775 * xmlXPathScanName:
5776 * @ctxt: the XPath Parser context
5777 *
5778 * Trickery: parse an XML name but without consuming the input flow
5779 * Needed to avoid insanity in the parser state.
5780 *
5781 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5782 * CombiningChar | Extender
5783 *
5784 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5785 *
5786 * [6] Names ::= Name (S Name)*
5787 *
5788 * Returns the Name parsed or NULL
5789 */
5790
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005791static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005792xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
5793 xmlChar buf[XML_MAX_NAMELEN];
5794 int len = 0;
5795
5796 SKIP_BLANKS;
5797 if (!IS_LETTER(CUR) && (CUR != '_') &&
5798 (CUR != ':')) {
5799 return(NULL);
5800 }
5801
5802 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5803 (NXT(len) == '.') || (NXT(len) == '-') ||
5804 (NXT(len) == '_') || (NXT(len) == ':') ||
5805 (IS_COMBINING(NXT(len))) ||
5806 (IS_EXTENDER(NXT(len)))) {
5807 buf[len] = NXT(len);
5808 len++;
5809 if (len >= XML_MAX_NAMELEN) {
5810 xmlGenericError(xmlGenericErrorContext,
5811 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5812 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5813 (NXT(len) == '.') || (NXT(len) == '-') ||
5814 (NXT(len) == '_') || (NXT(len) == ':') ||
5815 (IS_COMBINING(NXT(len))) ||
5816 (IS_EXTENDER(NXT(len))))
5817 len++;
5818 break;
5819 }
5820 }
5821 return(xmlStrndup(buf, len));
5822}
5823
5824/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005825 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005826 * @ctxt: the XPath Parser context
5827 *
5828 * [19] PathExpr ::= LocationPath
5829 * | FilterExpr
5830 * | FilterExpr '/' RelativeLocationPath
5831 * | FilterExpr '//' RelativeLocationPath
5832 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005833 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005834 * The / operator and // operators combine an arbitrary expression
5835 * and a relative location path. It is an error if the expression
5836 * does not evaluate to a node-set.
5837 * The / operator does composition in the same way as when / is
5838 * used in a location path. As in location paths, // is short for
5839 * /descendant-or-self::node()/.
5840 */
5841
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005842static void
5843xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005844 int lc = 1; /* Should we branch to LocationPath ? */
5845 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5846
5847 SKIP_BLANKS;
5848 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5849 (CUR == '\'') || (CUR == '"')) {
5850 lc = 0;
5851 } else if (CUR == '*') {
5852 /* relative or absolute location path */
5853 lc = 1;
5854 } else if (CUR == '/') {
5855 /* relative or absolute location path */
5856 lc = 1;
5857 } else if (CUR == '@') {
5858 /* relative abbreviated attribute location path */
5859 lc = 1;
5860 } else if (CUR == '.') {
5861 /* relative abbreviated attribute location path */
5862 lc = 1;
5863 } else {
5864 /*
5865 * Problem is finding if we have a name here whether it's:
5866 * - a nodetype
5867 * - a function call in which case it's followed by '('
5868 * - an axis in which case it's followed by ':'
5869 * - a element name
5870 * We do an a priori analysis here rather than having to
5871 * maintain parsed token content through the recursive function
5872 * calls. This looks uglier but makes the code quite easier to
5873 * read/write/debug.
5874 */
5875 SKIP_BLANKS;
5876 name = xmlXPathScanName(ctxt);
5877 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
5878#ifdef DEBUG_STEP
5879 xmlGenericError(xmlGenericErrorContext,
5880 "PathExpr: Axis\n");
5881#endif
5882 lc = 1;
5883 xmlFree(name);
5884 } else if (name != NULL) {
5885 int len =xmlStrlen(name);
5886 int blank = 0;
5887
5888
5889 while (NXT(len) != 0) {
5890 if (NXT(len) == '/') {
5891 /* element name */
5892#ifdef DEBUG_STEP
5893 xmlGenericError(xmlGenericErrorContext,
5894 "PathExpr: AbbrRelLocation\n");
5895#endif
5896 lc = 1;
5897 break;
5898 } else if (IS_BLANK(NXT(len))) {
5899 /* skip to next */
5900 blank = 1;
5901 } else if (NXT(len) == ':') {
5902#ifdef DEBUG_STEP
5903 xmlGenericError(xmlGenericErrorContext,
5904 "PathExpr: AbbrRelLocation\n");
5905#endif
5906 lc = 1;
5907 break;
5908 } else if ((NXT(len) == '(')) {
5909 /* Note Type or Function */
5910 if (xmlXPathIsNodeType(name)) {
5911#ifdef DEBUG_STEP
5912 xmlGenericError(xmlGenericErrorContext,
5913 "PathExpr: Type search\n");
5914#endif
5915 lc = 1;
5916 } else {
5917#ifdef DEBUG_STEP
5918 xmlGenericError(xmlGenericErrorContext,
5919 "PathExpr: function call\n");
5920#endif
5921 lc = 0;
5922 }
5923 break;
5924 } else if ((NXT(len) == '[')) {
5925 /* element name */
5926#ifdef DEBUG_STEP
5927 xmlGenericError(xmlGenericErrorContext,
5928 "PathExpr: AbbrRelLocation\n");
5929#endif
5930 lc = 1;
5931 break;
5932 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5933 (NXT(len) == '=')) {
5934 lc = 1;
5935 break;
5936 } else {
5937 lc = 1;
5938 break;
5939 }
5940 len++;
5941 }
5942 if (NXT(len) == 0) {
5943#ifdef DEBUG_STEP
5944 xmlGenericError(xmlGenericErrorContext,
5945 "PathExpr: AbbrRelLocation\n");
5946#endif
5947 /* element name */
5948 lc = 1;
5949 }
5950 xmlFree(name);
5951 } else {
5952 /* make sure all cases are covered explicitely */
5953 XP_ERROR(XPATH_EXPR_ERROR);
5954 }
5955 }
5956
5957 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005958 if (CUR == '/') {
5959 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
5960 } else {
5961 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00005962 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005963 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005964 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005965 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005966 CHECK_ERROR;
5967 if ((CUR == '/') && (NXT(1) == '/')) {
5968 SKIP(2);
5969 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005970
5971 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
5972 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5973 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
5974
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005975 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005976 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005977 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005978 }
5979 }
5980 SKIP_BLANKS;
5981}
5982
5983/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005984 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00005985 * @ctxt: the XPath Parser context
5986 *
5987 * [18] UnionExpr ::= PathExpr
5988 * | UnionExpr '|' PathExpr
5989 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005990 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00005991 */
5992
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005993static void
5994xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
5995 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005996 CHECK_ERROR;
5997 SKIP_BLANKS;
5998 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005999 int op1 = ctxt->comp->last;
6000 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006001
6002 NEXT;
6003 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006004 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006005
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006006 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6007
Owen Taylor3473f882001-02-23 17:55:21 +00006008 SKIP_BLANKS;
6009 }
Owen Taylor3473f882001-02-23 17:55:21 +00006010}
6011
6012/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006013 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006014 * @ctxt: the XPath Parser context
6015 *
6016 * [27] UnaryExpr ::= UnionExpr
6017 * | '-' UnaryExpr
6018 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006019 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006020 */
6021
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006022static void
6023xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006024 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006025 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006026
6027 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006028 while (CUR == '-') {
6029 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006030 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006031 NEXT;
6032 SKIP_BLANKS;
6033 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006034
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006035 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006036 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006037 if (found) {
6038 if (minus)
6039 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6040 else
6041 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006042 }
6043}
6044
6045/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006046 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006047 * @ctxt: the XPath Parser context
6048 *
6049 * [26] MultiplicativeExpr ::= UnaryExpr
6050 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6051 * | MultiplicativeExpr 'div' UnaryExpr
6052 * | MultiplicativeExpr 'mod' UnaryExpr
6053 * [34] MultiplyOperator ::= '*'
6054 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006055 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006056 */
6057
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006058static void
6059xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6060 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006061 CHECK_ERROR;
6062 SKIP_BLANKS;
6063 while ((CUR == '*') ||
6064 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6065 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6066 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006067 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006068
6069 if (CUR == '*') {
6070 op = 0;
6071 NEXT;
6072 } else if (CUR == 'd') {
6073 op = 1;
6074 SKIP(3);
6075 } else if (CUR == 'm') {
6076 op = 2;
6077 SKIP(3);
6078 }
6079 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006080 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006081 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006082 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006083 SKIP_BLANKS;
6084 }
6085}
6086
6087/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006088 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006089 * @ctxt: the XPath Parser context
6090 *
6091 * [25] AdditiveExpr ::= MultiplicativeExpr
6092 * | AdditiveExpr '+' MultiplicativeExpr
6093 * | AdditiveExpr '-' MultiplicativeExpr
6094 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006095 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006096 */
6097
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006098static void
6099xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006100
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006101 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006102 CHECK_ERROR;
6103 SKIP_BLANKS;
6104 while ((CUR == '+') || (CUR == '-')) {
6105 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006106 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006107
6108 if (CUR == '+') plus = 1;
6109 else plus = 0;
6110 NEXT;
6111 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006112 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006113 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006114 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006115 SKIP_BLANKS;
6116 }
6117}
6118
6119/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006120 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006121 * @ctxt: the XPath Parser context
6122 *
6123 * [24] RelationalExpr ::= AdditiveExpr
6124 * | RelationalExpr '<' AdditiveExpr
6125 * | RelationalExpr '>' AdditiveExpr
6126 * | RelationalExpr '<=' AdditiveExpr
6127 * | RelationalExpr '>=' AdditiveExpr
6128 *
6129 * A <= B > C is allowed ? Answer from James, yes with
6130 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6131 * which is basically what got implemented.
6132 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006133 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006134 * on the stack
6135 */
6136
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006137static void
6138xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6139 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006140 CHECK_ERROR;
6141 SKIP_BLANKS;
6142 while ((CUR == '<') ||
6143 (CUR == '>') ||
6144 ((CUR == '<') && (NXT(1) == '=')) ||
6145 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006146 int inf, strict;
6147 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006148
6149 if (CUR == '<') inf = 1;
6150 else inf = 0;
6151 if (NXT(1) == '=') strict = 0;
6152 else strict = 1;
6153 NEXT;
6154 if (!strict) NEXT;
6155 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006156 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006157 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006158 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006159 SKIP_BLANKS;
6160 }
6161}
6162
6163/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006164 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006165 * @ctxt: the XPath Parser context
6166 *
6167 * [23] EqualityExpr ::= RelationalExpr
6168 * | EqualityExpr '=' RelationalExpr
6169 * | EqualityExpr '!=' RelationalExpr
6170 *
6171 * A != B != C is allowed ? Answer from James, yes with
6172 * (RelationalExpr = RelationalExpr) = RelationalExpr
6173 * (RelationalExpr != RelationalExpr) != RelationalExpr
6174 * which is basically what got implemented.
6175 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006176 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006177 *
6178 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006179static void
6180xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6181 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006182 CHECK_ERROR;
6183 SKIP_BLANKS;
6184 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006185 int eq;
6186 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006187
6188 if (CUR == '=') eq = 1;
6189 else eq = 0;
6190 NEXT;
6191 if (!eq) NEXT;
6192 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006193 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006194 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006195 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006196 SKIP_BLANKS;
6197 }
6198}
6199
6200/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006201 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006202 * @ctxt: the XPath Parser context
6203 *
6204 * [22] AndExpr ::= EqualityExpr
6205 * | AndExpr 'and' EqualityExpr
6206 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006207 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006208 *
6209 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006210static void
6211xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6212 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006213 CHECK_ERROR;
6214 SKIP_BLANKS;
6215 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006216 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006217 SKIP(3);
6218 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006219 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006220 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006221 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006222 SKIP_BLANKS;
6223 }
6224}
6225
6226/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006227 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006228 * @ctxt: the XPath Parser context
6229 *
6230 * [14] Expr ::= OrExpr
6231 * [21] OrExpr ::= AndExpr
6232 * | OrExpr 'or' AndExpr
6233 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006234 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006235 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006236static void
6237xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6238 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006239 CHECK_ERROR;
6240 SKIP_BLANKS;
6241 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006242 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006243 SKIP(2);
6244 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006245 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006246 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006247 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6248 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006249 SKIP_BLANKS;
6250 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006251 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6252 /* more ops could be optimized too */
6253 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6254 }
Owen Taylor3473f882001-02-23 17:55:21 +00006255}
6256
6257/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006258 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006259 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006260 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006261 *
6262 * [8] Predicate ::= '[' PredicateExpr ']'
6263 * [9] PredicateExpr ::= Expr
6264 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006265 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006266 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006267static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006268xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006269 int op1 = ctxt->comp->last;
6270
6271 SKIP_BLANKS;
6272 if (CUR != '[') {
6273 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6274 }
6275 NEXT;
6276 SKIP_BLANKS;
6277
6278 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006279 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006280 CHECK_ERROR;
6281
6282 if (CUR != ']') {
6283 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6284 }
6285
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006286 if (filter)
6287 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6288 else
6289 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006290
6291 NEXT;
6292 SKIP_BLANKS;
6293}
6294
6295/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006296 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006297 * @ctxt: the XPath Parser context
6298 * @test: pointer to a xmlXPathTestVal
6299 * @type: pointer to a xmlXPathTypeVal
6300 * @prefix: placeholder for a possible name prefix
6301 *
6302 * [7] NodeTest ::= NameTest
6303 * | NodeType '(' ')'
6304 * | 'processing-instruction' '(' Literal ')'
6305 *
6306 * [37] NameTest ::= '*'
6307 * | NCName ':' '*'
6308 * | QName
6309 * [38] NodeType ::= 'comment'
6310 * | 'text'
6311 * | 'processing-instruction'
6312 * | 'node'
6313 *
6314 * Returns the name found and update @test, @type and @prefix appropriately
6315 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006316static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006317xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6318 xmlXPathTypeVal *type, const xmlChar **prefix,
6319 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006320 int blanks;
6321
6322 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6323 STRANGE;
6324 return(NULL);
6325 }
6326 *type = 0;
6327 *test = 0;
6328 *prefix = NULL;
6329 SKIP_BLANKS;
6330
6331 if ((name == NULL) && (CUR == '*')) {
6332 /*
6333 * All elements
6334 */
6335 NEXT;
6336 *test = NODE_TEST_ALL;
6337 return(NULL);
6338 }
6339
6340 if (name == NULL)
6341 name = xmlXPathParseNCName(ctxt);
6342 if (name == NULL) {
6343 XP_ERROR0(XPATH_EXPR_ERROR);
6344 }
6345
6346 blanks = IS_BLANK(CUR);
6347 SKIP_BLANKS;
6348 if (CUR == '(') {
6349 NEXT;
6350 /*
6351 * NodeType or PI search
6352 */
6353 if (xmlStrEqual(name, BAD_CAST "comment"))
6354 *type = NODE_TYPE_COMMENT;
6355 else if (xmlStrEqual(name, BAD_CAST "node"))
6356 *type = NODE_TYPE_NODE;
6357 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6358 *type = NODE_TYPE_PI;
6359 else if (xmlStrEqual(name, BAD_CAST "text"))
6360 *type = NODE_TYPE_TEXT;
6361 else {
6362 if (name != NULL)
6363 xmlFree(name);
6364 XP_ERROR0(XPATH_EXPR_ERROR);
6365 }
6366
6367 *test = NODE_TEST_TYPE;
6368
6369 SKIP_BLANKS;
6370 if (*type == NODE_TYPE_PI) {
6371 /*
6372 * Specific case: search a PI by name.
6373 */
Owen Taylor3473f882001-02-23 17:55:21 +00006374 if (name != NULL)
6375 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006376 name = NULL;
6377 if (CUR != ')') {
6378 name = xmlXPathParseLiteral(ctxt);
6379 CHECK_ERROR 0;
6380 SKIP_BLANKS;
6381 }
Owen Taylor3473f882001-02-23 17:55:21 +00006382 }
6383 if (CUR != ')') {
6384 if (name != NULL)
6385 xmlFree(name);
6386 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6387 }
6388 NEXT;
6389 return(name);
6390 }
6391 *test = NODE_TEST_NAME;
6392 if ((!blanks) && (CUR == ':')) {
6393 NEXT;
6394
6395 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006396 * Since currently the parser context don't have a
6397 * namespace list associated:
6398 * The namespace name for this prefix can be computed
6399 * only at evaluation time. The compilation is done
6400 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006401 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006402#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006403 *prefix = xmlXPathNsLookup(ctxt->context, name);
6404 if (name != NULL)
6405 xmlFree(name);
6406 if (*prefix == NULL) {
6407 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6408 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006409#else
6410 *prefix = name;
6411#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006412
6413 if (CUR == '*') {
6414 /*
6415 * All elements
6416 */
6417 NEXT;
6418 *test = NODE_TEST_ALL;
6419 return(NULL);
6420 }
6421
6422 name = xmlXPathParseNCName(ctxt);
6423 if (name == NULL) {
6424 XP_ERROR0(XPATH_EXPR_ERROR);
6425 }
6426 }
6427 return(name);
6428}
6429
6430/**
6431 * xmlXPathIsAxisName:
6432 * @name: a preparsed name token
6433 *
6434 * [6] AxisName ::= 'ancestor'
6435 * | 'ancestor-or-self'
6436 * | 'attribute'
6437 * | 'child'
6438 * | 'descendant'
6439 * | 'descendant-or-self'
6440 * | 'following'
6441 * | 'following-sibling'
6442 * | 'namespace'
6443 * | 'parent'
6444 * | 'preceding'
6445 * | 'preceding-sibling'
6446 * | 'self'
6447 *
6448 * Returns the axis or 0
6449 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006450static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006451xmlXPathIsAxisName(const xmlChar *name) {
6452 xmlXPathAxisVal ret = 0;
6453 switch (name[0]) {
6454 case 'a':
6455 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6456 ret = AXIS_ANCESTOR;
6457 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6458 ret = AXIS_ANCESTOR_OR_SELF;
6459 if (xmlStrEqual(name, BAD_CAST "attribute"))
6460 ret = AXIS_ATTRIBUTE;
6461 break;
6462 case 'c':
6463 if (xmlStrEqual(name, BAD_CAST "child"))
6464 ret = AXIS_CHILD;
6465 break;
6466 case 'd':
6467 if (xmlStrEqual(name, BAD_CAST "descendant"))
6468 ret = AXIS_DESCENDANT;
6469 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6470 ret = AXIS_DESCENDANT_OR_SELF;
6471 break;
6472 case 'f':
6473 if (xmlStrEqual(name, BAD_CAST "following"))
6474 ret = AXIS_FOLLOWING;
6475 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6476 ret = AXIS_FOLLOWING_SIBLING;
6477 break;
6478 case 'n':
6479 if (xmlStrEqual(name, BAD_CAST "namespace"))
6480 ret = AXIS_NAMESPACE;
6481 break;
6482 case 'p':
6483 if (xmlStrEqual(name, BAD_CAST "parent"))
6484 ret = AXIS_PARENT;
6485 if (xmlStrEqual(name, BAD_CAST "preceding"))
6486 ret = AXIS_PRECEDING;
6487 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6488 ret = AXIS_PRECEDING_SIBLING;
6489 break;
6490 case 's':
6491 if (xmlStrEqual(name, BAD_CAST "self"))
6492 ret = AXIS_SELF;
6493 break;
6494 }
6495 return(ret);
6496}
6497
6498/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006499 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006500 * @ctxt: the XPath Parser context
6501 *
6502 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6503 * | AbbreviatedStep
6504 *
6505 * [12] AbbreviatedStep ::= '.' | '..'
6506 *
6507 * [5] AxisSpecifier ::= AxisName '::'
6508 * | AbbreviatedAxisSpecifier
6509 *
6510 * [13] AbbreviatedAxisSpecifier ::= '@'?
6511 *
6512 * Modified for XPtr range support as:
6513 *
6514 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6515 * | AbbreviatedStep
6516 * | 'range-to' '(' Expr ')' Predicate*
6517 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006518 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006519 * A location step of . is short for self::node(). This is
6520 * particularly useful in conjunction with //. For example, the
6521 * location path .//para is short for
6522 * self::node()/descendant-or-self::node()/child::para
6523 * and so will select all para descendant elements of the context
6524 * node.
6525 * Similarly, a location step of .. is short for parent::node().
6526 * For example, ../title is short for parent::node()/child::title
6527 * and so will select the title children of the parent of the context
6528 * node.
6529 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006530static void
6531xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006532#ifdef LIBXML_XPTR_ENABLED
6533 int rangeto = 0;
6534 int op2 = -1;
6535#endif
6536
Owen Taylor3473f882001-02-23 17:55:21 +00006537 SKIP_BLANKS;
6538 if ((CUR == '.') && (NXT(1) == '.')) {
6539 SKIP(2);
6540 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006541 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6542 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006543 } else if (CUR == '.') {
6544 NEXT;
6545 SKIP_BLANKS;
6546 } else {
6547 xmlChar *name = NULL;
6548 const xmlChar *prefix = NULL;
6549 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006550 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006551 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006552 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006553
6554 /*
6555 * The modification needed for XPointer change to the production
6556 */
6557#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006558 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006559 name = xmlXPathParseNCName(ctxt);
6560 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006561 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006562 xmlFree(name);
6563 SKIP_BLANKS;
6564 if (CUR != '(') {
6565 XP_ERROR(XPATH_EXPR_ERROR);
6566 }
6567 NEXT;
6568 SKIP_BLANKS;
6569
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006570 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006571 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006572 CHECK_ERROR;
6573
6574 SKIP_BLANKS;
6575 if (CUR != ')') {
6576 XP_ERROR(XPATH_EXPR_ERROR);
6577 }
6578 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006579 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006580 goto eval_predicates;
6581 }
6582 }
6583#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006584 if (CUR == '*') {
6585 axis = AXIS_CHILD;
6586 } else {
6587 if (name == NULL)
6588 name = xmlXPathParseNCName(ctxt);
6589 if (name != NULL) {
6590 axis = xmlXPathIsAxisName(name);
6591 if (axis != 0) {
6592 SKIP_BLANKS;
6593 if ((CUR == ':') && (NXT(1) == ':')) {
6594 SKIP(2);
6595 xmlFree(name);
6596 name = NULL;
6597 } else {
6598 /* an element name can conflict with an axis one :-\ */
6599 axis = AXIS_CHILD;
6600 }
Owen Taylor3473f882001-02-23 17:55:21 +00006601 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00006602 axis = AXIS_CHILD;
6603 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006604 } else if (CUR == '@') {
6605 NEXT;
6606 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00006607 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00006608 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00006609 }
Owen Taylor3473f882001-02-23 17:55:21 +00006610 }
6611
6612 CHECK_ERROR;
6613
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006614 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006615 if (test == 0)
6616 return;
6617
6618#ifdef DEBUG_STEP
6619 xmlGenericError(xmlGenericErrorContext,
6620 "Basis : computing new set\n");
6621#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006622
Owen Taylor3473f882001-02-23 17:55:21 +00006623#ifdef DEBUG_STEP
6624 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006625 if (ctxt->value == NULL)
6626 xmlGenericError(xmlGenericErrorContext, "no value\n");
6627 else if (ctxt->value->nodesetval == NULL)
6628 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6629 else
6630 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006631#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006632
6633eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006634 op1 = ctxt->comp->last;
6635 ctxt->comp->last = -1;
6636
Owen Taylor3473f882001-02-23 17:55:21 +00006637 SKIP_BLANKS;
6638 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006639 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006640 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006641
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006642#ifdef LIBXML_XPTR_ENABLED
6643 if (rangeto) {
6644 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
6645 } else
6646#endif
6647 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
6648 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006649
Owen Taylor3473f882001-02-23 17:55:21 +00006650 }
6651#ifdef DEBUG_STEP
6652 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006653 if (ctxt->value == NULL)
6654 xmlGenericError(xmlGenericErrorContext, "no value\n");
6655 else if (ctxt->value->nodesetval == NULL)
6656 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6657 else
6658 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6659 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006660#endif
6661}
6662
6663/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006664 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006665 * @ctxt: the XPath Parser context
6666 *
6667 * [3] RelativeLocationPath ::= Step
6668 * | RelativeLocationPath '/' Step
6669 * | AbbreviatedRelativeLocationPath
6670 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6671 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006672 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00006673 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006674static void
Owen Taylor3473f882001-02-23 17:55:21 +00006675#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006676xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006677#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006678xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006679#endif
6680(xmlXPathParserContextPtr ctxt) {
6681 SKIP_BLANKS;
6682 if ((CUR == '/') && (NXT(1) == '/')) {
6683 SKIP(2);
6684 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006685 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6686 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006687 } else if (CUR == '/') {
6688 NEXT;
6689 SKIP_BLANKS;
6690 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006691 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006692 SKIP_BLANKS;
6693 while (CUR == '/') {
6694 if ((CUR == '/') && (NXT(1) == '/')) {
6695 SKIP(2);
6696 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006697 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00006698 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006699 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006700 } else if (CUR == '/') {
6701 NEXT;
6702 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006703 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006704 }
6705 SKIP_BLANKS;
6706 }
6707}
6708
6709/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006710 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006711 * @ctxt: the XPath Parser context
6712 *
6713 * [1] LocationPath ::= RelativeLocationPath
6714 * | AbsoluteLocationPath
6715 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6716 * | AbbreviatedAbsoluteLocationPath
6717 * [10] AbbreviatedAbsoluteLocationPath ::=
6718 * '//' RelativeLocationPath
6719 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006720 * Compile a location path
6721 *
Owen Taylor3473f882001-02-23 17:55:21 +00006722 * // is short for /descendant-or-self::node()/. For example,
6723 * //para is short for /descendant-or-self::node()/child::para and
6724 * so will select any para element in the document (even a para element
6725 * that is a document element will be selected by //para since the
6726 * document element node is a child of the root node); div//para is
6727 * short for div/descendant-or-self::node()/child::para and so will
6728 * select all para descendants of div children.
6729 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006730static void
6731xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006732 SKIP_BLANKS;
6733 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006734 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006735 } else {
6736 while (CUR == '/') {
6737 if ((CUR == '/') && (NXT(1) == '/')) {
6738 SKIP(2);
6739 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006740 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6741 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006742 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006743 } else if (CUR == '/') {
6744 NEXT;
6745 SKIP_BLANKS;
6746 if (CUR != 0)
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006747 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006748 }
6749 }
6750 }
6751}
6752
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006753/************************************************************************
6754 * *
6755 * XPath precompiled expression evaluation *
6756 * *
6757 ************************************************************************/
6758
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006759static void
6760xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
6761
6762/**
6763 * xmlXPathNodeCollectAndTest:
6764 * @ctxt: the XPath Parser context
6765 * @op: the XPath precompiled step operation
6766 *
6767 * This is the function implementing a step: based on the current list
6768 * of nodes, it builds up a new list, looking at all nodes under that
6769 * axis and selecting them it also do the predicate filtering
6770 *
6771 * Pushes the new NodeSet resulting from the search.
6772 */
6773static void
6774xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
6775 xmlXPathStepOpPtr op) {
6776 xmlXPathAxisVal axis = op->value;
6777 xmlXPathTestVal test = op->value2;
6778 xmlXPathTypeVal type = op->value3;
6779 const xmlChar *prefix = op->value4;
6780 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006781 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006782
6783#ifdef DEBUG_STEP
6784 int n = 0, t = 0;
6785#endif
6786 int i;
6787 xmlNodeSetPtr ret, list;
6788 xmlXPathTraversalFunction next = NULL;
6789 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
6790 xmlNodePtr cur = NULL;
6791 xmlXPathObjectPtr obj;
6792 xmlNodeSetPtr nodelist;
6793 xmlNodePtr tmp;
6794
6795 CHECK_TYPE(XPATH_NODESET);
6796 obj = valuePop(ctxt);
6797 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006798 if (prefix != NULL) {
6799 URI = xmlXPathNsLookup(ctxt->context, prefix);
6800 if (URI == NULL)
6801 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
6802 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006803
6804#ifdef DEBUG_STEP
6805 xmlGenericError(xmlGenericErrorContext,
6806 "new step : ");
6807#endif
6808 switch (axis) {
6809 case AXIS_ANCESTOR:
6810#ifdef DEBUG_STEP
6811 xmlGenericError(xmlGenericErrorContext,
6812 "axis 'ancestors' ");
6813#endif
6814 next = xmlXPathNextAncestor; break;
6815 case AXIS_ANCESTOR_OR_SELF:
6816#ifdef DEBUG_STEP
6817 xmlGenericError(xmlGenericErrorContext,
6818 "axis 'ancestors-or-self' ");
6819#endif
6820 next = xmlXPathNextAncestorOrSelf; break;
6821 case AXIS_ATTRIBUTE:
6822#ifdef DEBUG_STEP
6823 xmlGenericError(xmlGenericErrorContext,
6824 "axis 'attributes' ");
6825#endif
6826 next = xmlXPathNextAttribute; break;
6827 break;
6828 case AXIS_CHILD:
6829#ifdef DEBUG_STEP
6830 xmlGenericError(xmlGenericErrorContext,
6831 "axis 'child' ");
6832#endif
6833 next = xmlXPathNextChild; break;
6834 case AXIS_DESCENDANT:
6835#ifdef DEBUG_STEP
6836 xmlGenericError(xmlGenericErrorContext,
6837 "axis 'descendant' ");
6838#endif
6839 next = xmlXPathNextDescendant; break;
6840 case AXIS_DESCENDANT_OR_SELF:
6841#ifdef DEBUG_STEP
6842 xmlGenericError(xmlGenericErrorContext,
6843 "axis 'descendant-or-self' ");
6844#endif
6845 next = xmlXPathNextDescendantOrSelf; break;
6846 case AXIS_FOLLOWING:
6847#ifdef DEBUG_STEP
6848 xmlGenericError(xmlGenericErrorContext,
6849 "axis 'following' ");
6850#endif
6851 next = xmlXPathNextFollowing; break;
6852 case AXIS_FOLLOWING_SIBLING:
6853#ifdef DEBUG_STEP
6854 xmlGenericError(xmlGenericErrorContext,
6855 "axis 'following-siblings' ");
6856#endif
6857 next = xmlXPathNextFollowingSibling; break;
6858 case AXIS_NAMESPACE:
6859#ifdef DEBUG_STEP
6860 xmlGenericError(xmlGenericErrorContext,
6861 "axis 'namespace' ");
6862#endif
6863 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
6864 break;
6865 case AXIS_PARENT:
6866#ifdef DEBUG_STEP
6867 xmlGenericError(xmlGenericErrorContext,
6868 "axis 'parent' ");
6869#endif
6870 next = xmlXPathNextParent; break;
6871 case AXIS_PRECEDING:
6872#ifdef DEBUG_STEP
6873 xmlGenericError(xmlGenericErrorContext,
6874 "axis 'preceding' ");
6875#endif
6876 next = xmlXPathNextPreceding; break;
6877 case AXIS_PRECEDING_SIBLING:
6878#ifdef DEBUG_STEP
6879 xmlGenericError(xmlGenericErrorContext,
6880 "axis 'preceding-sibling' ");
6881#endif
6882 next = xmlXPathNextPrecedingSibling; break;
6883 case AXIS_SELF:
6884#ifdef DEBUG_STEP
6885 xmlGenericError(xmlGenericErrorContext,
6886 "axis 'self' ");
6887#endif
6888 next = xmlXPathNextSelf; break;
6889 }
6890 if (next == NULL)
6891 return;
6892
6893 nodelist = obj->nodesetval;
6894 if (nodelist == NULL) {
6895 xmlXPathFreeObject(obj);
6896 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
6897 return;
6898 }
6899 addNode = xmlXPathNodeSetAddUnique;
6900 ret = NULL;
6901#ifdef DEBUG_STEP
6902 xmlGenericError(xmlGenericErrorContext,
6903 " context contains %d nodes\n",
6904 nodelist->nodeNr);
6905 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006906 case NODE_TEST_NONE:
6907 xmlGenericError(xmlGenericErrorContext,
6908 " searching for none !!!\n");
6909 break;
6910 case NODE_TEST_TYPE:
6911 xmlGenericError(xmlGenericErrorContext,
6912 " searching for type %d\n", type);
6913 break;
6914 case NODE_TEST_PI:
6915 xmlGenericError(xmlGenericErrorContext,
6916 " searching for PI !!!\n");
6917 break;
6918 case NODE_TEST_ALL:
6919 xmlGenericError(xmlGenericErrorContext,
6920 " searching for *\n");
6921 break;
6922 case NODE_TEST_NS:
6923 xmlGenericError(xmlGenericErrorContext,
6924 " searching for namespace %s\n",
6925 prefix);
6926 break;
6927 case NODE_TEST_NAME:
6928 xmlGenericError(xmlGenericErrorContext,
6929 " searching for name %s\n", name);
6930 if (prefix != NULL)
6931 xmlGenericError(xmlGenericErrorContext,
6932 " with namespace %s\n",
6933 prefix);
6934 break;
6935 }
6936 xmlGenericError(xmlGenericErrorContext, "Testing : ");
6937#endif
6938 /*
6939 * 2.3 Node Tests
6940 * - For the attribute axis, the principal node type is attribute.
6941 * - For the namespace axis, the principal node type is namespace.
6942 * - For other axes, the principal node type is element.
6943 *
6944 * A node test * is true for any node of the
6945 * principal node type. For example, child::* willi
6946 * select all element children of the context node
6947 */
6948 tmp = ctxt->context->node;
6949 for (i = 0;i < nodelist->nodeNr; i++) {
6950 ctxt->context->node = nodelist->nodeTab[i];
6951
6952 cur = NULL;
6953 list = xmlXPathNodeSetCreate(NULL);
6954 do {
6955 cur = next(ctxt, cur);
6956 if (cur == NULL) break;
6957#ifdef DEBUG_STEP
6958 t++;
6959 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
6960#endif
6961 switch (test) {
6962 case NODE_TEST_NONE:
6963 ctxt->context->node = tmp;
6964 STRANGE
6965 return;
6966 case NODE_TEST_TYPE:
6967 if ((cur->type == type) ||
6968 ((type == NODE_TYPE_NODE) &&
6969 ((cur->type == XML_DOCUMENT_NODE) ||
6970 (cur->type == XML_HTML_DOCUMENT_NODE) ||
6971 (cur->type == XML_ELEMENT_NODE) ||
6972 (cur->type == XML_PI_NODE) ||
6973 (cur->type == XML_COMMENT_NODE) ||
6974 (cur->type == XML_CDATA_SECTION_NODE) ||
6975 (cur->type == XML_TEXT_NODE)))) {
6976#ifdef DEBUG_STEP
6977 n++;
6978#endif
6979 addNode(list, cur);
6980 }
6981 break;
6982 case NODE_TEST_PI:
6983 if (cur->type == XML_PI_NODE) {
6984 if ((name != NULL) &&
6985 (!xmlStrEqual(name, cur->name)))
6986 break;
6987#ifdef DEBUG_STEP
6988 n++;
6989#endif
6990 addNode(list, cur);
6991 }
6992 break;
6993 case NODE_TEST_ALL:
6994 if (axis == AXIS_ATTRIBUTE) {
6995 if (cur->type == XML_ATTRIBUTE_NODE) {
6996#ifdef DEBUG_STEP
6997 n++;
6998#endif
6999 addNode(list, cur);
7000 }
7001 } else if (axis == AXIS_NAMESPACE) {
7002 if (cur->type == XML_NAMESPACE_DECL) {
7003#ifdef DEBUG_STEP
7004 n++;
7005#endif
7006 addNode(list, cur);
7007 }
7008 } else {
7009 if ((cur->type == XML_ELEMENT_NODE) ||
7010 (cur->type == XML_DOCUMENT_NODE) ||
7011 (cur->type == XML_HTML_DOCUMENT_NODE)) {
7012 if (prefix == NULL) {
7013#ifdef DEBUG_STEP
7014 n++;
7015#endif
7016 addNode(list, cur);
7017 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007018 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007019 cur->ns->href))) {
7020#ifdef DEBUG_STEP
7021 n++;
7022#endif
7023 addNode(list, cur);
7024 }
7025 }
7026 }
7027 break;
7028 case NODE_TEST_NS: {
7029 TODO;
7030 break;
7031 }
7032 case NODE_TEST_NAME:
7033 switch (cur->type) {
7034 case XML_ELEMENT_NODE:
7035 if (xmlStrEqual(name, cur->name)) {
7036 if (prefix == NULL) {
7037 if ((cur->ns == NULL) ||
7038 (cur->ns->prefix == NULL)) {
7039#ifdef DEBUG_STEP
7040 n++;
7041#endif
7042 addNode(list, cur);
7043 }
7044 } else {
7045 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007046 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007047 cur->ns->href))) {
7048#ifdef DEBUG_STEP
7049 n++;
7050#endif
7051 addNode(list, cur);
7052 }
7053 }
7054 }
7055 break;
7056 case XML_ATTRIBUTE_NODE: {
7057 xmlAttrPtr attr = (xmlAttrPtr) cur;
7058 if (xmlStrEqual(name, attr->name)) {
7059 if (prefix == NULL) {
7060 if ((attr->ns == NULL) ||
7061 (attr->ns->prefix == NULL)) {
7062#ifdef DEBUG_STEP
7063 n++;
7064#endif
7065 addNode(list, (xmlNodePtr) attr);
7066 }
7067 } else {
7068 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007069 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007070 attr->ns->href))) {
7071#ifdef DEBUG_STEP
7072 n++;
7073#endif
7074 addNode(list, (xmlNodePtr) attr);
7075 }
7076 }
7077 }
7078 break;
7079 }
7080 case XML_NAMESPACE_DECL: {
7081 TODO;
7082 break;
7083 }
7084 default:
7085 break;
7086 }
7087 break;
7088 }
7089 } while (cur != NULL);
7090
7091 /*
7092 * If there is some predicate filtering do it now
7093 */
7094 if (op->ch2 != -1) {
7095 xmlXPathObjectPtr obj2;
7096
7097 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7098 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7099 CHECK_TYPE(XPATH_NODESET);
7100 obj2 = valuePop(ctxt);
7101 list = obj2->nodesetval;
7102 obj2->nodesetval = NULL;
7103 xmlXPathFreeObject(obj2);
7104 }
7105 if (ret == NULL) {
7106 ret = list;
7107 } else {
7108 ret = xmlXPathNodeSetMerge(ret, list);
7109 xmlXPathFreeNodeSet(list);
7110 }
7111 }
7112 ctxt->context->node = tmp;
7113#ifdef DEBUG_STEP
7114 xmlGenericError(xmlGenericErrorContext,
7115 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7116#endif
7117 xmlXPathFreeObject(obj);
7118 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7119}
7120
Owen Taylor3473f882001-02-23 17:55:21 +00007121/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007122 * xmlXPathCompOpEval:
7123 * @ctxt: the XPath parser context with the compiled expression
7124 * @op: an XPath compiled operation
7125 *
7126 * Evaluate the Precompiled XPath operation
7127 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007128static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007129xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7130 int equal, ret;
7131 xmlXPathCompExprPtr comp;
7132 xmlXPathObjectPtr arg1, arg2;
7133
7134 comp = ctxt->comp;
7135 switch (op->op) {
7136 case XPATH_OP_END:
7137 return;
7138 case XPATH_OP_AND:
7139 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7140 xmlXPathBooleanFunction(ctxt, 1);
7141 if (ctxt->value->boolval == 0)
7142 return;
7143 arg2 = valuePop(ctxt);
7144 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7145 xmlXPathBooleanFunction(ctxt, 1);
7146 arg1 = valuePop(ctxt);
7147 arg1->boolval &= arg2->boolval;
7148 valuePush(ctxt, arg1);
7149 xmlXPathFreeObject(arg2);
7150 return;
7151 case XPATH_OP_OR:
7152 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7153 xmlXPathBooleanFunction(ctxt, 1);
7154 if (ctxt->value->boolval == 1)
7155 return;
7156 arg2 = valuePop(ctxt);
7157 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7158 xmlXPathBooleanFunction(ctxt, 1);
7159 arg1 = valuePop(ctxt);
7160 arg1->boolval |= arg2->boolval;
7161 valuePush(ctxt, arg1);
7162 xmlXPathFreeObject(arg2);
7163 return;
7164 case XPATH_OP_EQUAL:
7165 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7166 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7167 equal = xmlXPathEqualValues(ctxt);
7168 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7169 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7170 return;
7171 case XPATH_OP_CMP:
7172 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7173 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7174 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7175 valuePush(ctxt, xmlXPathNewBoolean(ret));
7176 return;
7177 case XPATH_OP_PLUS:
7178 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7179 if (op->ch2 != -1)
7180 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7181 if (op->value == 0) xmlXPathSubValues(ctxt);
7182 else if (op->value == 1) xmlXPathAddValues(ctxt);
7183 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7184 else if (op->value == 3) {
7185 xmlXPathObjectPtr arg;
7186
7187 POP_FLOAT
7188 valuePush(ctxt, arg);
7189 }
7190 return;
7191 case XPATH_OP_MULT:
7192 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7193 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7194 if (op->value == 0) xmlXPathMultValues(ctxt);
7195 else if (op->value == 1) xmlXPathDivValues(ctxt);
7196 else if (op->value == 2) xmlXPathModValues(ctxt);
7197 return;
7198 case XPATH_OP_UNION:
7199 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7200 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7201 CHECK_TYPE(XPATH_NODESET);
7202 arg2 = valuePop(ctxt);
7203
7204 CHECK_TYPE(XPATH_NODESET);
7205 arg1 = valuePop(ctxt);
7206
7207 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7208 arg2->nodesetval);
7209 valuePush(ctxt, arg1);
7210 xmlXPathFreeObject(arg2);
7211 return;
7212 case XPATH_OP_ROOT:
7213 xmlXPathRoot(ctxt);
7214 return;
7215 case XPATH_OP_NODE:
7216 if (op->ch1 != -1)
7217 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7218 if (op->ch2 != -1)
7219 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7220 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7221 return;
7222 case XPATH_OP_RESET:
7223 if (op->ch1 != -1)
7224 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7225 if (op->ch2 != -1)
7226 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7227 ctxt->context->node = NULL;
7228 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007229 case XPATH_OP_COLLECT: {
7230 if (op->ch1 == -1)
7231 return;
7232
7233 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7234 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007235 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007236 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007237 case XPATH_OP_VALUE:
7238 valuePush(ctxt,
7239 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7240 return;
7241 case XPATH_OP_VARIABLE: {
7242 if (op->ch1 != -1)
7243 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7244 if (op->value5 == NULL)
7245 valuePush(ctxt,
7246 xmlXPathVariableLookup(ctxt->context, op->value4));
7247 else {
7248 const xmlChar *URI;
7249 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7250 if (URI == NULL) {
7251 xmlGenericError(xmlGenericErrorContext,
7252 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7253 op->value4, op->value5);
7254 return;
7255 }
7256 valuePush(ctxt,
7257 xmlXPathVariableLookupNS(ctxt->context,
7258 op->value4, URI));
7259 }
7260 return;
7261 }
7262 case XPATH_OP_FUNCTION: {
7263 xmlXPathFunction func;
7264
7265 if (op->ch1 != -1)
7266 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007267 if (op->cache != NULL)
7268 func = (xmlXPathFunction) op->cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007269 else {
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007270 if (op->value5 == NULL)
7271 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7272 else {
7273 const xmlChar *URI;
7274 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7275 if (URI == NULL) {
7276 xmlGenericError(xmlGenericErrorContext,
7277 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7278 op->value4, op->value5);
7279 return;
7280 }
7281 func = xmlXPathFunctionLookupNS(ctxt->context,
7282 op->value4, URI);
7283 }
7284 if (func == NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007285 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007286 "xmlXPathRunEval: function %s not found\n",
7287 op->value4);
7288 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007289 return;
7290 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007291 op->cache = (void *) func;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007292 }
7293 func(ctxt, op->value);
7294 return;
7295 }
7296 case XPATH_OP_ARG:
7297 if (op->ch1 != -1)
7298 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7299 if (op->ch2 != -1)
7300 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7301 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007302 case XPATH_OP_PREDICATE:
7303 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007304 xmlXPathObjectPtr res;
7305 xmlXPathObjectPtr obj, tmp;
7306 xmlNodeSetPtr newset = NULL;
7307 xmlNodeSetPtr oldset;
7308 xmlNodePtr oldnode;
7309 int i;
7310
7311 if (op->ch1 != -1)
7312 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7313 if (op->ch2 == -1)
7314 return;
7315
7316 oldnode = ctxt->context->node;
7317
7318#ifdef LIBXML_XPTR_ENABLED
7319 /*
7320 * Hum are we filtering the result of an XPointer expression
7321 */
7322 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007323 xmlLocationSetPtr newlocset = NULL;
7324 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007325
7326 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007327 * Extract the old locset, and then evaluate the result of the
7328 * expression for all the element in the locset. use it to grow
7329 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007330 */
7331 CHECK_TYPE(XPATH_LOCATIONSET);
7332 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007333 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007334 ctxt->context->node = NULL;
7335
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007336 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007337 ctxt->context->contextSize = 0;
7338 ctxt->context->proximityPosition = 0;
7339 if (op->ch2 != -1)
7340 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7341 res = valuePop(ctxt);
7342 if (res != NULL)
7343 xmlXPathFreeObject(res);
7344 valuePush(ctxt, obj);
7345 CHECK_ERROR;
7346 return;
7347 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007348 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007349
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007350 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007351 /*
7352 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007353 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007354 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007355 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007356 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7357 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007358 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007359 ctxt->context->proximityPosition = i + 1;
7360
7361 if (op->ch2 != -1)
7362 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7363 CHECK_ERROR;
7364
7365 /*
7366 * The result of the evaluation need to be tested to
7367 * decided whether the filter succeeded or not
7368 */
7369 res = valuePop(ctxt);
7370 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007371 xmlXPtrLocationSetAdd(newlocset,
7372 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007373 }
7374
7375 /*
7376 * Cleanup
7377 */
7378 if (res != NULL)
7379 xmlXPathFreeObject(res);
7380 if (ctxt->value == tmp) {
7381 res = valuePop(ctxt);
7382 xmlXPathFreeObject(res);
7383 }
7384
7385 ctxt->context->node = NULL;
7386 }
7387
7388 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007389 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007390 */
7391 xmlXPathFreeObject(obj);
7392 ctxt->context->node = NULL;
7393 ctxt->context->contextSize = -1;
7394 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007395 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007396 ctxt->context->node = oldnode;
7397 return;
7398 }
7399#endif /* LIBXML_XPTR_ENABLED */
7400
7401 /*
7402 * Extract the old set, and then evaluate the result of the
7403 * expression for all the element in the set. use it to grow
7404 * up a new set.
7405 */
7406 CHECK_TYPE(XPATH_NODESET);
7407 obj = valuePop(ctxt);
7408 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007409
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007410 oldnode = ctxt->context->node;
7411 ctxt->context->node = NULL;
7412
7413 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7414 ctxt->context->contextSize = 0;
7415 ctxt->context->proximityPosition = 0;
7416 if (op->ch2 != -1)
7417 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7418 res = valuePop(ctxt);
7419 if (res != NULL)
7420 xmlXPathFreeObject(res);
7421 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007422 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007423 CHECK_ERROR;
7424 } else {
7425 /*
7426 * Initialize the new set.
7427 */
7428 newset = xmlXPathNodeSetCreate(NULL);
7429
7430 for (i = 0; i < oldset->nodeNr; i++) {
7431 /*
7432 * Run the evaluation with a node list made of
7433 * a single item in the nodeset.
7434 */
7435 ctxt->context->node = oldset->nodeTab[i];
7436 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7437 valuePush(ctxt, tmp);
7438 ctxt->context->contextSize = oldset->nodeNr;
7439 ctxt->context->proximityPosition = i + 1;
7440
7441 if (op->ch2 != -1)
7442 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7443 CHECK_ERROR;
7444
7445 /*
7446 * The result of the evaluation need to be tested to
7447 * decided whether the filter succeeded or not
7448 */
7449 res = valuePop(ctxt);
7450 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7451 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7452 }
7453
7454 /*
7455 * Cleanup
7456 */
7457 if (res != NULL)
7458 xmlXPathFreeObject(res);
7459 if (ctxt->value == tmp) {
7460 res = valuePop(ctxt);
7461 xmlXPathFreeObject(res);
7462 }
7463
7464 ctxt->context->node = NULL;
7465 }
7466
7467 /*
7468 * The result is used as the new evaluation set.
7469 */
7470 xmlXPathFreeObject(obj);
7471 ctxt->context->node = NULL;
7472 ctxt->context->contextSize = -1;
7473 ctxt->context->proximityPosition = -1;
7474 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7475 }
7476 ctxt->context->node = oldnode;
7477 return;
7478 }
7479 case XPATH_OP_SORT:
7480 if (op->ch1 != -1)
7481 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7482 if ((ctxt->value != NULL) &&
7483 (ctxt->value->type == XPATH_NODESET) &&
7484 (ctxt->value->nodesetval != NULL))
7485 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7486 return;
7487#ifdef LIBXML_XPTR_ENABLED
7488 case XPATH_OP_RANGETO: {
7489 xmlXPathObjectPtr range;
7490 xmlXPathObjectPtr res, obj;
7491 xmlXPathObjectPtr tmp;
7492 xmlLocationSetPtr newset = NULL;
7493 xmlNodeSetPtr oldset;
7494 int i;
7495
7496 if (op->ch1 != -1)
7497 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7498 if (op->ch2 == -1)
7499 return;
7500
7501 CHECK_TYPE(XPATH_NODESET);
7502 obj = valuePop(ctxt);
7503 oldset = obj->nodesetval;
7504 ctxt->context->node = NULL;
7505
7506 newset = xmlXPtrLocationSetCreate(NULL);
7507
Daniel Veillard911f49a2001-04-07 15:39:35 +00007508 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007509 for (i = 0; i < oldset->nodeNr; i++) {
7510 /*
7511 * Run the evaluation with a node list made of a single item
7512 * in the nodeset.
7513 */
7514 ctxt->context->node = oldset->nodeTab[i];
7515 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7516 valuePush(ctxt, tmp);
7517
7518 if (op->ch2 != -1)
7519 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7520 CHECK_ERROR;
7521
7522 /*
7523 * The result of the evaluation need to be tested to
7524 * decided whether the filter succeeded or not
7525 */
7526 res = valuePop(ctxt);
7527 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7528 if (range != NULL) {
7529 xmlXPtrLocationSetAdd(newset, range);
7530 }
7531
7532 /*
7533 * Cleanup
7534 */
7535 if (res != NULL)
7536 xmlXPathFreeObject(res);
7537 if (ctxt->value == tmp) {
7538 res = valuePop(ctxt);
7539 xmlXPathFreeObject(res);
7540 }
7541
7542 ctxt->context->node = NULL;
7543 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007544 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007545
7546 /*
7547 * The result is used as the new evaluation set.
7548 */
7549 xmlXPathFreeObject(obj);
7550 ctxt->context->node = NULL;
7551 ctxt->context->contextSize = -1;
7552 ctxt->context->proximityPosition = -1;
7553 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7554 return;
7555 }
7556#endif /* LIBXML_XPTR_ENABLED */
7557 }
7558 xmlGenericError(xmlGenericErrorContext,
7559 "XPath: unknown precompiled operation %d\n",
7560 op->op);
7561 return;
7562}
7563
7564/**
7565 * xmlXPathRunEval:
7566 * @ctxt: the XPath parser context with the compiled expression
7567 *
7568 * Evaluate the Precompiled XPath expression in the given context.
7569 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007570static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007571xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7572 xmlXPathCompExprPtr comp;
7573
7574 if ((ctxt == NULL) || (ctxt->comp == NULL))
7575 return;
7576
7577 if (ctxt->valueTab == NULL) {
7578 /* Allocate the value stack */
7579 ctxt->valueTab = (xmlXPathObjectPtr *)
7580 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7581 if (ctxt->valueTab == NULL) {
7582 xmlFree(ctxt);
7583 xmlGenericError(xmlGenericErrorContext,
7584 "xmlXPathRunEval: out of memory\n");
7585 return;
7586 }
7587 ctxt->valueNr = 0;
7588 ctxt->valueMax = 10;
7589 ctxt->value = NULL;
7590 }
7591 comp = ctxt->comp;
7592 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7593}
7594
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007595/************************************************************************
7596 * *
7597 * Public interfaces *
7598 * *
7599 ************************************************************************/
7600
7601/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007602 * xmlXPathEvalPredicate:
7603 * @ctxt: the XPath context
7604 * @res: the Predicate Expression evaluation result
7605 *
7606 * Evaluate a predicate result for the current node.
7607 * A PredicateExpr is evaluated by evaluating the Expr and converting
7608 * the result to a boolean. If the result is a number, the result will
7609 * be converted to true if the number is equal to the position of the
7610 * context node in the context node list (as returned by the position
7611 * function) and will be converted to false otherwise; if the result
7612 * is not a number, then the result will be converted as if by a call
7613 * to the boolean function.
7614 *
7615 * Return 1 if predicate is true, 0 otherwise
7616 */
7617int
7618xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7619 if (res == NULL) return(0);
7620 switch (res->type) {
7621 case XPATH_BOOLEAN:
7622 return(res->boolval);
7623 case XPATH_NUMBER:
7624 return(res->floatval == ctxt->proximityPosition);
7625 case XPATH_NODESET:
7626 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007627 if (res->nodesetval == NULL)
7628 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007629 return(res->nodesetval->nodeNr != 0);
7630 case XPATH_STRING:
7631 return((res->stringval != NULL) &&
7632 (xmlStrlen(res->stringval) != 0));
7633 default:
7634 STRANGE
7635 }
7636 return(0);
7637}
7638
7639/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007640 * xmlXPathEvaluatePredicateResult:
7641 * @ctxt: the XPath Parser context
7642 * @res: the Predicate Expression evaluation result
7643 *
7644 * Evaluate a predicate result for the current node.
7645 * A PredicateExpr is evaluated by evaluating the Expr and converting
7646 * the result to a boolean. If the result is a number, the result will
7647 * be converted to true if the number is equal to the position of the
7648 * context node in the context node list (as returned by the position
7649 * function) and will be converted to false otherwise; if the result
7650 * is not a number, then the result will be converted as if by a call
7651 * to the boolean function.
7652 *
7653 * Return 1 if predicate is true, 0 otherwise
7654 */
7655int
7656xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
7657 xmlXPathObjectPtr res) {
7658 if (res == NULL) return(0);
7659 switch (res->type) {
7660 case XPATH_BOOLEAN:
7661 return(res->boolval);
7662 case XPATH_NUMBER:
7663 return(res->floatval == ctxt->context->proximityPosition);
7664 case XPATH_NODESET:
7665 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00007666 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00007667 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007668 return(res->nodesetval->nodeNr != 0);
7669 case XPATH_STRING:
7670 return((res->stringval != NULL) &&
7671 (xmlStrlen(res->stringval) != 0));
7672 default:
7673 STRANGE
7674 }
7675 return(0);
7676}
7677
7678/**
7679 * xmlXPathCompile:
7680 * @str: the XPath expression
7681 *
7682 * Compile an XPath expression
7683 *
7684 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7685 * the caller has to free the object.
7686 */
7687xmlXPathCompExprPtr
7688xmlXPathCompile(const xmlChar *str) {
7689 xmlXPathParserContextPtr ctxt;
7690 xmlXPathCompExprPtr comp;
7691
7692 xmlXPathInit();
7693
7694 ctxt = xmlXPathNewParserContext(str, NULL);
7695 xmlXPathCompileExpr(ctxt);
7696
Daniel Veillard40af6492001-04-22 08:50:55 +00007697 if (*ctxt->cur != 0) {
7698 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7699 comp = NULL;
7700 } else {
7701 comp = ctxt->comp;
7702 ctxt->comp = NULL;
7703 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007704 xmlXPathFreeParserContext(ctxt);
7705 return(comp);
7706}
7707
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007708/**
7709 * xmlXPathCompiledEval:
7710 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00007711 * @ctx: the XPath context
7712 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007713 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00007714 *
7715 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7716 * the caller has to free the object.
7717 */
7718xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007719xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00007720 xmlXPathParserContextPtr ctxt;
7721 xmlXPathObjectPtr res, tmp, init = NULL;
7722 int stack = 0;
7723
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007724 if ((comp == NULL) || (ctx == NULL))
7725 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007726 xmlXPathInit();
7727
7728 CHECK_CONTEXT(ctx)
7729
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007730 ctxt = xmlXPathCompParserContext(comp, ctx);
7731 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007732
7733 if (ctxt->value == NULL) {
7734 xmlGenericError(xmlGenericErrorContext,
7735 "xmlXPathEval: evaluation failed\n");
7736 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007737 } else {
7738 res = valuePop(ctxt);
7739 }
7740
7741 do {
7742 tmp = valuePop(ctxt);
7743 if (tmp != NULL) {
7744 if (tmp != init)
7745 stack++;
7746 xmlXPathFreeObject(tmp);
7747 }
7748 } while (tmp != NULL);
7749 if ((stack != 0) && (res != NULL)) {
7750 xmlGenericError(xmlGenericErrorContext,
7751 "xmlXPathEval: %d object left on the stack\n",
7752 stack);
7753 }
7754 if (ctxt->error != XPATH_EXPRESSION_OK) {
7755 xmlXPathFreeObject(res);
7756 res = NULL;
7757 }
7758
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007759
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007760 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007761 xmlXPathFreeParserContext(ctxt);
7762 return(res);
7763}
7764
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007765/**
7766 * xmlXPathEvalExpr:
7767 * @ctxt: the XPath Parser context
7768 *
7769 * Parse and evaluate an XPath expression in the given context,
7770 * then push the result on the context stack
7771 */
7772void
7773xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
7774 xmlXPathCompileExpr(ctxt);
7775 xmlXPathRunEval(ctxt);
7776}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007777
7778/**
7779 * xmlXPathEval:
7780 * @str: the XPath expression
7781 * @ctx: the XPath context
7782 *
7783 * Evaluate the XPath Location Path in the given context.
7784 *
7785 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
7786 * the caller has to free the object.
7787 */
7788xmlXPathObjectPtr
7789xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
7790 xmlXPathParserContextPtr ctxt;
7791 xmlXPathObjectPtr res, tmp, init = NULL;
7792 int stack = 0;
7793
7794 xmlXPathInit();
7795
7796 CHECK_CONTEXT(ctx)
7797
7798 ctxt = xmlXPathNewParserContext(str, ctx);
7799 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007800
7801 if (ctxt->value == NULL) {
7802 xmlGenericError(xmlGenericErrorContext,
7803 "xmlXPathEval: evaluation failed\n");
7804 res = NULL;
7805 } else if (*ctxt->cur != 0) {
7806 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7807 res = NULL;
7808 } else {
7809 res = valuePop(ctxt);
7810 }
7811
7812 do {
7813 tmp = valuePop(ctxt);
7814 if (tmp != NULL) {
7815 if (tmp != init)
7816 stack++;
7817 xmlXPathFreeObject(tmp);
7818 }
7819 } while (tmp != NULL);
7820 if ((stack != 0) && (res != NULL)) {
7821 xmlGenericError(xmlGenericErrorContext,
7822 "xmlXPathEval: %d object left on the stack\n",
7823 stack);
7824 }
7825 if (ctxt->error != XPATH_EXPRESSION_OK) {
7826 xmlXPathFreeObject(res);
7827 res = NULL;
7828 }
7829
Owen Taylor3473f882001-02-23 17:55:21 +00007830 xmlXPathFreeParserContext(ctxt);
7831 return(res);
7832}
7833
7834/**
7835 * xmlXPathEvalExpression:
7836 * @str: the XPath expression
7837 * @ctxt: the XPath context
7838 *
7839 * Evaluate the XPath expression in the given context.
7840 *
7841 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
7842 * the caller has to free the object.
7843 */
7844xmlXPathObjectPtr
7845xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
7846 xmlXPathParserContextPtr pctxt;
7847 xmlXPathObjectPtr res, tmp;
7848 int stack = 0;
7849
7850 xmlXPathInit();
7851
7852 CHECK_CONTEXT(ctxt)
7853
7854 pctxt = xmlXPathNewParserContext(str, ctxt);
7855 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007856
7857 if (*pctxt->cur != 0) {
7858 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
7859 res = NULL;
7860 } else {
7861 res = valuePop(pctxt);
7862 }
7863 do {
7864 tmp = valuePop(pctxt);
7865 if (tmp != NULL) {
7866 xmlXPathFreeObject(tmp);
7867 stack++;
7868 }
7869 } while (tmp != NULL);
7870 if ((stack != 0) && (res != NULL)) {
7871 xmlGenericError(xmlGenericErrorContext,
7872 "xmlXPathEvalExpression: %d object left on the stack\n",
7873 stack);
7874 }
7875 xmlXPathFreeParserContext(pctxt);
7876 return(res);
7877}
7878
7879/**
7880 * xmlXPathRegisterAllFunctions:
7881 * @ctxt: the XPath context
7882 *
7883 * Registers all default XPath functions in this context
7884 */
7885void
7886xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
7887{
7888 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
7889 xmlXPathBooleanFunction);
7890 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
7891 xmlXPathCeilingFunction);
7892 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
7893 xmlXPathCountFunction);
7894 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
7895 xmlXPathConcatFunction);
7896 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
7897 xmlXPathContainsFunction);
7898 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
7899 xmlXPathIdFunction);
7900 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
7901 xmlXPathFalseFunction);
7902 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
7903 xmlXPathFloorFunction);
7904 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
7905 xmlXPathLastFunction);
7906 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
7907 xmlXPathLangFunction);
7908 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
7909 xmlXPathLocalNameFunction);
7910 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
7911 xmlXPathNotFunction);
7912 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
7913 xmlXPathNameFunction);
7914 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
7915 xmlXPathNamespaceURIFunction);
7916 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
7917 xmlXPathNormalizeFunction);
7918 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
7919 xmlXPathNumberFunction);
7920 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
7921 xmlXPathPositionFunction);
7922 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
7923 xmlXPathRoundFunction);
7924 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
7925 xmlXPathStringFunction);
7926 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
7927 xmlXPathStringLengthFunction);
7928 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
7929 xmlXPathStartsWithFunction);
7930 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
7931 xmlXPathSubstringFunction);
7932 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
7933 xmlXPathSubstringBeforeFunction);
7934 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
7935 xmlXPathSubstringAfterFunction);
7936 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
7937 xmlXPathSumFunction);
7938 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
7939 xmlXPathTrueFunction);
7940 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
7941 xmlXPathTranslateFunction);
7942}
7943
7944#endif /* LIBXML_XPATH_ENABLED */