blob: 7f256dd04cad212c1ae324566a25e6289f674b6a [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 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
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 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000063/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000064/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000065/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000066
67void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
68double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000069double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000070
Daniel Veillard9e7160d2001-03-18 23:17:47 +000071/************************************************************************
72 * *
73 * Floating point stuff *
74 * *
75 ************************************************************************/
76
Owen Taylor3473f882001-02-23 17:55:21 +000077/*
Owen Taylor3473f882001-02-23 17:55:21 +000078 * The lack of portability of this section of the libc is annoying !
79 */
80double xmlXPathNAN = 0;
81double xmlXPathPINF = 1;
82double xmlXPathNINF = -1;
83
84#ifndef isinf
85#ifndef HAVE_ISINF
86
87#if HAVE_FPCLASS
88
89int isinf(double d) {
90 fpclass_t type = fpclass(d);
91 switch (type) {
92 case FP_NINF:
93 return(-1);
94 case FP_PINF:
95 return(1);
96 }
97 return(0);
98}
99
100#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
101
102#if HAVE_FP_CLASS_H
103#include <fp_class.h>
104#endif
105
106int isinf(double d) {
107#if HAVE_FP_CLASS
108 int fpclass = fp_class(d);
109#else
110 int fpclass = fp_class_d(d);
111#endif
112 if (fpclass == FP_POS_INF)
113 return(1);
114 if (fpclass == FP_NEG_INF)
115 return(-1);
116 return(0);
117}
118
119#elif defined(HAVE_CLASS)
120
121int isinf(double d) {
122 int fpclass = class(d);
123 if (fpclass == FP_PLUS_INF)
124 return(1);
125 if (fpclass == FP_MINUS_INF)
126 return(-1);
127 return(0);
128}
129#elif defined(finite) || defined(HAVE_FINITE)
130int isinf(double x) { return !finite(x) && x==x; }
131#elif defined(HUGE_VAL)
132int isinf(double x)
133{
134 if (x == HUGE_VAL)
135 return(1);
136 if (x == -HUGE_VAL)
137 return(-1);
138 return(0);
139}
140#endif
141
142#endif /* ! HAVE_ISINF */
143#endif /* ! defined(isinf) */
144
145#ifndef isnan
146#ifndef HAVE_ISNAN
147
148#ifdef HAVE_ISNAND
149#define isnan(f) isnand(f)
150#endif /* HAVE_iSNAND */
151
152#endif /* ! HAVE_iSNAN */
153#endif /* ! defined(isnan) */
154
Daniel Veillard5792e162001-04-30 17:44:45 +0000155
156/**
157 * xmlXPathDivideBy:
158 *
159 * The best way found so far to generate the NAN, +-INF
160 * without hitting a compiler bug or optimization :-\
161 *
162 * Returns the double resulting from the division
163 */
164double
165xmlXPathDivideBy(double f, double fzero) {
Daniel Veillard81418e32001-05-22 15:08:55 +0000166 double ret;
Daniel Veillard5792e162001-04-30 17:44:45 +0000167#ifdef HAVE_SIGNAL
168#ifdef SIGFPE
169#ifdef SIG_IGN
170 void (*sighandler)(int);
171 sighandler = signal(SIGFPE, SIG_IGN);
172#endif
173#endif
174#endif
175 ret = f / fzero;
176#ifdef HAVE_SIGNAL
177#ifdef SIGFPE
178#ifdef SIG_IGN
179 signal(SIGFPE, sighandler);
180#endif
181#endif
182#endif
183 return(ret);
184}
185
Owen Taylor3473f882001-02-23 17:55:21 +0000186/**
187 * xmlXPathInit:
188 *
189 * Initialize the XPath environment
190 */
191void
192xmlXPathInit(void) {
193 static int initialized = 0;
194
195 if (initialized) return;
196
Daniel Veillarda53c6882001-07-25 17:18:57 +0000197#if defined(HUGE_VAL) && defined(DBL_MAX)
198 xmlXPathPINF = (HUGE_VAL == DBL_MAX) ?
199 xmlXPathDivideBy(1.0, 0.0) : HUGE_VAL;
200 xmlXPathNINF = -xmlXPathPINF;
201 xmlXPathNAN = xmlXPathDivideBy(xmlXPathPINF, xmlXPathPINF);
202#else
Daniel Veillard5792e162001-04-30 17:44:45 +0000203 xmlXPathNAN = xmlXPathDivideBy(0.0, 0.0);
204 xmlXPathPINF = xmlXPathDivideBy(1.0, 0.0);
Daniel Veillard541d6552001-06-07 14:20:01 +0000205 xmlXPathNINF = xmlXPathDivideBy(-1.0, 0.0);
Daniel Veillarda53c6882001-07-25 17:18:57 +0000206#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000207
208 initialized = 1;
209}
210
211/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000212 * *
213 * Parser Types *
214 * *
215 ************************************************************************/
216
217/*
218 * Types are private:
219 */
220
221typedef enum {
222 XPATH_OP_END=0,
223 XPATH_OP_AND,
224 XPATH_OP_OR,
225 XPATH_OP_EQUAL,
226 XPATH_OP_CMP,
227 XPATH_OP_PLUS,
228 XPATH_OP_MULT,
229 XPATH_OP_UNION,
230 XPATH_OP_ROOT,
231 XPATH_OP_NODE,
232 XPATH_OP_RESET,
233 XPATH_OP_COLLECT,
234 XPATH_OP_VALUE,
235 XPATH_OP_VARIABLE,
236 XPATH_OP_FUNCTION,
237 XPATH_OP_ARG,
238 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000239 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000240 XPATH_OP_SORT
241#ifdef LIBXML_XPTR_ENABLED
242 ,XPATH_OP_RANGETO
243#endif
244} xmlXPathOp;
245
246typedef enum {
247 AXIS_ANCESTOR = 1,
248 AXIS_ANCESTOR_OR_SELF,
249 AXIS_ATTRIBUTE,
250 AXIS_CHILD,
251 AXIS_DESCENDANT,
252 AXIS_DESCENDANT_OR_SELF,
253 AXIS_FOLLOWING,
254 AXIS_FOLLOWING_SIBLING,
255 AXIS_NAMESPACE,
256 AXIS_PARENT,
257 AXIS_PRECEDING,
258 AXIS_PRECEDING_SIBLING,
259 AXIS_SELF
260} xmlXPathAxisVal;
261
262typedef enum {
263 NODE_TEST_NONE = 0,
264 NODE_TEST_TYPE = 1,
265 NODE_TEST_PI = 2,
266 NODE_TEST_ALL = 3,
267 NODE_TEST_NS = 4,
268 NODE_TEST_NAME = 5
269} xmlXPathTestVal;
270
271typedef enum {
272 NODE_TYPE_NODE = 0,
273 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
274 NODE_TYPE_TEXT = XML_TEXT_NODE,
275 NODE_TYPE_PI = XML_PI_NODE
276} xmlXPathTypeVal;
277
278
279typedef struct _xmlXPathStepOp xmlXPathStepOp;
280typedef xmlXPathStepOp *xmlXPathStepOpPtr;
281struct _xmlXPathStepOp {
282 xmlXPathOp op;
283 int ch1;
284 int ch2;
285 int value;
286 int value2;
287 int value3;
288 void *value4;
289 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000290 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000291 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000292};
293
294struct _xmlXPathCompExpr {
295 int nbStep;
296 int maxStep;
297 xmlXPathStepOp *steps; /* ops for computation */
298 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000299#ifdef DEBUG_EVAL_COUNTS
300 int nb;
301 xmlChar *string;
302#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000303};
304
305/************************************************************************
306 * *
307 * Parser Type functions *
308 * *
309 ************************************************************************/
310
311/**
312 * xmlXPathNewCompExpr:
313 *
314 * Create a new Xpath component
315 *
316 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
317 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000318static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000319xmlXPathNewCompExpr(void) {
320 xmlXPathCompExprPtr cur;
321
322 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
323 if (cur == NULL) {
324 xmlGenericError(xmlGenericErrorContext,
325 "xmlXPathNewCompExpr : malloc failed\n");
326 return(NULL);
327 }
328 memset(cur, 0, sizeof(xmlXPathCompExpr));
329 cur->maxStep = 10;
330 cur->nbStep = 0;
331 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
332 sizeof(xmlXPathStepOp));
333 if (cur->steps == NULL) {
334 xmlGenericError(xmlGenericErrorContext,
335 "xmlXPathNewCompExpr : malloc failed\n");
336 xmlFree(cur);
337 return(NULL);
338 }
339 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
340 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000341#ifdef DEBUG_EVAL_COUNTS
342 cur->nb = 0;
343#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000344 return(cur);
345}
346
347/**
348 * xmlXPathFreeCompExpr:
349 * @comp: an XPATH comp
350 *
351 * Free up the memory allocated by @comp
352 */
353void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000354xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
355{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000356 xmlXPathStepOpPtr op;
357 int i;
358
359 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000360 return;
361 for (i = 0; i < comp->nbStep; i++) {
362 op = &comp->steps[i];
363 if (op->value4 != NULL) {
364 if (op->op == XPATH_OP_VALUE)
365 xmlXPathFreeObject(op->value4);
366 else
367 xmlFree(op->value4);
368 }
369 if (op->value5 != NULL)
370 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000371 }
372 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000373 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000374 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000375#ifdef DEBUG_EVAL_COUNTS
376 if (comp->string != NULL) {
377 xmlFree(comp->string);
378 }
379#endif
380
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000381 xmlFree(comp);
382}
383
384/**
385 * xmlXPathCompExprAdd:
386 * @comp: the compiled expression
387 * @ch1: first child index
388 * @ch2: second child index
389 * @op: an op
390 * @value: the first int value
391 * @value2: the second int value
392 * @value3: the third int value
393 * @value4: the first string value
394 * @value5: the second string value
395 *
396 * Add an step to an XPath Compiled Expression
397 *
398 * Returns -1 in case of failure, the index otherwise
399 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000400static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000401xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
402 xmlXPathOp op, int value,
403 int value2, int value3, void *value4, void *value5) {
404 if (comp->nbStep >= comp->maxStep) {
405 xmlXPathStepOp *real;
406
407 comp->maxStep *= 2;
408 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
409 comp->maxStep * sizeof(xmlXPathStepOp));
410 if (real == NULL) {
411 comp->maxStep /= 2;
412 xmlGenericError(xmlGenericErrorContext,
413 "xmlXPathCompExprAdd : realloc failed\n");
414 return(-1);
415 }
416 comp->steps = real;
417 }
418 comp->last = comp->nbStep;
419 comp->steps[comp->nbStep].ch1 = ch1;
420 comp->steps[comp->nbStep].ch2 = ch2;
421 comp->steps[comp->nbStep].op = op;
422 comp->steps[comp->nbStep].value = value;
423 comp->steps[comp->nbStep].value2 = value2;
424 comp->steps[comp->nbStep].value3 = value3;
425 comp->steps[comp->nbStep].value4 = value4;
426 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000427 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000428 return(comp->nbStep++);
429}
430
Daniel Veillardf06307e2001-07-03 10:35:50 +0000431/**
432 * xmlXPathCompSwap:
433 * @comp: the compiled expression
434 * @op: operation index
435 *
436 * Swaps 2 operations in the compiled expression
437 * TODO: not thread safe, disable for multi-thread operations
438 *
439 * Returns -1 in case of failure, the index otherwise
440 */
441static void
442xmlXPathCompSwap(xmlXPathStepOpPtr op) {
443 int tmp;
444
445 tmp = op->ch1;
446 op->ch1 = op->ch2;
447 op->ch2 = tmp;
448}
449
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000450#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
451 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
452 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000453#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
454 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
455 (op), (val), (val2), (val3), (val4), (val5))
456
457#define PUSH_LEAVE_EXPR(op, val, val2) \
458xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
459
460#define PUSH_UNARY_EXPR(op, ch, val, val2) \
461xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
462
463#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
464xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
465
466/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000467 * *
468 * Debugging related functions *
469 * *
470 ************************************************************************/
471
472#define TODO \
473 xmlGenericError(xmlGenericErrorContext, \
474 "Unimplemented block at %s:%d\n", \
475 __FILE__, __LINE__);
476
477#define STRANGE \
478 xmlGenericError(xmlGenericErrorContext, \
479 "Internal error at %s:%d\n", \
480 __FILE__, __LINE__);
481
482#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000483static void
484xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000485 int i;
486 char shift[100];
487
488 for (i = 0;((i < depth) && (i < 25));i++)
489 shift[2 * i] = shift[2 * i + 1] = ' ';
490 shift[2 * i] = shift[2 * i + 1] = 0;
491 if (cur == NULL) {
492 fprintf(output, shift);
493 fprintf(output, "Node is NULL !\n");
494 return;
495
496 }
497
498 if ((cur->type == XML_DOCUMENT_NODE) ||
499 (cur->type == XML_HTML_DOCUMENT_NODE)) {
500 fprintf(output, shift);
501 fprintf(output, " /\n");
502 } else if (cur->type == XML_ATTRIBUTE_NODE)
503 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
504 else
505 xmlDebugDumpOneNode(output, cur, depth);
506}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000507static void
508xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000509 xmlNodePtr tmp;
510 int i;
511 char shift[100];
512
513 for (i = 0;((i < depth) && (i < 25));i++)
514 shift[2 * i] = shift[2 * i + 1] = ' ';
515 shift[2 * i] = shift[2 * i + 1] = 0;
516 if (cur == NULL) {
517 fprintf(output, shift);
518 fprintf(output, "Node is NULL !\n");
519 return;
520
521 }
522
523 while (cur != NULL) {
524 tmp = cur;
525 cur = cur->next;
526 xmlDebugDumpOneNode(output, tmp, depth);
527 }
528}
Owen Taylor3473f882001-02-23 17:55:21 +0000529
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000530static void
531xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000532 int i;
533 char shift[100];
534
535 for (i = 0;((i < depth) && (i < 25));i++)
536 shift[2 * i] = shift[2 * i + 1] = ' ';
537 shift[2 * i] = shift[2 * i + 1] = 0;
538
539 if (cur == NULL) {
540 fprintf(output, shift);
541 fprintf(output, "NodeSet is NULL !\n");
542 return;
543
544 }
545
Daniel Veillard911f49a2001-04-07 15:39:35 +0000546 if (cur != NULL) {
547 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
548 for (i = 0;i < cur->nodeNr;i++) {
549 fprintf(output, shift);
550 fprintf(output, "%d", i + 1);
551 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
552 }
Owen Taylor3473f882001-02-23 17:55:21 +0000553 }
554}
555
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000556static void
557xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000558 int i;
559 char shift[100];
560
561 for (i = 0;((i < depth) && (i < 25));i++)
562 shift[2 * i] = shift[2 * i + 1] = ' ';
563 shift[2 * i] = shift[2 * i + 1] = 0;
564
565 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
566 fprintf(output, shift);
567 fprintf(output, "Value Tree is NULL !\n");
568 return;
569
570 }
571
572 fprintf(output, shift);
573 fprintf(output, "%d", i + 1);
574 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
575}
Owen Taylor3473f882001-02-23 17:55:21 +0000576#if defined(LIBXML_XPTR_ENABLED)
577void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000578static void
579xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000580 int i;
581 char shift[100];
582
583 for (i = 0;((i < depth) && (i < 25));i++)
584 shift[2 * i] = shift[2 * i + 1] = ' ';
585 shift[2 * i] = shift[2 * i + 1] = 0;
586
587 if (cur == NULL) {
588 fprintf(output, shift);
589 fprintf(output, "LocationSet is NULL !\n");
590 return;
591
592 }
593
594 for (i = 0;i < cur->locNr;i++) {
595 fprintf(output, shift);
596 fprintf(output, "%d : ", i + 1);
597 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
598 }
599}
Daniel Veillard017b1082001-06-21 11:20:21 +0000600#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000601
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000602/**
603 * xmlXPathDebugDumpObject:
604 * @output: the FILE * to dump the output
605 * @cur: the object to inspect
606 * @depth: indentation level
607 *
608 * Dump the content of the object for debugging purposes
609 */
610void
611xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000612 int i;
613 char shift[100];
614
615 for (i = 0;((i < depth) && (i < 25));i++)
616 shift[2 * i] = shift[2 * i + 1] = ' ';
617 shift[2 * i] = shift[2 * i + 1] = 0;
618
619 fprintf(output, shift);
620
621 if (cur == NULL) {
622 fprintf(output, "Object is empty (NULL)\n");
623 return;
624 }
625 switch(cur->type) {
626 case XPATH_UNDEFINED:
627 fprintf(output, "Object is uninitialized\n");
628 break;
629 case XPATH_NODESET:
630 fprintf(output, "Object is a Node Set :\n");
631 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
632 break;
633 case XPATH_XSLT_TREE:
634 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000635 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000636 break;
637 case XPATH_BOOLEAN:
638 fprintf(output, "Object is a Boolean : ");
639 if (cur->boolval) fprintf(output, "true\n");
640 else fprintf(output, "false\n");
641 break;
642 case XPATH_NUMBER:
Daniel Veillard357c9602001-05-03 10:49:20 +0000643 switch (isinf(cur->floatval)) {
644 case 1:
645 fprintf(output, "Object is a number : +Infinity\n");
646 break;
647 case -1:
648 fprintf(output, "Object is a number : -Infinity\n");
649 break;
650 default:
651 if (isnan(cur->floatval)) {
652 fprintf(output, "Object is a number : NaN\n");
653 } else {
654 fprintf(output, "Object is a number : %0g\n", cur->floatval);
655 }
656 }
Owen Taylor3473f882001-02-23 17:55:21 +0000657 break;
658 case XPATH_STRING:
659 fprintf(output, "Object is a string : ");
660 xmlDebugDumpString(output, cur->stringval);
661 fprintf(output, "\n");
662 break;
663 case XPATH_POINT:
664 fprintf(output, "Object is a point : index %d in node", cur->index);
665 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
666 fprintf(output, "\n");
667 break;
668 case XPATH_RANGE:
669 if ((cur->user2 == NULL) ||
670 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
671 fprintf(output, "Object is a collapsed range :\n");
672 fprintf(output, shift);
673 if (cur->index >= 0)
674 fprintf(output, "index %d in ", cur->index);
675 fprintf(output, "node\n");
676 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
677 depth + 1);
678 } else {
679 fprintf(output, "Object is a range :\n");
680 fprintf(output, shift);
681 fprintf(output, "From ");
682 if (cur->index >= 0)
683 fprintf(output, "index %d in ", cur->index);
684 fprintf(output, "node\n");
685 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
686 depth + 1);
687 fprintf(output, shift);
688 fprintf(output, "To ");
689 if (cur->index2 >= 0)
690 fprintf(output, "index %d in ", cur->index2);
691 fprintf(output, "node\n");
692 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
693 depth + 1);
694 fprintf(output, "\n");
695 }
696 break;
697 case XPATH_LOCATIONSET:
698#if defined(LIBXML_XPTR_ENABLED)
699 fprintf(output, "Object is a Location Set:\n");
700 xmlXPathDebugDumpLocationSet(output,
701 (xmlLocationSetPtr) cur->user, depth);
702#endif
703 break;
704 case XPATH_USERS:
705 fprintf(output, "Object is user defined\n");
706 break;
707 }
708}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000709
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000710static void
711xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000712 xmlXPathStepOpPtr op, int depth) {
713 int i;
714 char shift[100];
715
716 for (i = 0;((i < depth) && (i < 25));i++)
717 shift[2 * i] = shift[2 * i + 1] = ' ';
718 shift[2 * i] = shift[2 * i + 1] = 0;
719
720 fprintf(output, shift);
721 if (op == NULL) {
722 fprintf(output, "Step is NULL\n");
723 return;
724 }
725 switch (op->op) {
726 case XPATH_OP_END:
727 fprintf(output, "END"); break;
728 case XPATH_OP_AND:
729 fprintf(output, "AND"); break;
730 case XPATH_OP_OR:
731 fprintf(output, "OR"); break;
732 case XPATH_OP_EQUAL:
733 if (op->value)
734 fprintf(output, "EQUAL =");
735 else
736 fprintf(output, "EQUAL !=");
737 break;
738 case XPATH_OP_CMP:
739 if (op->value)
740 fprintf(output, "CMP <");
741 else
742 fprintf(output, "CMP >");
743 if (!op->value2)
744 fprintf(output, "=");
745 break;
746 case XPATH_OP_PLUS:
747 if (op->value == 0)
748 fprintf(output, "PLUS -");
749 else if (op->value == 1)
750 fprintf(output, "PLUS +");
751 else if (op->value == 2)
752 fprintf(output, "PLUS unary -");
753 else if (op->value == 3)
754 fprintf(output, "PLUS unary - -");
755 break;
756 case XPATH_OP_MULT:
757 if (op->value == 0)
758 fprintf(output, "MULT *");
759 else if (op->value == 1)
760 fprintf(output, "MULT div");
761 else
762 fprintf(output, "MULT mod");
763 break;
764 case XPATH_OP_UNION:
765 fprintf(output, "UNION"); break;
766 case XPATH_OP_ROOT:
767 fprintf(output, "ROOT"); break;
768 case XPATH_OP_NODE:
769 fprintf(output, "NODE"); break;
770 case XPATH_OP_RESET:
771 fprintf(output, "RESET"); break;
772 case XPATH_OP_SORT:
773 fprintf(output, "SORT"); break;
774 case XPATH_OP_COLLECT: {
775 xmlXPathAxisVal axis = op->value;
776 xmlXPathTestVal test = op->value2;
777 xmlXPathTypeVal type = op->value3;
778 const xmlChar *prefix = op->value4;
779 const xmlChar *name = op->value5;
780
781 fprintf(output, "COLLECT ");
782 switch (axis) {
783 case AXIS_ANCESTOR:
784 fprintf(output, " 'ancestors' "); break;
785 case AXIS_ANCESTOR_OR_SELF:
786 fprintf(output, " 'ancestors-or-self' "); break;
787 case AXIS_ATTRIBUTE:
788 fprintf(output, " 'attributes' "); break;
789 case AXIS_CHILD:
790 fprintf(output, " 'child' "); break;
791 case AXIS_DESCENDANT:
792 fprintf(output, " 'descendant' "); break;
793 case AXIS_DESCENDANT_OR_SELF:
794 fprintf(output, " 'descendant-or-self' "); break;
795 case AXIS_FOLLOWING:
796 fprintf(output, " 'following' "); break;
797 case AXIS_FOLLOWING_SIBLING:
798 fprintf(output, " 'following-siblings' "); break;
799 case AXIS_NAMESPACE:
800 fprintf(output, " 'namespace' "); break;
801 case AXIS_PARENT:
802 fprintf(output, " 'parent' "); break;
803 case AXIS_PRECEDING:
804 fprintf(output, " 'preceding' "); break;
805 case AXIS_PRECEDING_SIBLING:
806 fprintf(output, " 'preceding-sibling' "); break;
807 case AXIS_SELF:
808 fprintf(output, " 'self' "); break;
809 }
810 switch (test) {
811 case NODE_TEST_NONE:
812 fprintf(output, "'none' "); break;
813 case NODE_TEST_TYPE:
814 fprintf(output, "'type' "); break;
815 case NODE_TEST_PI:
816 fprintf(output, "'PI' "); break;
817 case NODE_TEST_ALL:
818 fprintf(output, "'all' "); break;
819 case NODE_TEST_NS:
820 fprintf(output, "'namespace' "); break;
821 case NODE_TEST_NAME:
822 fprintf(output, "'name' "); break;
823 }
824 switch (type) {
825 case NODE_TYPE_NODE:
826 fprintf(output, "'node' "); break;
827 case NODE_TYPE_COMMENT:
828 fprintf(output, "'comment' "); break;
829 case NODE_TYPE_TEXT:
830 fprintf(output, "'text' "); break;
831 case NODE_TYPE_PI:
832 fprintf(output, "'PI' "); break;
833 }
834 if (prefix != NULL)
835 fprintf(output, "%s:", prefix);
836 if (name != NULL)
837 fprintf(output, "%s", name);
838 break;
839
840 }
841 case XPATH_OP_VALUE: {
842 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
843
844 fprintf(output, "ELEM ");
845 xmlXPathDebugDumpObject(output, object, 0);
846 goto finish;
847 }
848 case XPATH_OP_VARIABLE: {
849 const xmlChar *prefix = op->value5;
850 const xmlChar *name = op->value4;
851
852 if (prefix != NULL)
853 fprintf(output, "VARIABLE %s:%s", prefix, name);
854 else
855 fprintf(output, "VARIABLE %s", name);
856 break;
857 }
858 case XPATH_OP_FUNCTION: {
859 int nbargs = op->value;
860 const xmlChar *prefix = op->value5;
861 const xmlChar *name = op->value4;
862
863 if (prefix != NULL)
864 fprintf(output, "FUNCTION %s:%s(%d args)",
865 prefix, name, nbargs);
866 else
867 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
868 break;
869 }
870 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
871 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000872 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000873#ifdef LIBXML_XPTR_ENABLED
874 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
875#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000876 default:
877 fprintf(output, "UNKNOWN %d\n", op->op); return;
878 }
879 fprintf(output, "\n");
880finish:
881 if (op->ch1 >= 0)
882 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
883 if (op->ch2 >= 0)
884 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
885}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000886
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000887/**
888 * xmlXPathDebugDumpCompExpr:
889 * @output: the FILE * for the output
890 * @comp: the precompiled XPath expression
891 * @depth: the indentation level.
892 *
893 * Dumps the tree of the compiled XPath expression.
894 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000895void
896xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
897 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000898 int i;
899 char shift[100];
900
901 for (i = 0;((i < depth) && (i < 25));i++)
902 shift[2 * i] = shift[2 * i + 1] = ' ';
903 shift[2 * i] = shift[2 * i + 1] = 0;
904
905 fprintf(output, shift);
906
907 if (comp == NULL) {
908 fprintf(output, "Compiled Expression is NULL\n");
909 return;
910 }
911 fprintf(output, "Compiled Expression : %d elements\n",
912 comp->nbStep);
913 i = comp->last;
914 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
915}
Daniel Veillard017b1082001-06-21 11:20:21 +0000916#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000917
918/************************************************************************
919 * *
920 * Parser stacks related functions and macros *
921 * *
922 ************************************************************************/
923
924/*
925 * Generic function for accessing stacks in the Parser Context
926 */
927
928#define PUSH_AND_POP(type, name) \
929extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
930 if (ctxt->name##Nr >= ctxt->name##Max) { \
931 ctxt->name##Max *= 2; \
932 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
933 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
934 if (ctxt->name##Tab == NULL) { \
935 xmlGenericError(xmlGenericErrorContext, \
936 "realloc failed !\n"); \
937 return(0); \
938 } \
939 } \
940 ctxt->name##Tab[ctxt->name##Nr] = value; \
941 ctxt->name = value; \
942 return(ctxt->name##Nr++); \
943} \
944extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
945 type ret; \
946 if (ctxt->name##Nr <= 0) return(0); \
947 ctxt->name##Nr--; \
948 if (ctxt->name##Nr > 0) \
949 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
950 else \
951 ctxt->name = NULL; \
952 ret = ctxt->name##Tab[ctxt->name##Nr]; \
953 ctxt->name##Tab[ctxt->name##Nr] = 0; \
954 return(ret); \
955} \
956
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000957/**
958 * valuePop:
959 * @ctxt: an XPath evaluation context
960 *
961 * Pops the top XPath object from the value stack
962 *
963 * Returns the XPath object just removed
964 */
965/**
966 * valuePush:
967 * @ctxt: an XPath evaluation context
968 * @value: the XPath object
969 *
970 * Pushes a new XPath object on top of the value stack
971 */
Owen Taylor3473f882001-02-23 17:55:21 +0000972PUSH_AND_POP(xmlXPathObjectPtr, value)
973
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000974/**
975 * xmlXPathPopBoolean:
976 * @ctxt: an XPath parser context
977 *
978 * Pops a boolean from the stack, handling conversion if needed.
979 * Check error with #xmlXPathCheckError.
980 *
981 * Returns the boolean
982 */
983int
984xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
985 xmlXPathObjectPtr obj;
986 int ret;
987
988 obj = valuePop(ctxt);
989 if (obj == NULL) {
990 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
991 return(0);
992 }
993 ret = xmlXPathCastToBoolean(obj);
994 xmlXPathFreeObject(obj);
995 return(ret);
996}
997
998/**
999 * xmlXPathPopNumber:
1000 * @ctxt: an XPath parser context
1001 *
1002 * Pops a number from the stack, handling conversion if needed.
1003 * Check error with #xmlXPathCheckError.
1004 *
1005 * Returns the number
1006 */
1007double
1008xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1009 xmlXPathObjectPtr obj;
1010 double ret;
1011
1012 obj = valuePop(ctxt);
1013 if (obj == NULL) {
1014 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1015 return(0);
1016 }
1017 ret = xmlXPathCastToNumber(obj);
1018 xmlXPathFreeObject(obj);
1019 return(ret);
1020}
1021
1022/**
1023 * xmlXPathPopString:
1024 * @ctxt: an XPath parser context
1025 *
1026 * Pops a string from the stack, handling conversion if needed.
1027 * Check error with #xmlXPathCheckError.
1028 *
1029 * Returns the string
1030 */
1031xmlChar *
1032xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1033 xmlXPathObjectPtr obj;
1034 xmlChar * ret;
1035
1036 obj = valuePop(ctxt);
1037 if (obj == NULL) {
1038 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1039 return(NULL);
1040 }
1041 ret = xmlXPathCastToString(obj);
1042 /* TODO: needs refactoring somewhere else */
1043 if (obj->stringval == ret)
1044 obj->stringval = NULL;
1045 xmlXPathFreeObject(obj);
1046 return(ret);
1047}
1048
1049/**
1050 * xmlXPathPopNodeSet:
1051 * @ctxt: an XPath parser context
1052 *
1053 * Pops a node-set from the stack, handling conversion if needed.
1054 * Check error with #xmlXPathCheckError.
1055 *
1056 * Returns the node-set
1057 */
1058xmlNodeSetPtr
1059xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1060 xmlXPathObjectPtr obj;
1061 xmlNodeSetPtr ret;
1062
1063 if (ctxt->value == NULL) {
1064 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1065 return(NULL);
1066 }
1067 if (!xmlXPathStackIsNodeSet(ctxt)) {
1068 xmlXPathSetTypeError(ctxt);
1069 return(NULL);
1070 }
1071 obj = valuePop(ctxt);
1072 ret = obj->nodesetval;
1073 xmlXPathFreeNodeSetList(obj);
1074 return(ret);
1075}
1076
1077/**
1078 * xmlXPathPopExternal:
1079 * @ctxt: an XPath parser context
1080 *
1081 * Pops an external oject from the stack, handling conversion if needed.
1082 * Check error with #xmlXPathCheckError.
1083 *
1084 * Returns the object
1085 */
1086void *
1087xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1088 xmlXPathObjectPtr obj;
1089 void * ret;
1090
1091 if (ctxt->value == NULL) {
1092 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1093 return(NULL);
1094 }
1095 if (ctxt->value->type != XPATH_USERS) {
1096 xmlXPathSetTypeError(ctxt);
1097 return(NULL);
1098 }
1099 obj = valuePop(ctxt);
1100 ret = obj->user;
1101 xmlXPathFreeObject(obj);
1102 return(ret);
1103}
1104
Owen Taylor3473f882001-02-23 17:55:21 +00001105/*
1106 * Macros for accessing the content. Those should be used only by the parser,
1107 * and not exported.
1108 *
1109 * Dirty macros, i.e. one need to make assumption on the context to use them
1110 *
1111 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1112 * CUR returns the current xmlChar value, i.e. a 8 bit value
1113 * in ISO-Latin or UTF-8.
1114 * This should be used internally by the parser
1115 * only to compare to ASCII values otherwise it would break when
1116 * running with UTF-8 encoding.
1117 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1118 * to compare on ASCII based substring.
1119 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1120 * strings within the parser.
1121 * CURRENT Returns the current char value, with the full decoding of
1122 * UTF-8 if we are using this mode. It returns an int.
1123 * NEXT Skip to the next character, this does the proper decoding
1124 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1125 * It returns the pointer to the current xmlChar.
1126 */
1127
1128#define CUR (*ctxt->cur)
1129#define SKIP(val) ctxt->cur += (val)
1130#define NXT(val) ctxt->cur[(val)]
1131#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001132#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1133
1134#define COPY_BUF(l,b,i,v) \
1135 if (l == 1) b[i++] = (xmlChar) v; \
1136 else i += xmlCopyChar(l,&b[i],v)
1137
1138#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001139
1140#define SKIP_BLANKS \
1141 while (IS_BLANK(*(ctxt->cur))) NEXT
1142
1143#define CURRENT (*ctxt->cur)
1144#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1145
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001146
1147#ifndef DBL_DIG
1148#define DBL_DIG 16
1149#endif
1150#ifndef DBL_EPSILON
1151#define DBL_EPSILON 1E-9
1152#endif
1153
1154#define UPPER_DOUBLE 1E9
1155#define LOWER_DOUBLE 1E-5
1156
1157#define INTEGER_DIGITS DBL_DIG
1158#define FRACTION_DIGITS (DBL_DIG + 1)
1159#define EXPONENT_DIGITS (3 + 2)
1160
1161/**
1162 * xmlXPathFormatNumber:
1163 * @number: number to format
1164 * @buffer: output buffer
1165 * @buffersize: size of output buffer
1166 *
1167 * Convert the number into a string representation.
1168 */
1169static void
1170xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1171{
1172 switch (isinf(number)) {
1173 case 1:
1174 if (buffersize > (int)sizeof("+Infinity"))
1175 sprintf(buffer, "+Infinity");
1176 break;
1177 case -1:
1178 if (buffersize > (int)sizeof("-Infinity"))
1179 sprintf(buffer, "-Infinity");
1180 break;
1181 default:
1182 if (isnan(number)) {
1183 if (buffersize > (int)sizeof("NaN"))
1184 sprintf(buffer, "NaN");
1185 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001186 /* 3 is sign, decimal point, and terminating zero */
1187 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1188 int integer_place, fraction_place;
1189 char *ptr;
1190 char *after_fraction;
1191 double absolute_value;
1192 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001193
Bjorn Reese70a9da52001-04-21 16:57:29 +00001194 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001195
Bjorn Reese70a9da52001-04-21 16:57:29 +00001196 /*
1197 * First choose format - scientific or regular floating point.
1198 * In either case, result is in work, and after_fraction points
1199 * just past the fractional part.
1200 */
1201 if ( ((absolute_value > UPPER_DOUBLE) ||
1202 (absolute_value < LOWER_DOUBLE)) &&
1203 (absolute_value != 0.0) ) {
1204 /* Use scientific notation */
1205 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1206 fraction_place = DBL_DIG - 1;
1207 snprintf(work, sizeof(work),"%*.*e",
1208 integer_place, fraction_place, number);
1209 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001210 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001211 else {
1212 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001213 if (absolute_value > 0.0)
1214 integer_place = 1 + (int)log10(absolute_value);
1215 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001216 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001217 fraction_place = (integer_place > 0)
1218 ? DBL_DIG - integer_place
1219 : DBL_DIG;
1220 size = snprintf(work, sizeof(work), "%0.*f",
1221 fraction_place, number);
1222 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001223 }
1224
Bjorn Reese70a9da52001-04-21 16:57:29 +00001225 /* Remove fractional trailing zeroes */
1226 ptr = after_fraction;
1227 while (*(--ptr) == '0')
1228 ;
1229 if (*ptr != '.')
1230 ptr++;
1231 strcpy(ptr, after_fraction);
1232
1233 /* Finally copy result back to caller */
1234 size = strlen(work) + 1;
1235 if (size > buffersize) {
1236 work[buffersize - 1] = 0;
1237 size = buffersize;
1238 }
1239 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001240 }
1241 break;
1242 }
1243}
1244
Owen Taylor3473f882001-02-23 17:55:21 +00001245/************************************************************************
1246 * *
1247 * Error handling routines *
1248 * *
1249 ************************************************************************/
1250
1251
1252const char *xmlXPathErrorMessages[] = {
1253 "Ok",
1254 "Number encoding",
1255 "Unfinished litteral",
1256 "Start of litteral",
1257 "Expected $ for variable reference",
1258 "Undefined variable",
1259 "Invalid predicate",
1260 "Invalid expression",
1261 "Missing closing curly brace",
1262 "Unregistered function",
1263 "Invalid operand",
1264 "Invalid type",
1265 "Invalid number of arguments",
1266 "Invalid context size",
1267 "Invalid context position",
1268 "Memory allocation error",
1269 "Syntax error",
1270 "Resource error",
1271 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001272 "Undefined namespace prefix",
1273 "Encoding error",
1274 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001275};
1276
1277/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001278 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001279 * @ctxt: the XPath Parser context
1280 * @file: the file name
1281 * @line: the line number
1282 * @no: the error number
1283 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001284 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001285 */
1286void
1287xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1288 int line, int no) {
1289 int n;
1290 const xmlChar *cur;
1291 const xmlChar *base;
1292
1293 xmlGenericError(xmlGenericErrorContext,
1294 "Error %s:%d: %s\n", file, line,
1295 xmlXPathErrorMessages[no]);
1296
1297 cur = ctxt->cur;
1298 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001299 if ((cur == NULL) || (base == NULL))
1300 return;
1301
Owen Taylor3473f882001-02-23 17:55:21 +00001302 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1303 cur--;
1304 }
1305 n = 0;
1306 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1307 cur--;
1308 if ((*cur == '\n') || (*cur == '\r')) cur++;
1309 base = cur;
1310 n = 0;
1311 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1312 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1313 n++;
1314 }
1315 xmlGenericError(xmlGenericErrorContext, "\n");
1316 cur = ctxt->cur;
1317 while ((*cur == '\n') || (*cur == '\r'))
1318 cur--;
1319 n = 0;
1320 while ((cur != base) && (n++ < 80)) {
1321 xmlGenericError(xmlGenericErrorContext, " ");
1322 base++;
1323 }
1324 xmlGenericError(xmlGenericErrorContext,"^\n");
1325}
1326
1327
1328/************************************************************************
1329 * *
1330 * Routines to handle NodeSets *
1331 * *
1332 ************************************************************************/
1333
1334/**
1335 * xmlXPathCmpNodes:
1336 * @node1: the first node
1337 * @node2: the second node
1338 *
1339 * Compare two nodes w.r.t document order
1340 *
1341 * Returns -2 in case of error 1 if first point < second point, 0 if
1342 * that's the same node, -1 otherwise
1343 */
1344int
1345xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1346 int depth1, depth2;
1347 xmlNodePtr cur, root;
1348
1349 if ((node1 == NULL) || (node2 == NULL))
1350 return(-2);
1351 /*
1352 * a couple of optimizations which will avoid computations in most cases
1353 */
1354 if (node1 == node2)
1355 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001356 if ((node1->type == XML_NAMESPACE_DECL) ||
1357 (node2->type == XML_NAMESPACE_DECL))
1358 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001359 if (node1 == node2->prev)
1360 return(1);
1361 if (node1 == node2->next)
1362 return(-1);
1363
1364 /*
1365 * compute depth to root
1366 */
1367 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1368 if (cur == node1)
1369 return(1);
1370 depth2++;
1371 }
1372 root = cur;
1373 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1374 if (cur == node2)
1375 return(-1);
1376 depth1++;
1377 }
1378 /*
1379 * Distinct document (or distinct entities :-( ) case.
1380 */
1381 if (root != cur) {
1382 return(-2);
1383 }
1384 /*
1385 * get the nearest common ancestor.
1386 */
1387 while (depth1 > depth2) {
1388 depth1--;
1389 node1 = node1->parent;
1390 }
1391 while (depth2 > depth1) {
1392 depth2--;
1393 node2 = node2->parent;
1394 }
1395 while (node1->parent != node2->parent) {
1396 node1 = node1->parent;
1397 node2 = node2->parent;
1398 /* should not happen but just in case ... */
1399 if ((node1 == NULL) || (node2 == NULL))
1400 return(-2);
1401 }
1402 /*
1403 * Find who's first.
1404 */
1405 if (node1 == node2->next)
1406 return(-1);
1407 for (cur = node1->next;cur != NULL;cur = cur->next)
1408 if (cur == node2)
1409 return(1);
1410 return(-1); /* assume there is no sibling list corruption */
1411}
1412
1413/**
1414 * xmlXPathNodeSetSort:
1415 * @set: the node set
1416 *
1417 * Sort the node set in document order
1418 */
1419void
1420xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001421 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001422 xmlNodePtr tmp;
1423
1424 if (set == NULL)
1425 return;
1426
1427 /* Use Shell's sort to sort the node-set */
1428 len = set->nodeNr;
1429 for (incr = len / 2; incr > 0; incr /= 2) {
1430 for (i = incr; i < len; i++) {
1431 j = i - incr;
1432 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001433 if (xmlXPathCmpNodes(set->nodeTab[j],
1434 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001435 tmp = set->nodeTab[j];
1436 set->nodeTab[j] = set->nodeTab[j + incr];
1437 set->nodeTab[j + incr] = tmp;
1438 j -= incr;
1439 } else
1440 break;
1441 }
1442 }
1443 }
1444}
1445
1446#define XML_NODESET_DEFAULT 10
1447/**
1448 * xmlXPathNodeSetCreate:
1449 * @val: an initial xmlNodePtr, or NULL
1450 *
1451 * Create a new xmlNodeSetPtr of type double and of value @val
1452 *
1453 * Returns the newly created object.
1454 */
1455xmlNodeSetPtr
1456xmlXPathNodeSetCreate(xmlNodePtr val) {
1457 xmlNodeSetPtr ret;
1458
1459 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1460 if (ret == NULL) {
1461 xmlGenericError(xmlGenericErrorContext,
1462 "xmlXPathNewNodeSet: out of memory\n");
1463 return(NULL);
1464 }
1465 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1466 if (val != NULL) {
1467 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1468 sizeof(xmlNodePtr));
1469 if (ret->nodeTab == NULL) {
1470 xmlGenericError(xmlGenericErrorContext,
1471 "xmlXPathNewNodeSet: out of memory\n");
1472 return(NULL);
1473 }
1474 memset(ret->nodeTab, 0 ,
1475 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1476 ret->nodeMax = XML_NODESET_DEFAULT;
1477 ret->nodeTab[ret->nodeNr++] = val;
1478 }
1479 return(ret);
1480}
1481
1482/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001483 * xmlXPathNodeSetContains:
1484 * @cur: the node-set
1485 * @val: the node
1486 *
1487 * checks whether @cur contains @val
1488 *
1489 * Returns true (1) if @cur contains @val, false (0) otherwise
1490 */
1491int
1492xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1493 int i;
1494
1495 for (i = 0; i < cur->nodeNr; i++) {
1496 if (cur->nodeTab[i] == val)
1497 return(1);
1498 }
1499 return(0);
1500}
1501
1502/**
Owen Taylor3473f882001-02-23 17:55:21 +00001503 * xmlXPathNodeSetAdd:
1504 * @cur: the initial node set
1505 * @val: a new xmlNodePtr
1506 *
1507 * add a new xmlNodePtr ot an existing NodeSet
1508 */
1509void
1510xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1511 int i;
1512
1513 if (val == NULL) return;
1514
1515 /*
1516 * check against doublons
1517 */
1518 for (i = 0;i < cur->nodeNr;i++)
1519 if (cur->nodeTab[i] == val) return;
1520
1521 /*
1522 * grow the nodeTab if needed
1523 */
1524 if (cur->nodeMax == 0) {
1525 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1526 sizeof(xmlNodePtr));
1527 if (cur->nodeTab == NULL) {
1528 xmlGenericError(xmlGenericErrorContext,
1529 "xmlXPathNodeSetAdd: out of memory\n");
1530 return;
1531 }
1532 memset(cur->nodeTab, 0 ,
1533 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1534 cur->nodeMax = XML_NODESET_DEFAULT;
1535 } else if (cur->nodeNr == cur->nodeMax) {
1536 xmlNodePtr *temp;
1537
1538 cur->nodeMax *= 2;
1539 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1540 sizeof(xmlNodePtr));
1541 if (temp == NULL) {
1542 xmlGenericError(xmlGenericErrorContext,
1543 "xmlXPathNodeSetAdd: out of memory\n");
1544 return;
1545 }
1546 cur->nodeTab = temp;
1547 }
1548 cur->nodeTab[cur->nodeNr++] = val;
1549}
1550
1551/**
1552 * xmlXPathNodeSetAddUnique:
1553 * @cur: the initial node set
1554 * @val: a new xmlNodePtr
1555 *
1556 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1557 * when we are sure the node is not already in the set.
1558 */
1559void
1560xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1561 if (val == NULL) return;
1562
1563 /*
1564 * grow the nodeTab if needed
1565 */
1566 if (cur->nodeMax == 0) {
1567 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1568 sizeof(xmlNodePtr));
1569 if (cur->nodeTab == NULL) {
1570 xmlGenericError(xmlGenericErrorContext,
1571 "xmlXPathNodeSetAddUnique: out of memory\n");
1572 return;
1573 }
1574 memset(cur->nodeTab, 0 ,
1575 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1576 cur->nodeMax = XML_NODESET_DEFAULT;
1577 } else if (cur->nodeNr == cur->nodeMax) {
1578 xmlNodePtr *temp;
1579
1580 cur->nodeMax *= 2;
1581 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1582 sizeof(xmlNodePtr));
1583 if (temp == NULL) {
1584 xmlGenericError(xmlGenericErrorContext,
1585 "xmlXPathNodeSetAddUnique: out of memory\n");
1586 return;
1587 }
1588 cur->nodeTab = temp;
1589 }
1590 cur->nodeTab[cur->nodeNr++] = val;
1591}
1592
1593/**
1594 * xmlXPathNodeSetMerge:
1595 * @val1: the first NodeSet or NULL
1596 * @val2: the second NodeSet
1597 *
1598 * Merges two nodesets, all nodes from @val2 are added to @val1
1599 * if @val1 is NULL, a new set is created and copied from @val2
1600 *
1601 * Returns val1 once extended or NULL in case of error.
1602 */
1603xmlNodeSetPtr
1604xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001605 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001606
1607 if (val2 == NULL) return(val1);
1608 if (val1 == NULL) {
1609 val1 = xmlXPathNodeSetCreate(NULL);
1610 }
1611
1612 initNr = val1->nodeNr;
1613
1614 for (i = 0;i < val2->nodeNr;i++) {
1615 /*
1616 * check against doublons
1617 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001618 skip = 0;
1619 for (j = 0; j < initNr; j++) {
1620 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1621 skip = 1;
1622 break;
1623 }
1624 }
1625 if (skip)
1626 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001627
1628 /*
1629 * grow the nodeTab if needed
1630 */
1631 if (val1->nodeMax == 0) {
1632 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1633 sizeof(xmlNodePtr));
1634 if (val1->nodeTab == NULL) {
1635 xmlGenericError(xmlGenericErrorContext,
1636 "xmlXPathNodeSetMerge: out of memory\n");
1637 return(NULL);
1638 }
1639 memset(val1->nodeTab, 0 ,
1640 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1641 val1->nodeMax = XML_NODESET_DEFAULT;
1642 } else if (val1->nodeNr == val1->nodeMax) {
1643 xmlNodePtr *temp;
1644
1645 val1->nodeMax *= 2;
1646 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1647 sizeof(xmlNodePtr));
1648 if (temp == NULL) {
1649 xmlGenericError(xmlGenericErrorContext,
1650 "xmlXPathNodeSetMerge: out of memory\n");
1651 return(NULL);
1652 }
1653 val1->nodeTab = temp;
1654 }
1655 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1656 }
1657
1658 return(val1);
1659}
1660
1661/**
1662 * xmlXPathNodeSetDel:
1663 * @cur: the initial node set
1664 * @val: an xmlNodePtr
1665 *
1666 * Removes an xmlNodePtr from an existing NodeSet
1667 */
1668void
1669xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1670 int i;
1671
1672 if (cur == NULL) return;
1673 if (val == NULL) return;
1674
1675 /*
1676 * check against doublons
1677 */
1678 for (i = 0;i < cur->nodeNr;i++)
1679 if (cur->nodeTab[i] == val) break;
1680
1681 if (i >= cur->nodeNr) {
1682#ifdef DEBUG
1683 xmlGenericError(xmlGenericErrorContext,
1684 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1685 val->name);
1686#endif
1687 return;
1688 }
1689 cur->nodeNr--;
1690 for (;i < cur->nodeNr;i++)
1691 cur->nodeTab[i] = cur->nodeTab[i + 1];
1692 cur->nodeTab[cur->nodeNr] = NULL;
1693}
1694
1695/**
1696 * xmlXPathNodeSetRemove:
1697 * @cur: the initial node set
1698 * @val: the index to remove
1699 *
1700 * Removes an entry from an existing NodeSet list.
1701 */
1702void
1703xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1704 if (cur == NULL) return;
1705 if (val >= cur->nodeNr) return;
1706 cur->nodeNr--;
1707 for (;val < cur->nodeNr;val++)
1708 cur->nodeTab[val] = cur->nodeTab[val + 1];
1709 cur->nodeTab[cur->nodeNr] = NULL;
1710}
1711
1712/**
1713 * xmlXPathFreeNodeSet:
1714 * @obj: the xmlNodeSetPtr to free
1715 *
1716 * Free the NodeSet compound (not the actual nodes !).
1717 */
1718void
1719xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1720 if (obj == NULL) return;
1721 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001722 xmlFree(obj->nodeTab);
1723 }
Owen Taylor3473f882001-02-23 17:55:21 +00001724 xmlFree(obj);
1725}
1726
1727/**
1728 * xmlXPathFreeValueTree:
1729 * @obj: the xmlNodeSetPtr to free
1730 *
1731 * Free the NodeSet compound and the actual tree, this is different
1732 * from xmlXPathFreeNodeSet()
1733 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001734static void
Owen Taylor3473f882001-02-23 17:55:21 +00001735xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1736 int i;
1737
1738 if (obj == NULL) return;
1739 for (i = 0;i < obj->nodeNr;i++)
1740 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001741 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001742
1743 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001744 xmlFree(obj->nodeTab);
1745 }
Owen Taylor3473f882001-02-23 17:55:21 +00001746 xmlFree(obj);
1747}
1748
1749#if defined(DEBUG) || defined(DEBUG_STEP)
1750/**
1751 * xmlGenericErrorContextNodeSet:
1752 * @output: a FILE * for the output
1753 * @obj: the xmlNodeSetPtr to free
1754 *
1755 * Quick display of a NodeSet
1756 */
1757void
1758xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1759 int i;
1760
1761 if (output == NULL) output = xmlGenericErrorContext;
1762 if (obj == NULL) {
1763 fprintf(output, "NodeSet == NULL !\n");
1764 return;
1765 }
1766 if (obj->nodeNr == 0) {
1767 fprintf(output, "NodeSet is empty\n");
1768 return;
1769 }
1770 if (obj->nodeTab == NULL) {
1771 fprintf(output, " nodeTab == NULL !\n");
1772 return;
1773 }
1774 for (i = 0; i < obj->nodeNr; i++) {
1775 if (obj->nodeTab[i] == NULL) {
1776 fprintf(output, " NULL !\n");
1777 return;
1778 }
1779 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1780 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1781 fprintf(output, " /");
1782 else if (obj->nodeTab[i]->name == NULL)
1783 fprintf(output, " noname!");
1784 else fprintf(output, " %s", obj->nodeTab[i]->name);
1785 }
1786 fprintf(output, "\n");
1787}
1788#endif
1789
1790/**
1791 * xmlXPathNewNodeSet:
1792 * @val: the NodePtr value
1793 *
1794 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1795 * it with the single Node @val
1796 *
1797 * Returns the newly created object.
1798 */
1799xmlXPathObjectPtr
1800xmlXPathNewNodeSet(xmlNodePtr val) {
1801 xmlXPathObjectPtr ret;
1802
1803 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1804 if (ret == NULL) {
1805 xmlGenericError(xmlGenericErrorContext,
1806 "xmlXPathNewNodeSet: out of memory\n");
1807 return(NULL);
1808 }
1809 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1810 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001811 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001812 ret->nodesetval = xmlXPathNodeSetCreate(val);
1813 return(ret);
1814}
1815
1816/**
1817 * xmlXPathNewValueTree:
1818 * @val: the NodePtr value
1819 *
1820 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1821 * it with the tree root @val
1822 *
1823 * Returns the newly created object.
1824 */
1825xmlXPathObjectPtr
1826xmlXPathNewValueTree(xmlNodePtr val) {
1827 xmlXPathObjectPtr ret;
1828
1829 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1830 if (ret == NULL) {
1831 xmlGenericError(xmlGenericErrorContext,
1832 "xmlXPathNewNodeSet: out of memory\n");
1833 return(NULL);
1834 }
1835 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1836 ret->type = XPATH_XSLT_TREE;
1837 ret->nodesetval = xmlXPathNodeSetCreate(val);
1838 return(ret);
1839}
1840
1841/**
1842 * xmlXPathNewNodeSetList:
1843 * @val: an existing NodeSet
1844 *
1845 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1846 * it with the Nodeset @val
1847 *
1848 * Returns the newly created object.
1849 */
1850xmlXPathObjectPtr
1851xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1852 xmlXPathObjectPtr ret;
1853 int i;
1854
1855 if (val == NULL)
1856 ret = NULL;
1857 else if (val->nodeTab == NULL)
1858 ret = xmlXPathNewNodeSet(NULL);
1859 else
1860 {
1861 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1862 for (i = 1; i < val->nodeNr; ++i)
1863 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1864 }
1865
1866 return(ret);
1867}
1868
1869/**
1870 * xmlXPathWrapNodeSet:
1871 * @val: the NodePtr value
1872 *
1873 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1874 *
1875 * Returns the newly created object.
1876 */
1877xmlXPathObjectPtr
1878xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1879 xmlXPathObjectPtr ret;
1880
1881 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1882 if (ret == NULL) {
1883 xmlGenericError(xmlGenericErrorContext,
1884 "xmlXPathWrapNodeSet: out of memory\n");
1885 return(NULL);
1886 }
1887 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1888 ret->type = XPATH_NODESET;
1889 ret->nodesetval = val;
1890 return(ret);
1891}
1892
1893/**
1894 * xmlXPathFreeNodeSetList:
1895 * @obj: an existing NodeSetList object
1896 *
1897 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1898 * the list contrary to xmlXPathFreeObject().
1899 */
1900void
1901xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1902 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001903 xmlFree(obj);
1904}
1905
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001906/**
1907 * xmlXPathDifference:
1908 * @nodes1: a node-set
1909 * @nodes2: a node-set
1910 *
1911 * Implements the EXSLT - Sets difference() function:
1912 * node-set set:difference (node-set, node-set)
1913 *
1914 * Returns the difference between the two node sets, or nodes1 if
1915 * nodes2 is empty
1916 */
1917xmlNodeSetPtr
1918xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1919 xmlNodeSetPtr ret;
1920 int i, l1;
1921 xmlNodePtr cur;
1922
1923 if (xmlXPathNodeSetIsEmpty(nodes2))
1924 return(nodes1);
1925
1926 ret = xmlXPathNodeSetCreate(NULL);
1927 if (xmlXPathNodeSetIsEmpty(nodes1))
1928 return(ret);
1929
1930 l1 = xmlXPathNodeSetGetLength(nodes1);
1931
1932 for (i = 0; i < l1; i++) {
1933 cur = xmlXPathNodeSetItem(nodes1, i);
1934 if (!xmlXPathNodeSetContains(nodes2, cur))
1935 xmlXPathNodeSetAddUnique(ret, cur);
1936 }
1937 return(ret);
1938}
1939
1940/**
1941 * xmlXPathIntersection:
1942 * @nodes1: a node-set
1943 * @nodes2: a node-set
1944 *
1945 * Implements the EXSLT - Sets intersection() function:
1946 * node-set set:intersection (node-set, node-set)
1947 *
1948 * Returns a node set comprising the nodes that are within both the
1949 * node sets passed as arguments
1950 */
1951xmlNodeSetPtr
1952xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1953 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
1954 int i, l1;
1955 xmlNodePtr cur;
1956
1957 if (xmlXPathNodeSetIsEmpty(nodes1))
1958 return(ret);
1959 if (xmlXPathNodeSetIsEmpty(nodes2))
1960 return(ret);
1961
1962 l1 = xmlXPathNodeSetGetLength(nodes1);
1963
1964 for (i = 0; i < l1; i++) {
1965 cur = xmlXPathNodeSetItem(nodes1, i);
1966 if (xmlXPathNodeSetContains(nodes2, cur))
1967 xmlXPathNodeSetAddUnique(ret, cur);
1968 }
1969 return(ret);
1970}
1971
1972/**
1973 * xmlXPathDistinctSorted:
1974 * @nodes: a node-set, sorted by document order
1975 *
1976 * Implements the EXSLT - Sets distinct() function:
1977 * node-set set:distinct (node-set)
1978 *
1979 * Returns a subset of the nodes contained in @nodes, or @nodes if
1980 * it is empty
1981 */
1982xmlNodeSetPtr
1983xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
1984 xmlNodeSetPtr ret;
1985 xmlHashTablePtr hash;
1986 int i, l;
1987 xmlChar * strval;
1988 xmlNodePtr cur;
1989
1990 if (xmlXPathNodeSetIsEmpty(nodes))
1991 return(nodes);
1992
1993 ret = xmlXPathNodeSetCreate(NULL);
1994 l = xmlXPathNodeSetGetLength(nodes);
1995 hash = xmlHashCreate (l);
1996 for (i = 0; i < l; i++) {
1997 cur = xmlXPathNodeSetItem(nodes, i);
1998 strval = xmlXPathCastNodeToString(cur);
1999 if (xmlHashLookup(hash, strval) == NULL) {
2000 xmlHashAddEntry(hash, strval, strval);
2001 xmlXPathNodeSetAddUnique(ret, cur);
2002 } else {
2003 xmlFree(strval);
2004 }
2005 }
2006 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2007 return(ret);
2008}
2009
2010/**
2011 * xmlXPathDistinct:
2012 * @nodes: a node-set
2013 *
2014 * Implements the EXSLT - Sets distinct() function:
2015 * node-set set:distinct (node-set)
2016 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2017 * is called with the sorted node-set
2018 *
2019 * Returns a subset of the nodes contained in @nodes, or @nodes if
2020 * it is empty
2021 */
2022xmlNodeSetPtr
2023xmlXPathDistinct (xmlNodeSetPtr nodes) {
2024 if (xmlXPathNodeSetIsEmpty(nodes))
2025 return(nodes);
2026
2027 xmlXPathNodeSetSort(nodes);
2028 return(xmlXPathDistinctSorted(nodes));
2029}
2030
2031/**
2032 * xmlXPathHasSameNodes:
2033 * @nodes1: a node-set
2034 * @nodes2: a node-set
2035 *
2036 * Implements the EXSLT - Sets has-same-nodes function:
2037 * boolean set:has-same-node(node-set, node-set)
2038 *
2039 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2040 * otherwise
2041 */
2042int
2043xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2044 int i, l;
2045 xmlNodePtr cur;
2046
2047 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2048 xmlXPathNodeSetIsEmpty(nodes2))
2049 return(0);
2050
2051 l = xmlXPathNodeSetGetLength(nodes1);
2052 for (i = 0; i < l; i++) {
2053 cur = xmlXPathNodeSetItem(nodes1, i);
2054 if (xmlXPathNodeSetContains(nodes2, cur))
2055 return(1);
2056 }
2057 return(0);
2058}
2059
2060/**
2061 * xmlXPathNodeLeadingSorted:
2062 * @nodes: a node-set, sorted by document order
2063 * @node: a node
2064 *
2065 * Implements the EXSLT - Sets leading() function:
2066 * node-set set:leading (node-set, node-set)
2067 *
2068 * Returns the nodes in @nodes that precede @node in document order,
2069 * @nodes if @node is NULL or an empty node-set if @nodes
2070 * doesn't contain @node
2071 */
2072xmlNodeSetPtr
2073xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2074 int i, l;
2075 xmlNodePtr cur;
2076 xmlNodeSetPtr ret;
2077
2078 if (node == NULL)
2079 return(nodes);
2080
2081 ret = xmlXPathNodeSetCreate(NULL);
2082 if (xmlXPathNodeSetIsEmpty(nodes) ||
2083 (!xmlXPathNodeSetContains(nodes, node)))
2084 return(ret);
2085
2086 l = xmlXPathNodeSetGetLength(nodes);
2087 for (i = 0; i < l; i++) {
2088 cur = xmlXPathNodeSetItem(nodes, i);
2089 if (cur == node)
2090 break;
2091 xmlXPathNodeSetAddUnique(ret, cur);
2092 }
2093 return(ret);
2094}
2095
2096/**
2097 * xmlXPathNodeLeading:
2098 * @nodes: a node-set
2099 * @node: a node
2100 *
2101 * Implements the EXSLT - Sets leading() function:
2102 * node-set set:leading (node-set, node-set)
2103 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2104 * is called.
2105 *
2106 * Returns the nodes in @nodes that precede @node in document order,
2107 * @nodes if @node is NULL or an empty node-set if @nodes
2108 * doesn't contain @node
2109 */
2110xmlNodeSetPtr
2111xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2112 xmlXPathNodeSetSort(nodes);
2113 return(xmlXPathNodeLeadingSorted(nodes, node));
2114}
2115
2116/**
2117 * xmlXPathLeadingSorted:
2118 * @nodes1: a node-set, sorted by document order
2119 * @nodes2: a node-set, sorted by document order
2120 *
2121 * Implements the EXSLT - Sets leading() function:
2122 * node-set set:leading (node-set, node-set)
2123 *
2124 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2125 * in document order, @nodes1 if @nodes2 is NULL or empty or
2126 * an empty node-set if @nodes1 doesn't contain @nodes2
2127 */
2128xmlNodeSetPtr
2129xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2130 if (xmlXPathNodeSetIsEmpty(nodes2))
2131 return(nodes1);
2132 return(xmlXPathNodeLeadingSorted(nodes1,
2133 xmlXPathNodeSetItem(nodes2, 1)));
2134}
2135
2136/**
2137 * xmlXPathLeading:
2138 * @nodes1: a node-set
2139 * @nodes2: a node-set
2140 *
2141 * Implements the EXSLT - Sets leading() function:
2142 * node-set set:leading (node-set, node-set)
2143 * @nodes1 and @nodes2 are sorted by document order, then
2144 * #exslSetsLeadingSorted is called.
2145 *
2146 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2147 * in document order, @nodes1 if @nodes2 is NULL or empty or
2148 * an empty node-set if @nodes1 doesn't contain @nodes2
2149 */
2150xmlNodeSetPtr
2151xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2152 if (xmlXPathNodeSetIsEmpty(nodes2))
2153 return(nodes1);
2154 if (xmlXPathNodeSetIsEmpty(nodes1))
2155 return(xmlXPathNodeSetCreate(NULL));
2156 xmlXPathNodeSetSort(nodes1);
2157 xmlXPathNodeSetSort(nodes2);
2158 return(xmlXPathNodeLeadingSorted(nodes1,
2159 xmlXPathNodeSetItem(nodes2, 1)));
2160}
2161
2162/**
2163 * xmlXPathNodeTrailingSorted:
2164 * @nodes: a node-set, sorted by document order
2165 * @node: a node
2166 *
2167 * Implements the EXSLT - Sets trailing() function:
2168 * node-set set:trailing (node-set, node-set)
2169 *
2170 * Returns the nodes in @nodes that follow @node in document order,
2171 * @nodes if @node is NULL or an empty node-set if @nodes
2172 * doesn't contain @node
2173 */
2174xmlNodeSetPtr
2175xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2176 int i, l;
2177 xmlNodePtr cur;
2178 xmlNodeSetPtr ret;
2179
2180 if (node == NULL)
2181 return(nodes);
2182
2183 ret = xmlXPathNodeSetCreate(NULL);
2184 if (xmlXPathNodeSetIsEmpty(nodes) ||
2185 (!xmlXPathNodeSetContains(nodes, node)))
2186 return(ret);
2187
2188 l = xmlXPathNodeSetGetLength(nodes);
2189 for (i = 0; i < l; i++) {
2190 cur = xmlXPathNodeSetItem(nodes, i);
2191 if (cur == node)
2192 break;
2193 xmlXPathNodeSetAddUnique(ret, cur);
2194 }
2195 return(ret);
2196}
2197
2198/**
2199 * xmlXPathNodeTrailing:
2200 * @nodes: a node-set
2201 * @node: a node
2202 *
2203 * Implements the EXSLT - Sets trailing() function:
2204 * node-set set:trailing (node-set, node-set)
2205 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2206 * is called.
2207 *
2208 * Returns the nodes in @nodes that follow @node in document order,
2209 * @nodes if @node is NULL or an empty node-set if @nodes
2210 * doesn't contain @node
2211 */
2212xmlNodeSetPtr
2213xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2214 xmlXPathNodeSetSort(nodes);
2215 return(xmlXPathNodeTrailingSorted(nodes, node));
2216}
2217
2218/**
2219 * xmlXPathTrailingSorted:
2220 * @nodes1: a node-set, sorted by document order
2221 * @nodes2: a node-set, sorted by document order
2222 *
2223 * Implements the EXSLT - Sets trailing() function:
2224 * node-set set:trailing (node-set, node-set)
2225 *
2226 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2227 * in document order, @nodes1 if @nodes2 is NULL or empty or
2228 * an empty node-set if @nodes1 doesn't contain @nodes2
2229 */
2230xmlNodeSetPtr
2231xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2232 if (xmlXPathNodeSetIsEmpty(nodes2))
2233 return(nodes1);
2234 return(xmlXPathNodeTrailingSorted(nodes1,
2235 xmlXPathNodeSetItem(nodes2, 0)));
2236}
2237
2238/**
2239 * xmlXPathTrailing:
2240 * @nodes1: a node-set
2241 * @nodes2: a node-set
2242 *
2243 * Implements the EXSLT - Sets trailing() function:
2244 * node-set set:trailing (node-set, node-set)
2245 * @nodes1 and @nodes2 are sorted by document order, then
2246 * #xmlXPathTrailingSorted is called.
2247 *
2248 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2249 * in document order, @nodes1 if @nodes2 is NULL or empty or
2250 * an empty node-set if @nodes1 doesn't contain @nodes2
2251 */
2252xmlNodeSetPtr
2253xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2254 if (xmlXPathNodeSetIsEmpty(nodes2))
2255 return(nodes1);
2256 if (xmlXPathNodeSetIsEmpty(nodes1))
2257 return(xmlXPathNodeSetCreate(NULL));
2258 xmlXPathNodeSetSort(nodes1);
2259 xmlXPathNodeSetSort(nodes2);
2260 return(xmlXPathNodeTrailingSorted(nodes1,
2261 xmlXPathNodeSetItem(nodes2, 0)));
2262}
2263
Owen Taylor3473f882001-02-23 17:55:21 +00002264/************************************************************************
2265 * *
2266 * Routines to handle extra functions *
2267 * *
2268 ************************************************************************/
2269
2270/**
2271 * xmlXPathRegisterFunc:
2272 * @ctxt: the XPath context
2273 * @name: the function name
2274 * @f: the function implementation or NULL
2275 *
2276 * Register a new function. If @f is NULL it unregisters the function
2277 *
2278 * Returns 0 in case of success, -1 in case of error
2279 */
2280int
2281xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2282 xmlXPathFunction f) {
2283 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2284}
2285
2286/**
2287 * xmlXPathRegisterFuncNS:
2288 * @ctxt: the XPath context
2289 * @name: the function name
2290 * @ns_uri: the function namespace URI
2291 * @f: the function implementation or NULL
2292 *
2293 * Register a new function. If @f is NULL it unregisters the function
2294 *
2295 * Returns 0 in case of success, -1 in case of error
2296 */
2297int
2298xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2299 const xmlChar *ns_uri, xmlXPathFunction f) {
2300 if (ctxt == NULL)
2301 return(-1);
2302 if (name == NULL)
2303 return(-1);
2304
2305 if (ctxt->funcHash == NULL)
2306 ctxt->funcHash = xmlHashCreate(0);
2307 if (ctxt->funcHash == NULL)
2308 return(-1);
2309 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2310}
2311
2312/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002313 * xmlXPathRegisterFuncLookup:
2314 * @ctxt: the XPath context
2315 * @f: the lookup function
2316 * @data: the lookup data
2317 *
2318 * Registers an external mecanism to do function lookup.
2319 */
2320void
2321xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2322 xmlXPathFuncLookupFunc f,
2323 void *funcCtxt) {
2324 if (ctxt == NULL)
2325 return;
2326 ctxt->funcLookupFunc = (void *) f;
2327 ctxt->funcLookupData = funcCtxt;
2328}
2329
2330/**
Owen Taylor3473f882001-02-23 17:55:21 +00002331 * xmlXPathFunctionLookup:
2332 * @ctxt: the XPath context
2333 * @name: the function name
2334 *
2335 * Search in the Function array of the context for the given
2336 * function.
2337 *
2338 * Returns the xmlXPathFunction or NULL if not found
2339 */
2340xmlXPathFunction
2341xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002342 if (ctxt == NULL)
2343 return (NULL);
2344
2345 if (ctxt->funcLookupFunc != NULL) {
2346 xmlXPathFunction ret;
2347
2348 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2349 (ctxt->funcLookupData, name, NULL);
2350 if (ret != NULL)
2351 return(ret);
2352 }
Owen Taylor3473f882001-02-23 17:55:21 +00002353 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2354}
2355
2356/**
2357 * xmlXPathFunctionLookupNS:
2358 * @ctxt: the XPath context
2359 * @name: the function name
2360 * @ns_uri: the function namespace URI
2361 *
2362 * Search in the Function array of the context for the given
2363 * function.
2364 *
2365 * Returns the xmlXPathFunction or NULL if not found
2366 */
2367xmlXPathFunction
2368xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2369 const xmlChar *ns_uri) {
2370 if (ctxt == NULL)
2371 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002372 if (name == NULL)
2373 return(NULL);
2374
Thomas Broyerba4ad322001-07-26 16:55:21 +00002375 if (ctxt->funcLookupFunc != NULL) {
2376 xmlXPathFunction ret;
2377
2378 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2379 (ctxt->funcLookupData, name, ns_uri);
2380 if (ret != NULL)
2381 return(ret);
2382 }
2383
2384 if (ctxt->funcHash == NULL)
2385 return(NULL);
2386
Owen Taylor3473f882001-02-23 17:55:21 +00002387 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2388}
2389
2390/**
2391 * xmlXPathRegisteredFuncsCleanup:
2392 * @ctxt: the XPath context
2393 *
2394 * Cleanup the XPath context data associated to registered functions
2395 */
2396void
2397xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2398 if (ctxt == NULL)
2399 return;
2400
2401 xmlHashFree(ctxt->funcHash, NULL);
2402 ctxt->funcHash = NULL;
2403}
2404
2405/************************************************************************
2406 * *
2407 * Routines to handle Variable *
2408 * *
2409 ************************************************************************/
2410
2411/**
2412 * xmlXPathRegisterVariable:
2413 * @ctxt: the XPath context
2414 * @name: the variable name
2415 * @value: the variable value or NULL
2416 *
2417 * Register a new variable value. If @value is NULL it unregisters
2418 * the variable
2419 *
2420 * Returns 0 in case of success, -1 in case of error
2421 */
2422int
2423xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2424 xmlXPathObjectPtr value) {
2425 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2426}
2427
2428/**
2429 * xmlXPathRegisterVariableNS:
2430 * @ctxt: the XPath context
2431 * @name: the variable name
2432 * @ns_uri: the variable namespace URI
2433 * @value: the variable value or NULL
2434 *
2435 * Register a new variable value. If @value is NULL it unregisters
2436 * the variable
2437 *
2438 * Returns 0 in case of success, -1 in case of error
2439 */
2440int
2441xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2442 const xmlChar *ns_uri,
2443 xmlXPathObjectPtr value) {
2444 if (ctxt == NULL)
2445 return(-1);
2446 if (name == NULL)
2447 return(-1);
2448
2449 if (ctxt->varHash == NULL)
2450 ctxt->varHash = xmlHashCreate(0);
2451 if (ctxt->varHash == NULL)
2452 return(-1);
2453 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2454 (void *) value,
2455 (xmlHashDeallocator)xmlXPathFreeObject));
2456}
2457
2458/**
2459 * xmlXPathRegisterVariableLookup:
2460 * @ctxt: the XPath context
2461 * @f: the lookup function
2462 * @data: the lookup data
2463 *
2464 * register an external mechanism to do variable lookup
2465 */
2466void
2467xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2468 xmlXPathVariableLookupFunc f, void *data) {
2469 if (ctxt == NULL)
2470 return;
2471 ctxt->varLookupFunc = (void *) f;
2472 ctxt->varLookupData = data;
2473}
2474
2475/**
2476 * xmlXPathVariableLookup:
2477 * @ctxt: the XPath context
2478 * @name: the variable name
2479 *
2480 * Search in the Variable array of the context for the given
2481 * variable value.
2482 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002483 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002484 */
2485xmlXPathObjectPtr
2486xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2487 if (ctxt == NULL)
2488 return(NULL);
2489
2490 if (ctxt->varLookupFunc != NULL) {
2491 xmlXPathObjectPtr ret;
2492
2493 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2494 (ctxt->varLookupData, name, NULL);
2495 if (ret != NULL) return(ret);
2496 }
2497 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2498}
2499
2500/**
2501 * xmlXPathVariableLookupNS:
2502 * @ctxt: the XPath context
2503 * @name: the variable name
2504 * @ns_uri: the variable namespace URI
2505 *
2506 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002507 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002508 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002509 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002510 */
2511xmlXPathObjectPtr
2512xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2513 const xmlChar *ns_uri) {
2514 if (ctxt == NULL)
2515 return(NULL);
2516
2517 if (ctxt->varLookupFunc != NULL) {
2518 xmlXPathObjectPtr ret;
2519
2520 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2521 (ctxt->varLookupData, name, ns_uri);
2522 if (ret != NULL) return(ret);
2523 }
2524
2525 if (ctxt->varHash == NULL)
2526 return(NULL);
2527 if (name == NULL)
2528 return(NULL);
2529
Daniel Veillard8c357d52001-07-03 23:43:33 +00002530 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2531 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002532}
2533
2534/**
2535 * xmlXPathRegisteredVariablesCleanup:
2536 * @ctxt: the XPath context
2537 *
2538 * Cleanup the XPath context data associated to registered variables
2539 */
2540void
2541xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2542 if (ctxt == NULL)
2543 return;
2544
Daniel Veillard76d66f42001-05-16 21:05:17 +00002545 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002546 ctxt->varHash = NULL;
2547}
2548
2549/**
2550 * xmlXPathRegisterNs:
2551 * @ctxt: the XPath context
2552 * @prefix: the namespace prefix
2553 * @ns_uri: the namespace name
2554 *
2555 * Register a new namespace. If @ns_uri is NULL it unregisters
2556 * the namespace
2557 *
2558 * Returns 0 in case of success, -1 in case of error
2559 */
2560int
2561xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2562 const xmlChar *ns_uri) {
2563 if (ctxt == NULL)
2564 return(-1);
2565 if (prefix == NULL)
2566 return(-1);
2567
2568 if (ctxt->nsHash == NULL)
2569 ctxt->nsHash = xmlHashCreate(10);
2570 if (ctxt->nsHash == NULL)
2571 return(-1);
2572 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2573 (xmlHashDeallocator)xmlFree));
2574}
2575
2576/**
2577 * xmlXPathNsLookup:
2578 * @ctxt: the XPath context
2579 * @prefix: the namespace prefix value
2580 *
2581 * Search in the namespace declaration array of the context for the given
2582 * namespace name associated to the given prefix
2583 *
2584 * Returns the value or NULL if not found
2585 */
2586const xmlChar *
2587xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2588 if (ctxt == NULL)
2589 return(NULL);
2590 if (prefix == NULL)
2591 return(NULL);
2592
2593#ifdef XML_XML_NAMESPACE
2594 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2595 return(XML_XML_NAMESPACE);
2596#endif
2597
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002598 if (ctxt->namespaces != NULL) {
2599 int i;
2600
2601 for (i = 0;i < ctxt->nsNr;i++) {
2602 if ((ctxt->namespaces[i] != NULL) &&
2603 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2604 return(ctxt->namespaces[i]->href);
2605 }
2606 }
Owen Taylor3473f882001-02-23 17:55:21 +00002607
2608 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2609}
2610
2611/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002612 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002613 * @ctxt: the XPath context
2614 *
2615 * Cleanup the XPath context data associated to registered variables
2616 */
2617void
2618xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2619 if (ctxt == NULL)
2620 return;
2621
2622 xmlHashFree(ctxt->nsHash, NULL);
2623 ctxt->nsHash = NULL;
2624}
2625
2626/************************************************************************
2627 * *
2628 * Routines to handle Values *
2629 * *
2630 ************************************************************************/
2631
2632/* Allocations are terrible, one need to optimize all this !!! */
2633
2634/**
2635 * xmlXPathNewFloat:
2636 * @val: the double value
2637 *
2638 * Create a new xmlXPathObjectPtr of type double and of value @val
2639 *
2640 * Returns the newly created object.
2641 */
2642xmlXPathObjectPtr
2643xmlXPathNewFloat(double val) {
2644 xmlXPathObjectPtr ret;
2645
2646 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2647 if (ret == NULL) {
2648 xmlGenericError(xmlGenericErrorContext,
2649 "xmlXPathNewFloat: out of memory\n");
2650 return(NULL);
2651 }
2652 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2653 ret->type = XPATH_NUMBER;
2654 ret->floatval = val;
2655 return(ret);
2656}
2657
2658/**
2659 * xmlXPathNewBoolean:
2660 * @val: the boolean value
2661 *
2662 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2663 *
2664 * Returns the newly created object.
2665 */
2666xmlXPathObjectPtr
2667xmlXPathNewBoolean(int val) {
2668 xmlXPathObjectPtr ret;
2669
2670 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2671 if (ret == NULL) {
2672 xmlGenericError(xmlGenericErrorContext,
2673 "xmlXPathNewBoolean: out of memory\n");
2674 return(NULL);
2675 }
2676 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2677 ret->type = XPATH_BOOLEAN;
2678 ret->boolval = (val != 0);
2679 return(ret);
2680}
2681
2682/**
2683 * xmlXPathNewString:
2684 * @val: the xmlChar * value
2685 *
2686 * Create a new xmlXPathObjectPtr of type string and of value @val
2687 *
2688 * Returns the newly created object.
2689 */
2690xmlXPathObjectPtr
2691xmlXPathNewString(const xmlChar *val) {
2692 xmlXPathObjectPtr ret;
2693
2694 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2695 if (ret == NULL) {
2696 xmlGenericError(xmlGenericErrorContext,
2697 "xmlXPathNewString: out of memory\n");
2698 return(NULL);
2699 }
2700 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2701 ret->type = XPATH_STRING;
2702 if (val != NULL)
2703 ret->stringval = xmlStrdup(val);
2704 else
2705 ret->stringval = xmlStrdup((const xmlChar *)"");
2706 return(ret);
2707}
2708
2709/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002710 * xmlXPathWrapString:
2711 * @val: the xmlChar * value
2712 *
2713 * Wraps the @val string into an XPath object.
2714 *
2715 * Returns the newly created object.
2716 */
2717xmlXPathObjectPtr
2718xmlXPathWrapString (xmlChar *val) {
2719 xmlXPathObjectPtr ret;
2720
2721 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2722 if (ret == NULL) {
2723 xmlGenericError(xmlGenericErrorContext,
2724 "xmlXPathWrapString: out of memory\n");
2725 return(NULL);
2726 }
2727 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2728 ret->type = XPATH_STRING;
2729 ret->stringval = val;
2730 return(ret);
2731}
2732
2733/**
Owen Taylor3473f882001-02-23 17:55:21 +00002734 * xmlXPathNewCString:
2735 * @val: the char * value
2736 *
2737 * Create a new xmlXPathObjectPtr of type string and of value @val
2738 *
2739 * Returns the newly created object.
2740 */
2741xmlXPathObjectPtr
2742xmlXPathNewCString(const char *val) {
2743 xmlXPathObjectPtr ret;
2744
2745 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2746 if (ret == NULL) {
2747 xmlGenericError(xmlGenericErrorContext,
2748 "xmlXPathNewCString: out of memory\n");
2749 return(NULL);
2750 }
2751 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2752 ret->type = XPATH_STRING;
2753 ret->stringval = xmlStrdup(BAD_CAST val);
2754 return(ret);
2755}
2756
2757/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002758 * xmlXPathWrapCString:
2759 * @val: the char * value
2760 *
2761 * Wraps a string into an XPath object.
2762 *
2763 * Returns the newly created object.
2764 */
2765xmlXPathObjectPtr
2766xmlXPathWrapCString (char * val) {
2767 return(xmlXPathWrapString((xmlChar *)(val)));
2768}
2769
2770/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002771 * xmlXPathWrapExternal:
2772 * @val: the user data
2773 *
2774 * Wraps the @val data into an XPath object.
2775 *
2776 * Returns the newly created object.
2777 */
2778xmlXPathObjectPtr
2779xmlXPathWrapExternal (void *val) {
2780 xmlXPathObjectPtr ret;
2781
2782 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2783 if (ret == NULL) {
2784 xmlGenericError(xmlGenericErrorContext,
2785 "xmlXPathWrapString: out of memory\n");
2786 return(NULL);
2787 }
2788 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2789 ret->type = XPATH_USERS;
2790 ret->user = val;
2791 return(ret);
2792}
2793
2794/**
Owen Taylor3473f882001-02-23 17:55:21 +00002795 * xmlXPathObjectCopy:
2796 * @val: the original object
2797 *
2798 * allocate a new copy of a given object
2799 *
2800 * Returns the newly created object.
2801 */
2802xmlXPathObjectPtr
2803xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2804 xmlXPathObjectPtr ret;
2805
2806 if (val == NULL)
2807 return(NULL);
2808
2809 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2810 if (ret == NULL) {
2811 xmlGenericError(xmlGenericErrorContext,
2812 "xmlXPathObjectCopy: out of memory\n");
2813 return(NULL);
2814 }
2815 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2816 switch (val->type) {
2817 case XPATH_BOOLEAN:
2818 case XPATH_NUMBER:
2819 case XPATH_POINT:
2820 case XPATH_RANGE:
2821 break;
2822 case XPATH_STRING:
2823 ret->stringval = xmlStrdup(val->stringval);
2824 break;
2825 case XPATH_XSLT_TREE:
2826 if ((val->nodesetval != NULL) &&
2827 (val->nodesetval->nodeTab != NULL))
2828 ret->nodesetval = xmlXPathNodeSetCreate(
2829 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2830 else
2831 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2832 break;
2833 case XPATH_NODESET:
2834 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2835 break;
2836 case XPATH_LOCATIONSET:
2837#ifdef LIBXML_XPTR_ENABLED
2838 {
2839 xmlLocationSetPtr loc = val->user;
2840 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2841 break;
2842 }
2843#endif
2844 case XPATH_UNDEFINED:
2845 case XPATH_USERS:
2846 xmlGenericError(xmlGenericErrorContext,
2847 "xmlXPathObjectCopy: unsupported type %d\n",
2848 val->type);
2849 break;
2850 }
2851 return(ret);
2852}
2853
2854/**
2855 * xmlXPathFreeObject:
2856 * @obj: the object to free
2857 *
2858 * Free up an xmlXPathObjectPtr object.
2859 */
2860void
2861xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2862 if (obj == NULL) return;
2863 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002864 if (obj->boolval) {
2865 obj->type = XPATH_XSLT_TREE;
2866 if (obj->nodesetval != NULL)
2867 xmlXPathFreeValueTree(obj->nodesetval);
2868 } else {
2869 if (obj->nodesetval != NULL)
2870 xmlXPathFreeNodeSet(obj->nodesetval);
2871 }
Owen Taylor3473f882001-02-23 17:55:21 +00002872#ifdef LIBXML_XPTR_ENABLED
2873 } else if (obj->type == XPATH_LOCATIONSET) {
2874 if (obj->user != NULL)
2875 xmlXPtrFreeLocationSet(obj->user);
2876#endif
2877 } else if (obj->type == XPATH_STRING) {
2878 if (obj->stringval != NULL)
2879 xmlFree(obj->stringval);
2880 } else if (obj->type == XPATH_XSLT_TREE) {
2881 if (obj->nodesetval != NULL)
2882 xmlXPathFreeValueTree(obj->nodesetval);
2883 }
2884
Owen Taylor3473f882001-02-23 17:55:21 +00002885 xmlFree(obj);
2886}
2887
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002888
2889/************************************************************************
2890 * *
2891 * Type Casting Routines *
2892 * *
2893 ************************************************************************/
2894
2895/**
2896 * xmlXPathCastBooleanToString:
2897 * @val: a boolean
2898 *
2899 * Converts a boolean to its string value.
2900 *
2901 * Returns a newly allocated string.
2902 */
2903xmlChar *
2904xmlXPathCastBooleanToString (int val) {
2905 xmlChar *ret;
2906 if (val)
2907 ret = xmlStrdup((const xmlChar *) "true");
2908 else
2909 ret = xmlStrdup((const xmlChar *) "false");
2910 return(ret);
2911}
2912
2913/**
2914 * xmlXPathCastNumberToString:
2915 * @val: a number
2916 *
2917 * Converts a number to its string value.
2918 *
2919 * Returns a newly allocated string.
2920 */
2921xmlChar *
2922xmlXPathCastNumberToString (double val) {
2923 xmlChar *ret;
2924 switch (isinf(val)) {
2925 case 1:
2926 ret = xmlStrdup((const xmlChar *) "+Infinity");
2927 break;
2928 case -1:
2929 ret = xmlStrdup((const xmlChar *) "-Infinity");
2930 break;
2931 default:
2932 if (isnan(val)) {
2933 ret = xmlStrdup((const xmlChar *) "NaN");
2934 } else {
2935 /* could be improved */
2936 char buf[100];
2937 xmlXPathFormatNumber(val, buf, 100);
2938 ret = xmlStrdup((const xmlChar *) buf);
2939 }
2940 }
2941 return(ret);
2942}
2943
2944/**
2945 * xmlXPathCastNodeToString:
2946 * @node: a node
2947 *
2948 * Converts a node to its string value.
2949 *
2950 * Returns a newly allocated string.
2951 */
2952xmlChar *
2953xmlXPathCastNodeToString (xmlNodePtr node) {
2954 return(xmlNodeGetContent(node));
2955}
2956
2957/**
2958 * xmlXPathCastNodeSetToString:
2959 * @ns: a node-set
2960 *
2961 * Converts a node-set to its string value.
2962 *
2963 * Returns a newly allocated string.
2964 */
2965xmlChar *
2966xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2967 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2968 return(xmlStrdup((const xmlChar *) ""));
2969
2970 xmlXPathNodeSetSort(ns);
2971 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2972}
2973
2974/**
2975 * xmlXPathCastToString:
2976 * @val: an XPath object
2977 *
2978 * Converts an existing object to its string() equivalent
2979 *
2980 * Returns the string value of the object, NULL in case of error.
2981 * A new string is allocated only if needed (val isn't a
2982 * string object).
2983 */
2984xmlChar *
2985xmlXPathCastToString(xmlXPathObjectPtr val) {
2986 xmlChar *ret = NULL;
2987
2988 if (val == NULL)
2989 return(xmlStrdup((const xmlChar *) ""));
2990 switch (val->type) {
2991 case XPATH_UNDEFINED:
2992#ifdef DEBUG_EXPR
2993 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2994#endif
2995 ret = xmlStrdup((const xmlChar *) "");
2996 break;
2997 case XPATH_XSLT_TREE:
2998 case XPATH_NODESET:
2999 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3000 break;
3001 case XPATH_STRING:
3002 return(val->stringval);
3003 case XPATH_BOOLEAN:
3004 ret = xmlXPathCastBooleanToString(val->boolval);
3005 break;
3006 case XPATH_NUMBER: {
3007 ret = xmlXPathCastNumberToString(val->floatval);
3008 break;
3009 }
3010 case XPATH_USERS:
3011 case XPATH_POINT:
3012 case XPATH_RANGE:
3013 case XPATH_LOCATIONSET:
3014 TODO
3015 ret = xmlStrdup((const xmlChar *) "");
3016 break;
3017 }
3018 return(ret);
3019}
3020
3021/**
3022 * xmlXPathConvertString:
3023 * @val: an XPath object
3024 *
3025 * Converts an existing object to its string() equivalent
3026 *
3027 * Returns the new object, the old one is freed (or the operation
3028 * is done directly on @val)
3029 */
3030xmlXPathObjectPtr
3031xmlXPathConvertString(xmlXPathObjectPtr val) {
3032 xmlChar *res = NULL;
3033
3034 if (val == NULL)
3035 return(xmlXPathNewCString(""));
3036
3037 switch (val->type) {
3038 case XPATH_UNDEFINED:
3039#ifdef DEBUG_EXPR
3040 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3041#endif
3042 break;
3043 case XPATH_XSLT_TREE:
3044 case XPATH_NODESET:
3045 res = xmlXPathCastNodeSetToString(val->nodesetval);
3046 break;
3047 case XPATH_STRING:
3048 return(val);
3049 case XPATH_BOOLEAN:
3050 res = xmlXPathCastBooleanToString(val->boolval);
3051 break;
3052 case XPATH_NUMBER:
3053 res = xmlXPathCastNumberToString(val->floatval);
3054 break;
3055 case XPATH_USERS:
3056 case XPATH_POINT:
3057 case XPATH_RANGE:
3058 case XPATH_LOCATIONSET:
3059 TODO;
3060 break;
3061 }
3062 xmlXPathFreeObject(val);
3063 if (res == NULL)
3064 return(xmlXPathNewCString(""));
3065 return(xmlXPathWrapString(res));
3066}
3067
3068/**
3069 * xmlXPathCastBooleanToNumber:
3070 * @val: a boolean
3071 *
3072 * Converts a boolean to its number value
3073 *
3074 * Returns the number value
3075 */
3076double
3077xmlXPathCastBooleanToNumber(int val) {
3078 if (val)
3079 return(1.0);
3080 return(0.0);
3081}
3082
3083/**
3084 * xmlXPathCastStringToNumber:
3085 * @val: a string
3086 *
3087 * Converts a string to its number value
3088 *
3089 * Returns the number value
3090 */
3091double
3092xmlXPathCastStringToNumber(const xmlChar * val) {
3093 return(xmlXPathStringEvalNumber(val));
3094}
3095
3096/**
3097 * xmlXPathCastNodeToNumber:
3098 * @node: a node
3099 *
3100 * Converts a node to its number value
3101 *
3102 * Returns the number value
3103 */
3104double
3105xmlXPathCastNodeToNumber (xmlNodePtr node) {
3106 xmlChar *strval;
3107 double ret;
3108
3109 if (node == NULL)
3110 return(xmlXPathNAN);
3111 strval = xmlXPathCastNodeToString(node);
3112 if (strval == NULL)
3113 return(xmlXPathNAN);
3114 ret = xmlXPathCastStringToNumber(strval);
3115 xmlFree(strval);
3116
3117 return(ret);
3118}
3119
3120/**
3121 * xmlXPathCastNodeSetToNumber:
3122 * @ns: a node-set
3123 *
3124 * Converts a node-set to its number value
3125 *
3126 * Returns the number value
3127 */
3128double
3129xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3130 xmlChar *str;
3131 double ret;
3132
3133 if (ns == NULL)
3134 return(xmlXPathNAN);
3135 str = xmlXPathCastNodeSetToString(ns);
3136 ret = xmlXPathCastStringToNumber(str);
3137 xmlFree(str);
3138 return(ret);
3139}
3140
3141/**
3142 * xmlXPathCastToNumber:
3143 * @val: an XPath object
3144 *
3145 * Converts an XPath object to its number value
3146 *
3147 * Returns the number value
3148 */
3149double
3150xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3151 double ret = 0.0;
3152
3153 if (val == NULL)
3154 return(xmlXPathNAN);
3155 switch (val->type) {
3156 case XPATH_UNDEFINED:
3157#ifdef DEGUB_EXPR
3158 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3159#endif
3160 ret = xmlXPathNAN;
3161 break;
3162 case XPATH_XSLT_TREE:
3163 case XPATH_NODESET:
3164 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3165 break;
3166 case XPATH_STRING:
3167 ret = xmlXPathCastStringToNumber(val->stringval);
3168 break;
3169 case XPATH_NUMBER:
3170 ret = val->floatval;
3171 break;
3172 case XPATH_BOOLEAN:
3173 ret = xmlXPathCastBooleanToNumber(val->boolval);
3174 break;
3175 case XPATH_USERS:
3176 case XPATH_POINT:
3177 case XPATH_RANGE:
3178 case XPATH_LOCATIONSET:
3179 TODO;
3180 ret = xmlXPathNAN;
3181 break;
3182 }
3183 return(ret);
3184}
3185
3186/**
3187 * xmlXPathConvertNumber:
3188 * @val: an XPath object
3189 *
3190 * Converts an existing object to its number() equivalent
3191 *
3192 * Returns the new object, the old one is freed (or the operation
3193 * is done directly on @val)
3194 */
3195xmlXPathObjectPtr
3196xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3197 xmlXPathObjectPtr ret;
3198
3199 if (val == NULL)
3200 return(xmlXPathNewFloat(0.0));
3201 if (val->type == XPATH_NUMBER)
3202 return(val);
3203 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3204 xmlXPathFreeObject(val);
3205 return(ret);
3206}
3207
3208/**
3209 * xmlXPathCastNumberToBoolean:
3210 * @val: a number
3211 *
3212 * Converts a number to its boolean value
3213 *
3214 * Returns the boolean value
3215 */
3216int
3217xmlXPathCastNumberToBoolean (double val) {
3218 if (isnan(val) || (val == 0.0))
3219 return(0);
3220 return(1);
3221}
3222
3223/**
3224 * xmlXPathCastStringToBoolean:
3225 * @val: a string
3226 *
3227 * Converts a string to its boolean value
3228 *
3229 * Returns the boolean value
3230 */
3231int
3232xmlXPathCastStringToBoolean (const xmlChar *val) {
3233 if ((val == NULL) || (xmlStrlen(val) == 0))
3234 return(0);
3235 return(1);
3236}
3237
3238/**
3239 * xmlXPathCastNodeSetToBoolean:
3240 * @ns: a node-set
3241 *
3242 * Converts a node-set to its boolean value
3243 *
3244 * Returns the boolean value
3245 */
3246int
3247xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3248 if ((ns == NULL) || (ns->nodeNr == 0))
3249 return(0);
3250 return(1);
3251}
3252
3253/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003254 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003255 * @val: an XPath object
3256 *
3257 * Converts an XPath object to its boolean value
3258 *
3259 * Returns the boolean value
3260 */
3261int
3262xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3263 int ret = 0;
3264
3265 if (val == NULL)
3266 return(0);
3267 switch (val->type) {
3268 case XPATH_UNDEFINED:
3269#ifdef DEBUG_EXPR
3270 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3271#endif
3272 ret = 0;
3273 break;
3274 case XPATH_XSLT_TREE:
3275 case XPATH_NODESET:
3276 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3277 break;
3278 case XPATH_STRING:
3279 ret = xmlXPathCastStringToBoolean(val->stringval);
3280 break;
3281 case XPATH_NUMBER:
3282 ret = xmlXPathCastNumberToBoolean(val->floatval);
3283 break;
3284 case XPATH_BOOLEAN:
3285 ret = val->boolval;
3286 break;
3287 case XPATH_USERS:
3288 case XPATH_POINT:
3289 case XPATH_RANGE:
3290 case XPATH_LOCATIONSET:
3291 TODO;
3292 ret = 0;
3293 break;
3294 }
3295 return(ret);
3296}
3297
3298
3299/**
3300 * xmlXPathConvertBoolean:
3301 * @val: an XPath object
3302 *
3303 * Converts an existing object to its boolean() equivalent
3304 *
3305 * Returns the new object, the old one is freed (or the operation
3306 * is done directly on @val)
3307 */
3308xmlXPathObjectPtr
3309xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3310 xmlXPathObjectPtr ret;
3311
3312 if (val == NULL)
3313 return(xmlXPathNewBoolean(0));
3314 if (val->type == XPATH_BOOLEAN)
3315 return(val);
3316 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3317 xmlXPathFreeObject(val);
3318 return(ret);
3319}
3320
Owen Taylor3473f882001-02-23 17:55:21 +00003321/************************************************************************
3322 * *
3323 * Routines to handle XPath contexts *
3324 * *
3325 ************************************************************************/
3326
3327/**
3328 * xmlXPathNewContext:
3329 * @doc: the XML document
3330 *
3331 * Create a new xmlXPathContext
3332 *
3333 * Returns the xmlXPathContext just allocated.
3334 */
3335xmlXPathContextPtr
3336xmlXPathNewContext(xmlDocPtr doc) {
3337 xmlXPathContextPtr ret;
3338
3339 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3340 if (ret == NULL) {
3341 xmlGenericError(xmlGenericErrorContext,
3342 "xmlXPathNewContext: out of memory\n");
3343 return(NULL);
3344 }
3345 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3346 ret->doc = doc;
3347 ret->node = NULL;
3348
3349 ret->varHash = NULL;
3350
3351 ret->nb_types = 0;
3352 ret->max_types = 0;
3353 ret->types = NULL;
3354
3355 ret->funcHash = xmlHashCreate(0);
3356
3357 ret->nb_axis = 0;
3358 ret->max_axis = 0;
3359 ret->axis = NULL;
3360
3361 ret->nsHash = NULL;
3362 ret->user = NULL;
3363
3364 ret->contextSize = -1;
3365 ret->proximityPosition = -1;
3366
3367 xmlXPathRegisterAllFunctions(ret);
3368
3369 return(ret);
3370}
3371
3372/**
3373 * xmlXPathFreeContext:
3374 * @ctxt: the context to free
3375 *
3376 * Free up an xmlXPathContext
3377 */
3378void
3379xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3380 xmlXPathRegisteredNsCleanup(ctxt);
3381 xmlXPathRegisteredFuncsCleanup(ctxt);
3382 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003383 xmlFree(ctxt);
3384}
3385
3386/************************************************************************
3387 * *
3388 * Routines to handle XPath parser contexts *
3389 * *
3390 ************************************************************************/
3391
3392#define CHECK_CTXT(ctxt) \
3393 if (ctxt == NULL) { \
3394 xmlGenericError(xmlGenericErrorContext, \
3395 "%s:%d Internal error: ctxt == NULL\n", \
3396 __FILE__, __LINE__); \
3397 } \
3398
3399
3400#define CHECK_CONTEXT(ctxt) \
3401 if (ctxt == NULL) { \
3402 xmlGenericError(xmlGenericErrorContext, \
3403 "%s:%d Internal error: no context\n", \
3404 __FILE__, __LINE__); \
3405 } \
3406 else if (ctxt->doc == NULL) { \
3407 xmlGenericError(xmlGenericErrorContext, \
3408 "%s:%d Internal error: no document\n", \
3409 __FILE__, __LINE__); \
3410 } \
3411 else if (ctxt->doc->children == NULL) { \
3412 xmlGenericError(xmlGenericErrorContext, \
3413 "%s:%d Internal error: document without root\n", \
3414 __FILE__, __LINE__); \
3415 } \
3416
3417
3418/**
3419 * xmlXPathNewParserContext:
3420 * @str: the XPath expression
3421 * @ctxt: the XPath context
3422 *
3423 * Create a new xmlXPathParserContext
3424 *
3425 * Returns the xmlXPathParserContext just allocated.
3426 */
3427xmlXPathParserContextPtr
3428xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3429 xmlXPathParserContextPtr ret;
3430
3431 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3432 if (ret == NULL) {
3433 xmlGenericError(xmlGenericErrorContext,
3434 "xmlXPathNewParserContext: out of memory\n");
3435 return(NULL);
3436 }
3437 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3438 ret->cur = ret->base = str;
3439 ret->context = ctxt;
3440
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003441 ret->comp = xmlXPathNewCompExpr();
3442 if (ret->comp == NULL) {
3443 xmlFree(ret->valueTab);
3444 xmlFree(ret);
3445 return(NULL);
3446 }
3447
3448 return(ret);
3449}
3450
3451/**
3452 * xmlXPathCompParserContext:
3453 * @comp: the XPath compiled expression
3454 * @ctxt: the XPath context
3455 *
3456 * Create a new xmlXPathParserContext when processing a compiled expression
3457 *
3458 * Returns the xmlXPathParserContext just allocated.
3459 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003460static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003461xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3462 xmlXPathParserContextPtr ret;
3463
3464 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3465 if (ret == NULL) {
3466 xmlGenericError(xmlGenericErrorContext,
3467 "xmlXPathNewParserContext: out of memory\n");
3468 return(NULL);
3469 }
3470 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3471
Owen Taylor3473f882001-02-23 17:55:21 +00003472 /* Allocate the value stack */
3473 ret->valueTab = (xmlXPathObjectPtr *)
3474 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003475 if (ret->valueTab == NULL) {
3476 xmlFree(ret);
3477 xmlGenericError(xmlGenericErrorContext,
3478 "xmlXPathNewParserContext: out of memory\n");
3479 return(NULL);
3480 }
Owen Taylor3473f882001-02-23 17:55:21 +00003481 ret->valueNr = 0;
3482 ret->valueMax = 10;
3483 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003484
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003485 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003486 ret->comp = comp;
3487
Owen Taylor3473f882001-02-23 17:55:21 +00003488 return(ret);
3489}
3490
3491/**
3492 * xmlXPathFreeParserContext:
3493 * @ctxt: the context to free
3494 *
3495 * Free up an xmlXPathParserContext
3496 */
3497void
3498xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3499 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003500 xmlFree(ctxt->valueTab);
3501 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003502 if (ctxt->comp)
3503 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003504 xmlFree(ctxt);
3505}
3506
3507/************************************************************************
3508 * *
3509 * The implicit core function library *
3510 * *
3511 ************************************************************************/
3512
Owen Taylor3473f882001-02-23 17:55:21 +00003513/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003514 * xmlXPathNodeStringHash:
3515 * @node: a node pointer
3516 *
3517 * Function computing the beginning of the string value of the node,
3518 * used to speed up comparisons
3519 *
3520 * Returns an int usable as a hash
3521 */
3522static unsigned int
3523xmlXPathNodeValHash(xmlNodePtr node) {
3524 int len = 2;
3525 const xmlChar * string = NULL;
3526 xmlNodePtr tmp = NULL;
3527 unsigned int ret = 0;
3528
3529 if (node == NULL)
3530 return(0);
3531
3532
3533 switch (node->type) {
3534 case XML_COMMENT_NODE:
3535 case XML_PI_NODE:
3536 case XML_CDATA_SECTION_NODE:
3537 case XML_TEXT_NODE:
3538 string = node->content;
3539 if (string == NULL)
3540 return(0);
3541 if (string[0] == 0)
3542 return(0);
3543 return(((unsigned int) string[0]) +
3544 (((unsigned int) string[1]) << 8));
3545 case XML_NAMESPACE_DECL:
3546 string = ((xmlNsPtr)node)->href;
3547 if (string == NULL)
3548 return(0);
3549 if (string[0] == 0)
3550 return(0);
3551 return(((unsigned int) string[0]) +
3552 (((unsigned int) string[1]) << 8));
3553 case XML_ATTRIBUTE_NODE:
3554 tmp = ((xmlAttrPtr) node)->children;
3555 break;
3556 case XML_ELEMENT_NODE:
3557 tmp = node->children;
3558 break;
3559 default:
3560 return(0);
3561 }
3562 while (tmp != NULL) {
3563 switch (tmp->type) {
3564 case XML_COMMENT_NODE:
3565 case XML_PI_NODE:
3566 case XML_CDATA_SECTION_NODE:
3567 case XML_TEXT_NODE:
3568 string = tmp->content;
3569 break;
3570 case XML_NAMESPACE_DECL:
3571 string = ((xmlNsPtr)tmp)->href;
3572 break;
3573 default:
3574 break;
3575 }
3576 if ((string != NULL) && (string[0] != 0)) {
3577 if (string[0] == 0)
3578 return(0);
3579 if (len == 1) {
3580 return(ret + (((unsigned int) string[0]) << 8));
3581 }
3582 if (string[1] == 0) {
3583 len = 1;
3584 ret = (unsigned int) string[0];
3585 } else {
3586 return(((unsigned int) string[0]) +
3587 (((unsigned int) string[1]) << 8));
3588 }
3589 }
3590 /*
3591 * Skip to next node
3592 */
3593 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3594 if (tmp->children->type != XML_ENTITY_DECL) {
3595 tmp = tmp->children;
3596 continue;
3597 }
3598 }
3599 if (tmp == node)
3600 break;
3601
3602 if (tmp->next != NULL) {
3603 tmp = tmp->next;
3604 continue;
3605 }
3606
3607 do {
3608 tmp = tmp->parent;
3609 if (tmp == NULL)
3610 break;
3611 if (tmp == node) {
3612 tmp = NULL;
3613 break;
3614 }
3615 if (tmp->next != NULL) {
3616 tmp = tmp->next;
3617 break;
3618 }
3619 } while (tmp != NULL);
3620 }
3621 return(ret);
3622}
3623
3624/**
3625 * xmlXPathStringHash:
3626 * @string: a string
3627 *
3628 * Function computing the beginning of the string value of the node,
3629 * used to speed up comparisons
3630 *
3631 * Returns an int usable as a hash
3632 */
3633static unsigned int
3634xmlXPathStringHash(const xmlChar * string) {
3635 if (string == NULL)
3636 return((unsigned int) 0);
3637 if (string[0] == 0)
3638 return(0);
3639 return(((unsigned int) string[0]) +
3640 (((unsigned int) string[1]) << 8));
3641}
3642
3643/**
Owen Taylor3473f882001-02-23 17:55:21 +00003644 * xmlXPathCompareNodeSetFloat:
3645 * @ctxt: the XPath Parser context
3646 * @inf: less than (1) or greater than (0)
3647 * @strict: is the comparison strict
3648 * @arg: the node set
3649 * @f: the value
3650 *
3651 * Implement the compare operation between a nodeset and a number
3652 * @ns < @val (1, 1, ...
3653 * @ns <= @val (1, 0, ...
3654 * @ns > @val (0, 1, ...
3655 * @ns >= @val (0, 0, ...
3656 *
3657 * If one object to be compared is a node-set and the other is a number,
3658 * then the comparison will be true if and only if there is a node in the
3659 * node-set such that the result of performing the comparison on the number
3660 * to be compared and on the result of converting the string-value of that
3661 * node to a number using the number function is true.
3662 *
3663 * Returns 0 or 1 depending on the results of the test.
3664 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003665static int
Owen Taylor3473f882001-02-23 17:55:21 +00003666xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3667 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3668 int i, ret = 0;
3669 xmlNodeSetPtr ns;
3670 xmlChar *str2;
3671
3672 if ((f == NULL) || (arg == NULL) ||
3673 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3674 xmlXPathFreeObject(arg);
3675 xmlXPathFreeObject(f);
3676 return(0);
3677 }
3678 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003679 if (ns != NULL) {
3680 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003681 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003682 if (str2 != NULL) {
3683 valuePush(ctxt,
3684 xmlXPathNewString(str2));
3685 xmlFree(str2);
3686 xmlXPathNumberFunction(ctxt, 1);
3687 valuePush(ctxt, xmlXPathObjectCopy(f));
3688 ret = xmlXPathCompareValues(ctxt, inf, strict);
3689 if (ret)
3690 break;
3691 }
3692 }
Owen Taylor3473f882001-02-23 17:55:21 +00003693 }
3694 xmlXPathFreeObject(arg);
3695 xmlXPathFreeObject(f);
3696 return(ret);
3697}
3698
3699/**
3700 * xmlXPathCompareNodeSetString:
3701 * @ctxt: the XPath Parser context
3702 * @inf: less than (1) or greater than (0)
3703 * @strict: is the comparison strict
3704 * @arg: the node set
3705 * @s: the value
3706 *
3707 * Implement the compare operation between a nodeset and a string
3708 * @ns < @val (1, 1, ...
3709 * @ns <= @val (1, 0, ...
3710 * @ns > @val (0, 1, ...
3711 * @ns >= @val (0, 0, ...
3712 *
3713 * If one object to be compared is a node-set and the other is a string,
3714 * then the comparison will be true if and only if there is a node in
3715 * the node-set such that the result of performing the comparison on the
3716 * string-value of the node and the other string is true.
3717 *
3718 * Returns 0 or 1 depending on the results of the test.
3719 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003720static int
Owen Taylor3473f882001-02-23 17:55:21 +00003721xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3722 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3723 int i, ret = 0;
3724 xmlNodeSetPtr ns;
3725 xmlChar *str2;
3726
3727 if ((s == NULL) || (arg == NULL) ||
3728 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3729 xmlXPathFreeObject(arg);
3730 xmlXPathFreeObject(s);
3731 return(0);
3732 }
3733 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003734 if (ns != NULL) {
3735 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003736 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003737 if (str2 != NULL) {
3738 valuePush(ctxt,
3739 xmlXPathNewString(str2));
3740 xmlFree(str2);
3741 valuePush(ctxt, xmlXPathObjectCopy(s));
3742 ret = xmlXPathCompareValues(ctxt, inf, strict);
3743 if (ret)
3744 break;
3745 }
3746 }
Owen Taylor3473f882001-02-23 17:55:21 +00003747 }
3748 xmlXPathFreeObject(arg);
3749 xmlXPathFreeObject(s);
3750 return(ret);
3751}
3752
3753/**
3754 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003755 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003756 * @strict: is the comparison strict
3757 * @arg1: the fist node set object
3758 * @arg2: the second node set object
3759 *
3760 * Implement the compare operation on nodesets:
3761 *
3762 * If both objects to be compared are node-sets, then the comparison
3763 * will be true if and only if there is a node in the first node-set
3764 * and a node in the second node-set such that the result of performing
3765 * the comparison on the string-values of the two nodes is true.
3766 * ....
3767 * When neither object to be compared is a node-set and the operator
3768 * is <=, <, >= or >, then the objects are compared by converting both
3769 * objects to numbers and comparing the numbers according to IEEE 754.
3770 * ....
3771 * The number function converts its argument to a number as follows:
3772 * - a string that consists of optional whitespace followed by an
3773 * optional minus sign followed by a Number followed by whitespace
3774 * is converted to the IEEE 754 number that is nearest (according
3775 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3776 * represented by the string; any other string is converted to NaN
3777 *
3778 * Conclusion all nodes need to be converted first to their string value
3779 * and then the comparison must be done when possible
3780 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003781static int
3782xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003783 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3784 int i, j, init = 0;
3785 double val1;
3786 double *values2;
3787 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003788 xmlNodeSetPtr ns1;
3789 xmlNodeSetPtr ns2;
3790
3791 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003792 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3793 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003794 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003795 }
Owen Taylor3473f882001-02-23 17:55:21 +00003796 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003797 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3798 xmlXPathFreeObject(arg1);
3799 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003800 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003801 }
Owen Taylor3473f882001-02-23 17:55:21 +00003802
3803 ns1 = arg1->nodesetval;
3804 ns2 = arg2->nodesetval;
3805
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003806 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003807 xmlXPathFreeObject(arg1);
3808 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003809 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003810 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003811 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003812 xmlXPathFreeObject(arg1);
3813 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003814 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003815 }
Owen Taylor3473f882001-02-23 17:55:21 +00003816
3817 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3818 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003819 xmlXPathFreeObject(arg1);
3820 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003821 return(0);
3822 }
3823 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003824 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003825 if (isnan(val1))
3826 continue;
3827 for (j = 0;j < ns2->nodeNr;j++) {
3828 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003829 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003830 }
3831 if (isnan(values2[j]))
3832 continue;
3833 if (inf && strict)
3834 ret = (val1 < values2[j]);
3835 else if (inf && !strict)
3836 ret = (val1 <= values2[j]);
3837 else if (!inf && strict)
3838 ret = (val1 > values2[j]);
3839 else if (!inf && !strict)
3840 ret = (val1 >= values2[j]);
3841 if (ret)
3842 break;
3843 }
3844 if (ret)
3845 break;
3846 init = 1;
3847 }
3848 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003849 xmlXPathFreeObject(arg1);
3850 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003851 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003852}
3853
3854/**
3855 * xmlXPathCompareNodeSetValue:
3856 * @ctxt: the XPath Parser context
3857 * @inf: less than (1) or greater than (0)
3858 * @strict: is the comparison strict
3859 * @arg: the node set
3860 * @val: the value
3861 *
3862 * Implement the compare operation between a nodeset and a value
3863 * @ns < @val (1, 1, ...
3864 * @ns <= @val (1, 0, ...
3865 * @ns > @val (0, 1, ...
3866 * @ns >= @val (0, 0, ...
3867 *
3868 * If one object to be compared is a node-set and the other is a boolean,
3869 * then the comparison will be true if and only if the result of performing
3870 * the comparison on the boolean and on the result of converting
3871 * the node-set to a boolean using the boolean function is true.
3872 *
3873 * Returns 0 or 1 depending on the results of the test.
3874 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003875static int
Owen Taylor3473f882001-02-23 17:55:21 +00003876xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3877 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3878 if ((val == NULL) || (arg == NULL) ||
3879 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3880 return(0);
3881
3882 switch(val->type) {
3883 case XPATH_NUMBER:
3884 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3885 case XPATH_NODESET:
3886 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003887 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003888 case XPATH_STRING:
3889 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3890 case XPATH_BOOLEAN:
3891 valuePush(ctxt, arg);
3892 xmlXPathBooleanFunction(ctxt, 1);
3893 valuePush(ctxt, val);
3894 return(xmlXPathCompareValues(ctxt, inf, strict));
3895 default:
3896 TODO
3897 return(0);
3898 }
3899 return(0);
3900}
3901
3902/**
3903 * xmlXPathEqualNodeSetString
3904 * @arg: the nodeset object argument
3905 * @str: the string to compare to.
3906 *
3907 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3908 * If one object to be compared is a node-set and the other is a string,
3909 * then the comparison will be true if and only if there is a node in
3910 * the node-set such that the result of performing the comparison on the
3911 * string-value of the node and the other string is true.
3912 *
3913 * Returns 0 or 1 depending on the results of the test.
3914 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003915static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003916xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3917{
Owen Taylor3473f882001-02-23 17:55:21 +00003918 int i;
3919 xmlNodeSetPtr ns;
3920 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003921 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003922
3923 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003924 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3925 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003926 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003927 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003928 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003929 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003930 if (ns->nodeNr <= 0) {
3931 if (hash == 0)
3932 return(1);
3933 return(0);
3934 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003935 for (i = 0; i < ns->nodeNr; i++) {
3936 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3937 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3938 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3939 xmlFree(str2);
3940 return (1);
3941 }
3942 if (str2 != NULL)
3943 xmlFree(str2);
3944 }
Owen Taylor3473f882001-02-23 17:55:21 +00003945 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003946 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003947}
3948
3949/**
3950 * xmlXPathEqualNodeSetFloat
3951 * @arg: the nodeset object argument
3952 * @f: the float to compare to
3953 *
3954 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3955 * If one object to be compared is a node-set and the other is a number,
3956 * then the comparison will be true if and only if there is a node in
3957 * the node-set such that the result of performing the comparison on the
3958 * number to be compared and on the result of converting the string-value
3959 * of that node to a number using the number function is true.
3960 *
3961 * Returns 0 or 1 depending on the results of the test.
3962 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003963static int
Owen Taylor3473f882001-02-23 17:55:21 +00003964xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3965 char buf[100] = "";
3966
3967 if ((arg == NULL) ||
3968 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3969 return(0);
3970
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003971 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003972 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3973}
3974
3975
3976/**
3977 * xmlXPathEqualNodeSets
3978 * @arg1: first nodeset object argument
3979 * @arg2: second nodeset object argument
3980 *
3981 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3982 * If both objects to be compared are node-sets, then the comparison
3983 * will be true if and only if there is a node in the first node-set and
3984 * a node in the second node-set such that the result of performing the
3985 * comparison on the string-values of the two nodes is true.
3986 *
3987 * (needless to say, this is a costly operation)
3988 *
3989 * Returns 0 or 1 depending on the results of the test.
3990 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003991static int
Owen Taylor3473f882001-02-23 17:55:21 +00003992xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3993 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003994 unsigned int *hashs1;
3995 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003996 xmlChar **values1;
3997 xmlChar **values2;
3998 int ret = 0;
3999 xmlNodeSetPtr ns1;
4000 xmlNodeSetPtr ns2;
4001
4002 if ((arg1 == NULL) ||
4003 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4004 return(0);
4005 if ((arg2 == NULL) ||
4006 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4007 return(0);
4008
4009 ns1 = arg1->nodesetval;
4010 ns2 = arg2->nodesetval;
4011
Daniel Veillard911f49a2001-04-07 15:39:35 +00004012 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004013 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004014 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004015 return(0);
4016
4017 /*
4018 * check if there is a node pertaining to both sets
4019 */
4020 for (i = 0;i < ns1->nodeNr;i++)
4021 for (j = 0;j < ns2->nodeNr;j++)
4022 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4023 return(1);
4024
4025 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4026 if (values1 == NULL)
4027 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004028 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4029 if (hashs1 == NULL) {
4030 xmlFree(values1);
4031 return(0);
4032 }
Owen Taylor3473f882001-02-23 17:55:21 +00004033 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4034 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4035 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004036 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004037 xmlFree(values1);
4038 return(0);
4039 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004040 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4041 if (hashs2 == NULL) {
4042 xmlFree(hashs1);
4043 xmlFree(values1);
4044 xmlFree(values2);
4045 return(0);
4046 }
Owen Taylor3473f882001-02-23 17:55:21 +00004047 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4048 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004049 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004050 for (j = 0;j < ns2->nodeNr;j++) {
4051 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004052 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4053 if (hashs1[i] == hashs2[j]) {
4054 if (values1[i] == NULL)
4055 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4056 if (values2[j] == NULL)
4057 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4058 ret = xmlStrEqual(values1[i], values2[j]);
4059 if (ret)
4060 break;
4061 }
Owen Taylor3473f882001-02-23 17:55:21 +00004062 }
4063 if (ret)
4064 break;
4065 }
4066 for (i = 0;i < ns1->nodeNr;i++)
4067 if (values1[i] != NULL)
4068 xmlFree(values1[i]);
4069 for (j = 0;j < ns2->nodeNr;j++)
4070 if (values2[j] != NULL)
4071 xmlFree(values2[j]);
4072 xmlFree(values1);
4073 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004074 xmlFree(hashs1);
4075 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 return(ret);
4077}
4078
4079/**
4080 * xmlXPathEqualValues:
4081 * @ctxt: the XPath Parser context
4082 *
4083 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4084 *
4085 * Returns 0 or 1 depending on the results of the test.
4086 */
4087int
4088xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4089 xmlXPathObjectPtr arg1, arg2;
4090 int ret = 0;
4091
4092 arg1 = valuePop(ctxt);
4093 if (arg1 == NULL)
4094 XP_ERROR0(XPATH_INVALID_OPERAND);
4095
4096 arg2 = valuePop(ctxt);
4097 if (arg2 == NULL) {
4098 xmlXPathFreeObject(arg1);
4099 XP_ERROR0(XPATH_INVALID_OPERAND);
4100 }
4101
4102 if (arg1 == arg2) {
4103#ifdef DEBUG_EXPR
4104 xmlGenericError(xmlGenericErrorContext,
4105 "Equal: by pointer\n");
4106#endif
4107 return(1);
4108 }
4109
4110 switch (arg1->type) {
4111 case XPATH_UNDEFINED:
4112#ifdef DEBUG_EXPR
4113 xmlGenericError(xmlGenericErrorContext,
4114 "Equal: undefined\n");
4115#endif
4116 break;
4117 case XPATH_XSLT_TREE:
4118 case XPATH_NODESET:
4119 switch (arg2->type) {
4120 case XPATH_UNDEFINED:
4121#ifdef DEBUG_EXPR
4122 xmlGenericError(xmlGenericErrorContext,
4123 "Equal: undefined\n");
4124#endif
4125 break;
4126 case XPATH_XSLT_TREE:
4127 case XPATH_NODESET:
4128 ret = xmlXPathEqualNodeSets(arg1, arg2);
4129 break;
4130 case XPATH_BOOLEAN:
4131 if ((arg1->nodesetval == NULL) ||
4132 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4133 else
4134 ret = 1;
4135 ret = (ret == arg2->boolval);
4136 break;
4137 case XPATH_NUMBER:
4138 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4139 break;
4140 case XPATH_STRING:
4141 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4142 break;
4143 case XPATH_USERS:
4144 case XPATH_POINT:
4145 case XPATH_RANGE:
4146 case XPATH_LOCATIONSET:
4147 TODO
4148 break;
4149 }
4150 break;
4151 case XPATH_BOOLEAN:
4152 switch (arg2->type) {
4153 case XPATH_UNDEFINED:
4154#ifdef DEBUG_EXPR
4155 xmlGenericError(xmlGenericErrorContext,
4156 "Equal: undefined\n");
4157#endif
4158 break;
4159 case XPATH_NODESET:
4160 case XPATH_XSLT_TREE:
4161 if ((arg2->nodesetval == NULL) ||
4162 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4163 else
4164 ret = 1;
4165 break;
4166 case XPATH_BOOLEAN:
4167#ifdef DEBUG_EXPR
4168 xmlGenericError(xmlGenericErrorContext,
4169 "Equal: %d boolean %d \n",
4170 arg1->boolval, arg2->boolval);
4171#endif
4172 ret = (arg1->boolval == arg2->boolval);
4173 break;
4174 case XPATH_NUMBER:
4175 if (arg2->floatval) ret = 1;
4176 else ret = 0;
4177 ret = (arg1->boolval == ret);
4178 break;
4179 case XPATH_STRING:
4180 if ((arg2->stringval == NULL) ||
4181 (arg2->stringval[0] == 0)) ret = 0;
4182 else
4183 ret = 1;
4184 ret = (arg1->boolval == ret);
4185 break;
4186 case XPATH_USERS:
4187 case XPATH_POINT:
4188 case XPATH_RANGE:
4189 case XPATH_LOCATIONSET:
4190 TODO
4191 break;
4192 }
4193 break;
4194 case XPATH_NUMBER:
4195 switch (arg2->type) {
4196 case XPATH_UNDEFINED:
4197#ifdef DEBUG_EXPR
4198 xmlGenericError(xmlGenericErrorContext,
4199 "Equal: undefined\n");
4200#endif
4201 break;
4202 case XPATH_NODESET:
4203 case XPATH_XSLT_TREE:
4204 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4205 break;
4206 case XPATH_BOOLEAN:
4207 if (arg1->floatval) ret = 1;
4208 else ret = 0;
4209 ret = (arg2->boolval == ret);
4210 break;
4211 case XPATH_STRING:
4212 valuePush(ctxt, arg2);
4213 xmlXPathNumberFunction(ctxt, 1);
4214 arg2 = valuePop(ctxt);
4215 /* no break on purpose */
4216 case XPATH_NUMBER:
4217 ret = (arg1->floatval == arg2->floatval);
4218 break;
4219 case XPATH_USERS:
4220 case XPATH_POINT:
4221 case XPATH_RANGE:
4222 case XPATH_LOCATIONSET:
4223 TODO
4224 break;
4225 }
4226 break;
4227 case XPATH_STRING:
4228 switch (arg2->type) {
4229 case XPATH_UNDEFINED:
4230#ifdef DEBUG_EXPR
4231 xmlGenericError(xmlGenericErrorContext,
4232 "Equal: undefined\n");
4233#endif
4234 break;
4235 case XPATH_NODESET:
4236 case XPATH_XSLT_TREE:
4237 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4238 break;
4239 case XPATH_BOOLEAN:
4240 if ((arg1->stringval == NULL) ||
4241 (arg1->stringval[0] == 0)) ret = 0;
4242 else
4243 ret = 1;
4244 ret = (arg2->boolval == ret);
4245 break;
4246 case XPATH_STRING:
4247 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4248 break;
4249 case XPATH_NUMBER:
4250 valuePush(ctxt, arg1);
4251 xmlXPathNumberFunction(ctxt, 1);
4252 arg1 = valuePop(ctxt);
4253 ret = (arg1->floatval == arg2->floatval);
4254 break;
4255 case XPATH_USERS:
4256 case XPATH_POINT:
4257 case XPATH_RANGE:
4258 case XPATH_LOCATIONSET:
4259 TODO
4260 break;
4261 }
4262 break;
4263 case XPATH_USERS:
4264 case XPATH_POINT:
4265 case XPATH_RANGE:
4266 case XPATH_LOCATIONSET:
4267 TODO
4268 break;
4269 }
4270 xmlXPathFreeObject(arg1);
4271 xmlXPathFreeObject(arg2);
4272 return(ret);
4273}
4274
4275
4276/**
4277 * xmlXPathCompareValues:
4278 * @ctxt: the XPath Parser context
4279 * @inf: less than (1) or greater than (0)
4280 * @strict: is the comparison strict
4281 *
4282 * Implement the compare operation on XPath objects:
4283 * @arg1 < @arg2 (1, 1, ...
4284 * @arg1 <= @arg2 (1, 0, ...
4285 * @arg1 > @arg2 (0, 1, ...
4286 * @arg1 >= @arg2 (0, 0, ...
4287 *
4288 * When neither object to be compared is a node-set and the operator is
4289 * <=, <, >=, >, then the objects are compared by converted both objects
4290 * to numbers and comparing the numbers according to IEEE 754. The <
4291 * comparison will be true if and only if the first number is less than the
4292 * second number. The <= comparison will be true if and only if the first
4293 * number is less than or equal to the second number. The > comparison
4294 * will be true if and only if the first number is greater than the second
4295 * number. The >= comparison will be true if and only if the first number
4296 * is greater than or equal to the second number.
4297 *
4298 * Returns 1 if the comparaison succeeded, 0 if it failed
4299 */
4300int
4301xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4302 int ret = 0;
4303 xmlXPathObjectPtr arg1, arg2;
4304
4305 arg2 = valuePop(ctxt);
4306 if (arg2 == NULL) {
4307 XP_ERROR0(XPATH_INVALID_OPERAND);
4308 }
4309
4310 arg1 = valuePop(ctxt);
4311 if (arg1 == NULL) {
4312 xmlXPathFreeObject(arg2);
4313 XP_ERROR0(XPATH_INVALID_OPERAND);
4314 }
4315
4316 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4317 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004318 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004319 } else {
4320 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004321 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4322 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004323 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004324 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4325 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004326 }
4327 }
4328 return(ret);
4329 }
4330
4331 if (arg1->type != XPATH_NUMBER) {
4332 valuePush(ctxt, arg1);
4333 xmlXPathNumberFunction(ctxt, 1);
4334 arg1 = valuePop(ctxt);
4335 }
4336 if (arg1->type != XPATH_NUMBER) {
4337 xmlXPathFreeObject(arg1);
4338 xmlXPathFreeObject(arg2);
4339 XP_ERROR0(XPATH_INVALID_OPERAND);
4340 }
4341 if (arg2->type != XPATH_NUMBER) {
4342 valuePush(ctxt, arg2);
4343 xmlXPathNumberFunction(ctxt, 1);
4344 arg2 = valuePop(ctxt);
4345 }
4346 if (arg2->type != XPATH_NUMBER) {
4347 xmlXPathFreeObject(arg1);
4348 xmlXPathFreeObject(arg2);
4349 XP_ERROR0(XPATH_INVALID_OPERAND);
4350 }
4351 /*
4352 * Add tests for infinity and nan
4353 * => feedback on 3.4 for Inf and NaN
4354 */
4355 if (inf && strict)
4356 ret = (arg1->floatval < arg2->floatval);
4357 else if (inf && !strict)
4358 ret = (arg1->floatval <= arg2->floatval);
4359 else if (!inf && strict)
4360 ret = (arg1->floatval > arg2->floatval);
4361 else if (!inf && !strict)
4362 ret = (arg1->floatval >= arg2->floatval);
4363 xmlXPathFreeObject(arg1);
4364 xmlXPathFreeObject(arg2);
4365 return(ret);
4366}
4367
4368/**
4369 * xmlXPathValueFlipSign:
4370 * @ctxt: the XPath Parser context
4371 *
4372 * Implement the unary - operation on an XPath object
4373 * The numeric operators convert their operands to numbers as if
4374 * by calling the number function.
4375 */
4376void
4377xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004378 CAST_TO_NUMBER;
4379 CHECK_TYPE(XPATH_NUMBER);
4380 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004381}
4382
4383/**
4384 * xmlXPathAddValues:
4385 * @ctxt: the XPath Parser context
4386 *
4387 * Implement the add operation on XPath objects:
4388 * The numeric operators convert their operands to numbers as if
4389 * by calling the number function.
4390 */
4391void
4392xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4393 xmlXPathObjectPtr arg;
4394 double val;
4395
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004396 arg = valuePop(ctxt);
4397 if (arg == NULL)
4398 XP_ERROR(XPATH_INVALID_OPERAND);
4399 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004400 xmlXPathFreeObject(arg);
4401
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004402 CAST_TO_NUMBER;
4403 CHECK_TYPE(XPATH_NUMBER);
4404 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004405}
4406
4407/**
4408 * xmlXPathSubValues:
4409 * @ctxt: the XPath Parser context
4410 *
4411 * Implement the substraction operation on XPath objects:
4412 * The numeric operators convert their operands to numbers as if
4413 * by calling the number function.
4414 */
4415void
4416xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4417 xmlXPathObjectPtr arg;
4418 double val;
4419
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004420 arg = valuePop(ctxt);
4421 if (arg == NULL)
4422 XP_ERROR(XPATH_INVALID_OPERAND);
4423 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004424 xmlXPathFreeObject(arg);
4425
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004426 CAST_TO_NUMBER;
4427 CHECK_TYPE(XPATH_NUMBER);
4428 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004429}
4430
4431/**
4432 * xmlXPathMultValues:
4433 * @ctxt: the XPath Parser context
4434 *
4435 * Implement the multiply operation on XPath objects:
4436 * The numeric operators convert their operands to numbers as if
4437 * by calling the number function.
4438 */
4439void
4440xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4441 xmlXPathObjectPtr arg;
4442 double val;
4443
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004444 arg = valuePop(ctxt);
4445 if (arg == NULL)
4446 XP_ERROR(XPATH_INVALID_OPERAND);
4447 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004448 xmlXPathFreeObject(arg);
4449
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004450 CAST_TO_NUMBER;
4451 CHECK_TYPE(XPATH_NUMBER);
4452 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004453}
4454
4455/**
4456 * xmlXPathDivValues:
4457 * @ctxt: the XPath Parser context
4458 *
4459 * Implement the div operation on XPath objects @arg1 / @arg2:
4460 * The numeric operators convert their operands to numbers as if
4461 * by calling the number function.
4462 */
4463void
4464xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4465 xmlXPathObjectPtr arg;
4466 double val;
4467
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004468 arg = valuePop(ctxt);
4469 if (arg == NULL)
4470 XP_ERROR(XPATH_INVALID_OPERAND);
4471 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004472 xmlXPathFreeObject(arg);
4473
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004474 CAST_TO_NUMBER;
4475 CHECK_TYPE(XPATH_NUMBER);
4476 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004477}
4478
4479/**
4480 * xmlXPathModValues:
4481 * @ctxt: the XPath Parser context
4482 *
4483 * Implement the mod operation on XPath objects: @arg1 / @arg2
4484 * The numeric operators convert their operands to numbers as if
4485 * by calling the number function.
4486 */
4487void
4488xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4489 xmlXPathObjectPtr arg;
4490 int arg1, arg2;
4491
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004492 arg = valuePop(ctxt);
4493 if (arg == NULL)
4494 XP_ERROR(XPATH_INVALID_OPERAND);
4495 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004496 xmlXPathFreeObject(arg);
4497
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004498 CAST_TO_NUMBER;
4499 CHECK_TYPE(XPATH_NUMBER);
4500 arg1 = (int) ctxt->value->floatval;
4501 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004502}
4503
4504/************************************************************************
4505 * *
4506 * The traversal functions *
4507 * *
4508 ************************************************************************/
4509
Owen Taylor3473f882001-02-23 17:55:21 +00004510/*
4511 * A traversal function enumerates nodes along an axis.
4512 * Initially it must be called with NULL, and it indicates
4513 * termination on the axis by returning NULL.
4514 */
4515typedef xmlNodePtr (*xmlXPathTraversalFunction)
4516 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4517
4518/**
4519 * xmlXPathNextSelf:
4520 * @ctxt: the XPath Parser context
4521 * @cur: the current node in the traversal
4522 *
4523 * Traversal function for the "self" direction
4524 * The self axis contains just the context node itself
4525 *
4526 * Returns the next element following that axis
4527 */
4528xmlNodePtr
4529xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4530 if (cur == NULL)
4531 return(ctxt->context->node);
4532 return(NULL);
4533}
4534
4535/**
4536 * xmlXPathNextChild:
4537 * @ctxt: the XPath Parser context
4538 * @cur: the current node in the traversal
4539 *
4540 * Traversal function for the "child" direction
4541 * The child axis contains the children of the context node in document order.
4542 *
4543 * Returns the next element following that axis
4544 */
4545xmlNodePtr
4546xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4547 if (cur == NULL) {
4548 if (ctxt->context->node == NULL) return(NULL);
4549 switch (ctxt->context->node->type) {
4550 case XML_ELEMENT_NODE:
4551 case XML_TEXT_NODE:
4552 case XML_CDATA_SECTION_NODE:
4553 case XML_ENTITY_REF_NODE:
4554 case XML_ENTITY_NODE:
4555 case XML_PI_NODE:
4556 case XML_COMMENT_NODE:
4557 case XML_NOTATION_NODE:
4558 case XML_DTD_NODE:
4559 return(ctxt->context->node->children);
4560 case XML_DOCUMENT_NODE:
4561 case XML_DOCUMENT_TYPE_NODE:
4562 case XML_DOCUMENT_FRAG_NODE:
4563 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004564#ifdef LIBXML_DOCB_ENABLED
4565 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004566#endif
4567 return(((xmlDocPtr) ctxt->context->node)->children);
4568 case XML_ELEMENT_DECL:
4569 case XML_ATTRIBUTE_DECL:
4570 case XML_ENTITY_DECL:
4571 case XML_ATTRIBUTE_NODE:
4572 case XML_NAMESPACE_DECL:
4573 case XML_XINCLUDE_START:
4574 case XML_XINCLUDE_END:
4575 return(NULL);
4576 }
4577 return(NULL);
4578 }
4579 if ((cur->type == XML_DOCUMENT_NODE) ||
4580 (cur->type == XML_HTML_DOCUMENT_NODE))
4581 return(NULL);
4582 return(cur->next);
4583}
4584
4585/**
4586 * xmlXPathNextDescendant:
4587 * @ctxt: the XPath Parser context
4588 * @cur: the current node in the traversal
4589 *
4590 * Traversal function for the "descendant" direction
4591 * the descendant axis contains the descendants of the context node in document
4592 * order; a descendant is a child or a child of a child and so on.
4593 *
4594 * Returns the next element following that axis
4595 */
4596xmlNodePtr
4597xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4598 if (cur == NULL) {
4599 if (ctxt->context->node == NULL)
4600 return(NULL);
4601 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4602 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4603 return(NULL);
4604
4605 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4606 return(ctxt->context->doc->children);
4607 return(ctxt->context->node->children);
4608 }
4609
4610 if (cur->children != NULL)
4611 {
4612 if (cur->children->type != XML_ENTITY_DECL)
4613 return(cur->children);
4614 }
4615 if (cur->next != NULL) return(cur->next);
4616
4617 do {
4618 cur = cur->parent;
4619 if (cur == NULL) return(NULL);
4620 if (cur == ctxt->context->node) return(NULL);
4621 if (cur->next != NULL) {
4622 cur = cur->next;
4623 return(cur);
4624 }
4625 } while (cur != NULL);
4626 return(cur);
4627}
4628
4629/**
4630 * xmlXPathNextDescendantOrSelf:
4631 * @ctxt: the XPath Parser context
4632 * @cur: the current node in the traversal
4633 *
4634 * Traversal function for the "descendant-or-self" direction
4635 * the descendant-or-self axis contains the context node and the descendants
4636 * of the context node in document order; thus the context node is the first
4637 * node on the axis, and the first child of the context node is the second node
4638 * on the axis
4639 *
4640 * Returns the next element following that axis
4641 */
4642xmlNodePtr
4643xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4644 if (cur == NULL) {
4645 if (ctxt->context->node == NULL)
4646 return(NULL);
4647 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4648 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4649 return(NULL);
4650 return(ctxt->context->node);
4651 }
4652
4653 return(xmlXPathNextDescendant(ctxt, cur));
4654}
4655
4656/**
4657 * xmlXPathNextParent:
4658 * @ctxt: the XPath Parser context
4659 * @cur: the current node in the traversal
4660 *
4661 * Traversal function for the "parent" direction
4662 * The parent axis contains the parent of the context node, if there is one.
4663 *
4664 * Returns the next element following that axis
4665 */
4666xmlNodePtr
4667xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4668 /*
4669 * the parent of an attribute or namespace node is the element
4670 * to which the attribute or namespace node is attached
4671 * Namespace handling !!!
4672 */
4673 if (cur == NULL) {
4674 if (ctxt->context->node == NULL) return(NULL);
4675 switch (ctxt->context->node->type) {
4676 case XML_ELEMENT_NODE:
4677 case XML_TEXT_NODE:
4678 case XML_CDATA_SECTION_NODE:
4679 case XML_ENTITY_REF_NODE:
4680 case XML_ENTITY_NODE:
4681 case XML_PI_NODE:
4682 case XML_COMMENT_NODE:
4683 case XML_NOTATION_NODE:
4684 case XML_DTD_NODE:
4685 case XML_ELEMENT_DECL:
4686 case XML_ATTRIBUTE_DECL:
4687 case XML_XINCLUDE_START:
4688 case XML_XINCLUDE_END:
4689 case XML_ENTITY_DECL:
4690 if (ctxt->context->node->parent == NULL)
4691 return((xmlNodePtr) ctxt->context->doc);
4692 return(ctxt->context->node->parent);
4693 case XML_ATTRIBUTE_NODE: {
4694 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4695
4696 return(att->parent);
4697 }
4698 case XML_DOCUMENT_NODE:
4699 case XML_DOCUMENT_TYPE_NODE:
4700 case XML_DOCUMENT_FRAG_NODE:
4701 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004702#ifdef LIBXML_DOCB_ENABLED
4703 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004704#endif
4705 return(NULL);
4706 case XML_NAMESPACE_DECL:
4707 /*
4708 * TODO !!! may require extending struct _xmlNs with
4709 * parent field
4710 * C.f. Infoset case...
4711 */
4712 return(NULL);
4713 }
4714 }
4715 return(NULL);
4716}
4717
4718/**
4719 * xmlXPathNextAncestor:
4720 * @ctxt: the XPath Parser context
4721 * @cur: the current node in the traversal
4722 *
4723 * Traversal function for the "ancestor" direction
4724 * the ancestor axis contains the ancestors of the context node; the ancestors
4725 * of the context node consist of the parent of context node and the parent's
4726 * parent and so on; the nodes are ordered in reverse document order; thus the
4727 * parent is the first node on the axis, and the parent's parent is the second
4728 * node on the axis
4729 *
4730 * Returns the next element following that axis
4731 */
4732xmlNodePtr
4733xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4734 /*
4735 * the parent of an attribute or namespace node is the element
4736 * to which the attribute or namespace node is attached
4737 * !!!!!!!!!!!!!
4738 */
4739 if (cur == NULL) {
4740 if (ctxt->context->node == NULL) return(NULL);
4741 switch (ctxt->context->node->type) {
4742 case XML_ELEMENT_NODE:
4743 case XML_TEXT_NODE:
4744 case XML_CDATA_SECTION_NODE:
4745 case XML_ENTITY_REF_NODE:
4746 case XML_ENTITY_NODE:
4747 case XML_PI_NODE:
4748 case XML_COMMENT_NODE:
4749 case XML_DTD_NODE:
4750 case XML_ELEMENT_DECL:
4751 case XML_ATTRIBUTE_DECL:
4752 case XML_ENTITY_DECL:
4753 case XML_NOTATION_NODE:
4754 case XML_XINCLUDE_START:
4755 case XML_XINCLUDE_END:
4756 if (ctxt->context->node->parent == NULL)
4757 return((xmlNodePtr) ctxt->context->doc);
4758 return(ctxt->context->node->parent);
4759 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004760 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004761
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004762 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004763 }
4764 case XML_DOCUMENT_NODE:
4765 case XML_DOCUMENT_TYPE_NODE:
4766 case XML_DOCUMENT_FRAG_NODE:
4767 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004768#ifdef LIBXML_DOCB_ENABLED
4769 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004770#endif
4771 return(NULL);
4772 case XML_NAMESPACE_DECL:
4773 /*
4774 * TODO !!! may require extending struct _xmlNs with
4775 * parent field
4776 * C.f. Infoset case...
4777 */
4778 return(NULL);
4779 }
4780 return(NULL);
4781 }
4782 if (cur == ctxt->context->doc->children)
4783 return((xmlNodePtr) ctxt->context->doc);
4784 if (cur == (xmlNodePtr) ctxt->context->doc)
4785 return(NULL);
4786 switch (cur->type) {
4787 case XML_ELEMENT_NODE:
4788 case XML_TEXT_NODE:
4789 case XML_CDATA_SECTION_NODE:
4790 case XML_ENTITY_REF_NODE:
4791 case XML_ENTITY_NODE:
4792 case XML_PI_NODE:
4793 case XML_COMMENT_NODE:
4794 case XML_NOTATION_NODE:
4795 case XML_DTD_NODE:
4796 case XML_ELEMENT_DECL:
4797 case XML_ATTRIBUTE_DECL:
4798 case XML_ENTITY_DECL:
4799 case XML_XINCLUDE_START:
4800 case XML_XINCLUDE_END:
4801 return(cur->parent);
4802 case XML_ATTRIBUTE_NODE: {
4803 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4804
4805 return(att->parent);
4806 }
4807 case XML_DOCUMENT_NODE:
4808 case XML_DOCUMENT_TYPE_NODE:
4809 case XML_DOCUMENT_FRAG_NODE:
4810 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004811#ifdef LIBXML_DOCB_ENABLED
4812 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004813#endif
4814 return(NULL);
4815 case XML_NAMESPACE_DECL:
4816 /*
4817 * TODO !!! may require extending struct _xmlNs with
4818 * parent field
4819 * C.f. Infoset case...
4820 */
4821 return(NULL);
4822 }
4823 return(NULL);
4824}
4825
4826/**
4827 * xmlXPathNextAncestorOrSelf:
4828 * @ctxt: the XPath Parser context
4829 * @cur: the current node in the traversal
4830 *
4831 * Traversal function for the "ancestor-or-self" direction
4832 * he ancestor-or-self axis contains the context node and ancestors of
4833 * the context node in reverse document order; thus the context node is
4834 * the first node on the axis, and the context node's parent the second;
4835 * parent here is defined the same as with the parent axis.
4836 *
4837 * Returns the next element following that axis
4838 */
4839xmlNodePtr
4840xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4841 if (cur == NULL)
4842 return(ctxt->context->node);
4843 return(xmlXPathNextAncestor(ctxt, cur));
4844}
4845
4846/**
4847 * xmlXPathNextFollowingSibling:
4848 * @ctxt: the XPath Parser context
4849 * @cur: the current node in the traversal
4850 *
4851 * Traversal function for the "following-sibling" direction
4852 * The following-sibling axis contains the following siblings of the context
4853 * node in document order.
4854 *
4855 * Returns the next element following that axis
4856 */
4857xmlNodePtr
4858xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4859 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4860 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4861 return(NULL);
4862 if (cur == (xmlNodePtr) ctxt->context->doc)
4863 return(NULL);
4864 if (cur == NULL)
4865 return(ctxt->context->node->next);
4866 return(cur->next);
4867}
4868
4869/**
4870 * xmlXPathNextPrecedingSibling:
4871 * @ctxt: the XPath Parser context
4872 * @cur: the current node in the traversal
4873 *
4874 * Traversal function for the "preceding-sibling" direction
4875 * The preceding-sibling axis contains the preceding siblings of the context
4876 * node in reverse document order; the first preceding sibling is first on the
4877 * axis; the sibling preceding that node is the second on the axis and so on.
4878 *
4879 * Returns the next element following that axis
4880 */
4881xmlNodePtr
4882xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4883 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4884 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4885 return(NULL);
4886 if (cur == (xmlNodePtr) ctxt->context->doc)
4887 return(NULL);
4888 if (cur == NULL)
4889 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004890 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4891 cur = cur->prev;
4892 if (cur == NULL)
4893 return(ctxt->context->node->prev);
4894 }
Owen Taylor3473f882001-02-23 17:55:21 +00004895 return(cur->prev);
4896}
4897
4898/**
4899 * xmlXPathNextFollowing:
4900 * @ctxt: the XPath Parser context
4901 * @cur: the current node in the traversal
4902 *
4903 * Traversal function for the "following" direction
4904 * The following axis contains all nodes in the same document as the context
4905 * node that are after the context node in document order, excluding any
4906 * descendants and excluding attribute nodes and namespace nodes; the nodes
4907 * are ordered in document order
4908 *
4909 * Returns the next element following that axis
4910 */
4911xmlNodePtr
4912xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4913 if (cur != NULL && cur->children != NULL)
4914 return cur->children ;
4915 if (cur == NULL) cur = ctxt->context->node;
4916 if (cur == NULL) return(NULL) ; /* ERROR */
4917 if (cur->next != NULL) return(cur->next) ;
4918 do {
4919 cur = cur->parent;
4920 if (cur == NULL) return(NULL);
4921 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4922 if (cur->next != NULL) return(cur->next);
4923 } while (cur != NULL);
4924 return(cur);
4925}
4926
4927/*
4928 * xmlXPathIsAncestor:
4929 * @ancestor: the ancestor node
4930 * @node: the current node
4931 *
4932 * Check that @ancestor is a @node's ancestor
4933 *
4934 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4935 */
4936static int
4937xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4938 if ((ancestor == NULL) || (node == NULL)) return(0);
4939 /* nodes need to be in the same document */
4940 if (ancestor->doc != node->doc) return(0);
4941 /* avoid searching if ancestor or node is the root node */
4942 if (ancestor == (xmlNodePtr) node->doc) return(1);
4943 if (node == (xmlNodePtr) ancestor->doc) return(0);
4944 while (node->parent != NULL) {
4945 if (node->parent == ancestor)
4946 return(1);
4947 node = node->parent;
4948 }
4949 return(0);
4950}
4951
4952/**
4953 * xmlXPathNextPreceding:
4954 * @ctxt: the XPath Parser context
4955 * @cur: the current node in the traversal
4956 *
4957 * Traversal function for the "preceding" direction
4958 * the preceding axis contains all nodes in the same document as the context
4959 * node that are before the context node in document order, excluding any
4960 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4961 * ordered in reverse document order
4962 *
4963 * Returns the next element following that axis
4964 */
4965xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004966xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4967{
Owen Taylor3473f882001-02-23 17:55:21 +00004968 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004969 cur = ctxt->context->node;
4970 if (cur == NULL)
4971 return (NULL);
4972 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4973 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004974 do {
4975 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004976 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4977 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004978 }
4979
4980 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004981 if (cur == NULL)
4982 return (NULL);
4983 if (cur == ctxt->context->doc->children)
4984 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004985 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004986 return (cur);
4987}
4988
4989/**
4990 * xmlXPathNextPrecedingInternal:
4991 * @ctxt: the XPath Parser context
4992 * @cur: the current node in the traversal
4993 *
4994 * Traversal function for the "preceding" direction
4995 * the preceding axis contains all nodes in the same document as the context
4996 * node that are before the context node in document order, excluding any
4997 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4998 * ordered in reverse document order
4999 * This is a faster implementation but internal only since it requires a
5000 * state kept in the parser context: ctxt->ancestor.
5001 *
5002 * Returns the next element following that axis
5003 */
5004static xmlNodePtr
5005xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5006 xmlNodePtr cur)
5007{
5008 if (cur == NULL) {
5009 cur = ctxt->context->node;
5010 if (cur == NULL)
5011 return (NULL);
5012 ctxt->ancestor = cur->parent;
5013 }
5014 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5015 cur = cur->prev;
5016 while (cur->prev == NULL) {
5017 cur = cur->parent;
5018 if (cur == NULL)
5019 return (NULL);
5020 if (cur == ctxt->context->doc->children)
5021 return (NULL);
5022 if (cur != ctxt->ancestor)
5023 return (cur);
5024 ctxt->ancestor = cur->parent;
5025 }
5026 cur = cur->prev;
5027 while (cur->last != NULL)
5028 cur = cur->last;
5029 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005030}
5031
5032/**
5033 * xmlXPathNextNamespace:
5034 * @ctxt: the XPath Parser context
5035 * @cur: the current attribute in the traversal
5036 *
5037 * Traversal function for the "namespace" direction
5038 * the namespace axis contains the namespace nodes of the context node;
5039 * the order of nodes on this axis is implementation-defined; the axis will
5040 * be empty unless the context node is an element
5041 *
5042 * Returns the next element following that axis
5043 */
5044xmlNodePtr
5045xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5046 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
5047 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
5048 if (ctxt->context->namespaces != NULL)
5049 xmlFree(ctxt->context->namespaces);
5050 ctxt->context->namespaces =
5051 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
5052 if (ctxt->context->namespaces == NULL) return(NULL);
5053 ctxt->context->nsNr = 0;
5054 }
5055 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
5056}
5057
5058/**
5059 * xmlXPathNextAttribute:
5060 * @ctxt: the XPath Parser context
5061 * @cur: the current attribute in the traversal
5062 *
5063 * Traversal function for the "attribute" direction
5064 * TODO: support DTD inherited default attributes
5065 *
5066 * Returns the next element following that axis
5067 */
5068xmlNodePtr
5069xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005070 if (ctxt->context->node == NULL)
5071 return(NULL);
5072 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5073 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005074 if (cur == NULL) {
5075 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5076 return(NULL);
5077 return((xmlNodePtr)ctxt->context->node->properties);
5078 }
5079 return((xmlNodePtr)cur->next);
5080}
5081
5082/************************************************************************
5083 * *
5084 * NodeTest Functions *
5085 * *
5086 ************************************************************************/
5087
Owen Taylor3473f882001-02-23 17:55:21 +00005088#define IS_FUNCTION 200
5089
Owen Taylor3473f882001-02-23 17:55:21 +00005090
5091/************************************************************************
5092 * *
5093 * Implicit tree core function library *
5094 * *
5095 ************************************************************************/
5096
5097/**
5098 * xmlXPathRoot:
5099 * @ctxt: the XPath Parser context
5100 *
5101 * Initialize the context to the root of the document
5102 */
5103void
5104xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5105 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5106 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5107}
5108
5109/************************************************************************
5110 * *
5111 * The explicit core function library *
5112 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5113 * *
5114 ************************************************************************/
5115
5116
5117/**
5118 * xmlXPathLastFunction:
5119 * @ctxt: the XPath Parser context
5120 * @nargs: the number of arguments
5121 *
5122 * Implement the last() XPath function
5123 * number last()
5124 * The last function returns the number of nodes in the context node list.
5125 */
5126void
5127xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5128 CHECK_ARITY(0);
5129 if (ctxt->context->contextSize >= 0) {
5130 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5131#ifdef DEBUG_EXPR
5132 xmlGenericError(xmlGenericErrorContext,
5133 "last() : %d\n", ctxt->context->contextSize);
5134#endif
5135 } else {
5136 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5137 }
5138}
5139
5140/**
5141 * xmlXPathPositionFunction:
5142 * @ctxt: the XPath Parser context
5143 * @nargs: the number of arguments
5144 *
5145 * Implement the position() XPath function
5146 * number position()
5147 * The position function returns the position of the context node in the
5148 * context node list. The first position is 1, and so the last positionr
5149 * will be equal to last().
5150 */
5151void
5152xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5153 CHECK_ARITY(0);
5154 if (ctxt->context->proximityPosition >= 0) {
5155 valuePush(ctxt,
5156 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5157#ifdef DEBUG_EXPR
5158 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5159 ctxt->context->proximityPosition);
5160#endif
5161 } else {
5162 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5163 }
5164}
5165
5166/**
5167 * xmlXPathCountFunction:
5168 * @ctxt: the XPath Parser context
5169 * @nargs: the number of arguments
5170 *
5171 * Implement the count() XPath function
5172 * number count(node-set)
5173 */
5174void
5175xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5176 xmlXPathObjectPtr cur;
5177
5178 CHECK_ARITY(1);
5179 if ((ctxt->value == NULL) ||
5180 ((ctxt->value->type != XPATH_NODESET) &&
5181 (ctxt->value->type != XPATH_XSLT_TREE)))
5182 XP_ERROR(XPATH_INVALID_TYPE);
5183 cur = valuePop(ctxt);
5184
Daniel Veillard911f49a2001-04-07 15:39:35 +00005185 if ((cur == NULL) || (cur->nodesetval == NULL))
5186 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5187 else
5188 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00005189 xmlXPathFreeObject(cur);
5190}
5191
5192/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005193 * xmlXPathGetElementsByIds:
5194 * @doc: the document
5195 * @ids: a whitespace separated list of IDs
5196 *
5197 * Selects elements by their unique ID.
5198 *
5199 * Returns a node-set of selected elements.
5200 */
5201static xmlNodeSetPtr
5202xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5203 xmlNodeSetPtr ret;
5204 const xmlChar *cur = ids;
5205 xmlChar *ID;
5206 xmlAttrPtr attr;
5207 xmlNodePtr elem = NULL;
5208
5209 ret = xmlXPathNodeSetCreate(NULL);
5210
5211 while (IS_BLANK(*cur)) cur++;
5212 while (*cur != 0) {
5213 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5214 (*cur == '.') || (*cur == '-') ||
5215 (*cur == '_') || (*cur == ':') ||
5216 (IS_COMBINING(*cur)) ||
5217 (IS_EXTENDER(*cur)))
5218 cur++;
5219
5220 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5221
5222 ID = xmlStrndup(ids, cur - ids);
5223 attr = xmlGetID(doc, ID);
5224 if (attr != NULL) {
5225 elem = attr->parent;
5226 xmlXPathNodeSetAdd(ret, elem);
5227 }
5228 if (ID != NULL)
5229 xmlFree(ID);
5230
5231 while (IS_BLANK(*cur)) cur++;
5232 ids = cur;
5233 }
5234 return(ret);
5235}
5236
5237/**
Owen Taylor3473f882001-02-23 17:55:21 +00005238 * xmlXPathIdFunction:
5239 * @ctxt: the XPath Parser context
5240 * @nargs: the number of arguments
5241 *
5242 * Implement the id() XPath function
5243 * node-set id(object)
5244 * The id function selects elements by their unique ID
5245 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5246 * then the result is the union of the result of applying id to the
5247 * string value of each of the nodes in the argument node-set. When the
5248 * argument to id is of any other type, the argument is converted to a
5249 * string as if by a call to the string function; the string is split
5250 * into a whitespace-separated list of tokens (whitespace is any sequence
5251 * of characters matching the production S); the result is a node-set
5252 * containing the elements in the same document as the context node that
5253 * have a unique ID equal to any of the tokens in the list.
5254 */
5255void
5256xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005257 xmlChar *tokens;
5258 xmlNodeSetPtr ret;
5259 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005260
5261 CHECK_ARITY(1);
5262 obj = valuePop(ctxt);
5263 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5264 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005265 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005266 int i;
5267
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005268 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005269
Daniel Veillard911f49a2001-04-07 15:39:35 +00005270 if (obj->nodesetval != NULL) {
5271 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005272 tokens =
5273 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5274 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5275 ret = xmlXPathNodeSetMerge(ret, ns);
5276 xmlXPathFreeNodeSet(ns);
5277 if (tokens != NULL)
5278 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005279 }
Owen Taylor3473f882001-02-23 17:55:21 +00005280 }
5281
5282 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005283 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005284 return;
5285 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005286 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005287
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005288 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5289 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005290
Owen Taylor3473f882001-02-23 17:55:21 +00005291 xmlXPathFreeObject(obj);
5292 return;
5293}
5294
5295/**
5296 * xmlXPathLocalNameFunction:
5297 * @ctxt: the XPath Parser context
5298 * @nargs: the number of arguments
5299 *
5300 * Implement the local-name() XPath function
5301 * string local-name(node-set?)
5302 * The local-name function returns a string containing the local part
5303 * of the name of the node in the argument node-set that is first in
5304 * document order. If the node-set is empty or the first node has no
5305 * name, an empty string is returned. If the argument is omitted it
5306 * defaults to the context node.
5307 */
5308void
5309xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5310 xmlXPathObjectPtr cur;
5311
5312 if (nargs == 0) {
5313 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5314 nargs = 1;
5315 }
5316
5317 CHECK_ARITY(1);
5318 if ((ctxt->value == NULL) ||
5319 ((ctxt->value->type != XPATH_NODESET) &&
5320 (ctxt->value->type != XPATH_XSLT_TREE)))
5321 XP_ERROR(XPATH_INVALID_TYPE);
5322 cur = valuePop(ctxt);
5323
Daniel Veillard911f49a2001-04-07 15:39:35 +00005324 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005325 valuePush(ctxt, xmlXPathNewCString(""));
5326 } else {
5327 int i = 0; /* Should be first in document order !!!!! */
5328 switch (cur->nodesetval->nodeTab[i]->type) {
5329 case XML_ELEMENT_NODE:
5330 case XML_ATTRIBUTE_NODE:
5331 case XML_PI_NODE:
5332 valuePush(ctxt,
5333 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5334 break;
5335 case XML_NAMESPACE_DECL:
5336 valuePush(ctxt, xmlXPathNewString(
5337 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5338 break;
5339 default:
5340 valuePush(ctxt, xmlXPathNewCString(""));
5341 }
5342 }
5343 xmlXPathFreeObject(cur);
5344}
5345
5346/**
5347 * xmlXPathNamespaceURIFunction:
5348 * @ctxt: the XPath Parser context
5349 * @nargs: the number of arguments
5350 *
5351 * Implement the namespace-uri() XPath function
5352 * string namespace-uri(node-set?)
5353 * The namespace-uri function returns a string containing the
5354 * namespace URI of the expanded name of the node in the argument
5355 * node-set that is first in document order. If the node-set is empty,
5356 * the first node has no name, or the expanded name has no namespace
5357 * URI, an empty string is returned. If the argument is omitted it
5358 * defaults to the context node.
5359 */
5360void
5361xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5362 xmlXPathObjectPtr cur;
5363
5364 if (nargs == 0) {
5365 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5366 nargs = 1;
5367 }
5368 CHECK_ARITY(1);
5369 if ((ctxt->value == NULL) ||
5370 ((ctxt->value->type != XPATH_NODESET) &&
5371 (ctxt->value->type != XPATH_XSLT_TREE)))
5372 XP_ERROR(XPATH_INVALID_TYPE);
5373 cur = valuePop(ctxt);
5374
Daniel Veillard911f49a2001-04-07 15:39:35 +00005375 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005376 valuePush(ctxt, xmlXPathNewCString(""));
5377 } else {
5378 int i = 0; /* Should be first in document order !!!!! */
5379 switch (cur->nodesetval->nodeTab[i]->type) {
5380 case XML_ELEMENT_NODE:
5381 case XML_ATTRIBUTE_NODE:
5382 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5383 valuePush(ctxt, xmlXPathNewCString(""));
5384 else
5385 valuePush(ctxt, xmlXPathNewString(
5386 cur->nodesetval->nodeTab[i]->ns->href));
5387 break;
5388 default:
5389 valuePush(ctxt, xmlXPathNewCString(""));
5390 }
5391 }
5392 xmlXPathFreeObject(cur);
5393}
5394
5395/**
5396 * xmlXPathNameFunction:
5397 * @ctxt: the XPath Parser context
5398 * @nargs: the number of arguments
5399 *
5400 * Implement the name() XPath function
5401 * string name(node-set?)
5402 * The name function returns a string containing a QName representing
5403 * the name of the node in the argument node-set that is first in documenti
5404 * order. The QName must represent the name with respect to the namespace
5405 * declarations in effect on the node whose name is being represented.
5406 * Typically, this will be the form in which the name occurred in the XML
5407 * source. This need not be the case if there are namespace declarations
5408 * in effect on the node that associate multiple prefixes with the same
5409 * namespace. However, an implementation may include information about
5410 * the original prefix in its representation of nodes; in this case, an
5411 * implementation can ensure that the returned string is always the same
5412 * as the QName used in the XML source. If the argument it omitted it
5413 * defaults to the context node.
5414 * Libxml keep the original prefix so the "real qualified name" used is
5415 * returned.
5416 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005417static void
Daniel Veillard04383752001-07-08 14:27:15 +00005418xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5419{
Owen Taylor3473f882001-02-23 17:55:21 +00005420 xmlXPathObjectPtr cur;
5421
5422 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005423 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5424 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005425 }
5426
5427 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005428 if ((ctxt->value == NULL) ||
5429 ((ctxt->value->type != XPATH_NODESET) &&
5430 (ctxt->value->type != XPATH_XSLT_TREE)))
5431 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005432 cur = valuePop(ctxt);
5433
Daniel Veillard911f49a2001-04-07 15:39:35 +00005434 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005435 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005436 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005437 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005438
Daniel Veillard04383752001-07-08 14:27:15 +00005439 switch (cur->nodesetval->nodeTab[i]->type) {
5440 case XML_ELEMENT_NODE:
5441 case XML_ATTRIBUTE_NODE:
5442 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5443 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5444 valuePush(ctxt,
5445 xmlXPathNewString(cur->nodesetval->
5446 nodeTab[i]->name));
5447
5448 else {
5449 char name[2000];
5450
5451 snprintf(name, sizeof(name), "%s:%s",
5452 (char *) cur->nodesetval->nodeTab[i]->ns->
5453 prefix,
5454 (char *) cur->nodesetval->nodeTab[i]->name);
5455 name[sizeof(name) - 1] = 0;
5456 valuePush(ctxt, xmlXPathNewCString(name));
5457 }
5458 break;
5459 default:
5460 valuePush(ctxt,
5461 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5462 xmlXPathLocalNameFunction(ctxt, 1);
5463 }
Owen Taylor3473f882001-02-23 17:55:21 +00005464 }
5465 xmlXPathFreeObject(cur);
5466}
5467
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005468
5469/**
Owen Taylor3473f882001-02-23 17:55:21 +00005470 * xmlXPathStringFunction:
5471 * @ctxt: the XPath Parser context
5472 * @nargs: the number of arguments
5473 *
5474 * Implement the string() XPath function
5475 * string string(object?)
5476 * he string function converts an object to a string as follows:
5477 * - A node-set is converted to a string by returning the value of
5478 * the node in the node-set that is first in document order.
5479 * If the node-set is empty, an empty string is returned.
5480 * - A number is converted to a string as follows
5481 * + NaN is converted to the string NaN
5482 * + positive zero is converted to the string 0
5483 * + negative zero is converted to the string 0
5484 * + positive infinity is converted to the string Infinity
5485 * + negative infinity is converted to the string -Infinity
5486 * + if the number is an integer, the number is represented in
5487 * decimal form as a Number with no decimal point and no leading
5488 * zeros, preceded by a minus sign (-) if the number is negative
5489 * + otherwise, the number is represented in decimal form as a
5490 * Number including a decimal point with at least one digit
5491 * before the decimal point and at least one digit after the
5492 * decimal point, preceded by a minus sign (-) if the number
5493 * is negative; there must be no leading zeros before the decimal
5494 * point apart possibly from the one required digit immediatelyi
5495 * before the decimal point; beyond the one required digit
5496 * after the decimal point there must be as many, but only as
5497 * many, more digits as are needed to uniquely distinguish the
5498 * number from all other IEEE 754 numeric values.
5499 * - The boolean false value is converted to the string false.
5500 * The boolean true value is converted to the string true.
5501 *
5502 * If the argument is omitted, it defaults to a node-set with the
5503 * context node as its only member.
5504 */
5505void
5506xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5507 xmlXPathObjectPtr cur;
5508
5509 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005510 valuePush(ctxt,
5511 xmlXPathWrapString(
5512 xmlXPathCastNodeToString(ctxt->context->node)));
5513 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005514 }
5515
5516 CHECK_ARITY(1);
5517 cur = valuePop(ctxt);
5518 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005519 cur = xmlXPathConvertString(cur);
5520 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005521}
5522
5523/**
5524 * xmlXPathStringLengthFunction:
5525 * @ctxt: the XPath Parser context
5526 * @nargs: the number of arguments
5527 *
5528 * Implement the string-length() XPath function
5529 * number string-length(string?)
5530 * The string-length returns the number of characters in the string
5531 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5532 * the context node converted to a string, in other words the value
5533 * of the context node.
5534 */
5535void
5536xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5537 xmlXPathObjectPtr cur;
5538
5539 if (nargs == 0) {
5540 if (ctxt->context->node == NULL) {
5541 valuePush(ctxt, xmlXPathNewFloat(0));
5542 } else {
5543 xmlChar *content;
5544
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005545 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005546 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005547 xmlFree(content);
5548 }
5549 return;
5550 }
5551 CHECK_ARITY(1);
5552 CAST_TO_STRING;
5553 CHECK_TYPE(XPATH_STRING);
5554 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005555 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005556 xmlXPathFreeObject(cur);
5557}
5558
5559/**
5560 * xmlXPathConcatFunction:
5561 * @ctxt: the XPath Parser context
5562 * @nargs: the number of arguments
5563 *
5564 * Implement the concat() XPath function
5565 * string concat(string, string, string*)
5566 * The concat function returns the concatenation of its arguments.
5567 */
5568void
5569xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5570 xmlXPathObjectPtr cur, newobj;
5571 xmlChar *tmp;
5572
5573 if (nargs < 2) {
5574 CHECK_ARITY(2);
5575 }
5576
5577 CAST_TO_STRING;
5578 cur = valuePop(ctxt);
5579 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5580 xmlXPathFreeObject(cur);
5581 return;
5582 }
5583 nargs--;
5584
5585 while (nargs > 0) {
5586 CAST_TO_STRING;
5587 newobj = valuePop(ctxt);
5588 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5589 xmlXPathFreeObject(newobj);
5590 xmlXPathFreeObject(cur);
5591 XP_ERROR(XPATH_INVALID_TYPE);
5592 }
5593 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5594 newobj->stringval = cur->stringval;
5595 cur->stringval = tmp;
5596
5597 xmlXPathFreeObject(newobj);
5598 nargs--;
5599 }
5600 valuePush(ctxt, cur);
5601}
5602
5603/**
5604 * xmlXPathContainsFunction:
5605 * @ctxt: the XPath Parser context
5606 * @nargs: the number of arguments
5607 *
5608 * Implement the contains() XPath function
5609 * boolean contains(string, string)
5610 * The contains function returns true if the first argument string
5611 * contains the second argument string, and otherwise returns false.
5612 */
5613void
5614xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5615 xmlXPathObjectPtr hay, needle;
5616
5617 CHECK_ARITY(2);
5618 CAST_TO_STRING;
5619 CHECK_TYPE(XPATH_STRING);
5620 needle = valuePop(ctxt);
5621 CAST_TO_STRING;
5622 hay = valuePop(ctxt);
5623 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5624 xmlXPathFreeObject(hay);
5625 xmlXPathFreeObject(needle);
5626 XP_ERROR(XPATH_INVALID_TYPE);
5627 }
5628 if (xmlStrstr(hay->stringval, needle->stringval))
5629 valuePush(ctxt, xmlXPathNewBoolean(1));
5630 else
5631 valuePush(ctxt, xmlXPathNewBoolean(0));
5632 xmlXPathFreeObject(hay);
5633 xmlXPathFreeObject(needle);
5634}
5635
5636/**
5637 * xmlXPathStartsWithFunction:
5638 * @ctxt: the XPath Parser context
5639 * @nargs: the number of arguments
5640 *
5641 * Implement the starts-with() XPath function
5642 * boolean starts-with(string, string)
5643 * The starts-with function returns true if the first argument string
5644 * starts with the second argument string, and otherwise returns false.
5645 */
5646void
5647xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5648 xmlXPathObjectPtr hay, needle;
5649 int n;
5650
5651 CHECK_ARITY(2);
5652 CAST_TO_STRING;
5653 CHECK_TYPE(XPATH_STRING);
5654 needle = valuePop(ctxt);
5655 CAST_TO_STRING;
5656 hay = valuePop(ctxt);
5657 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5658 xmlXPathFreeObject(hay);
5659 xmlXPathFreeObject(needle);
5660 XP_ERROR(XPATH_INVALID_TYPE);
5661 }
5662 n = xmlStrlen(needle->stringval);
5663 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5664 valuePush(ctxt, xmlXPathNewBoolean(0));
5665 else
5666 valuePush(ctxt, xmlXPathNewBoolean(1));
5667 xmlXPathFreeObject(hay);
5668 xmlXPathFreeObject(needle);
5669}
5670
5671/**
5672 * xmlXPathSubstringFunction:
5673 * @ctxt: the XPath Parser context
5674 * @nargs: the number of arguments
5675 *
5676 * Implement the substring() XPath function
5677 * string substring(string, number, number?)
5678 * The substring function returns the substring of the first argument
5679 * starting at the position specified in the second argument with
5680 * length specified in the third argument. For example,
5681 * substring("12345",2,3) returns "234". If the third argument is not
5682 * specified, it returns the substring starting at the position specified
5683 * in the second argument and continuing to the end of the string. For
5684 * example, substring("12345",2) returns "2345". More precisely, each
5685 * character in the string (see [3.6 Strings]) is considered to have a
5686 * numeric position: the position of the first character is 1, the position
5687 * of the second character is 2 and so on. The returned substring contains
5688 * those characters for which the position of the character is greater than
5689 * or equal to the second argument and, if the third argument is specified,
5690 * less than the sum of the second and third arguments; the comparisons
5691 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5692 * - substring("12345", 1.5, 2.6) returns "234"
5693 * - substring("12345", 0, 3) returns "12"
5694 * - substring("12345", 0 div 0, 3) returns ""
5695 * - substring("12345", 1, 0 div 0) returns ""
5696 * - substring("12345", -42, 1 div 0) returns "12345"
5697 * - substring("12345", -1 div 0, 1 div 0) returns ""
5698 */
5699void
5700xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5701 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005702 double le=0, in;
5703 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005704 xmlChar *ret;
5705
Owen Taylor3473f882001-02-23 17:55:21 +00005706 if (nargs < 2) {
5707 CHECK_ARITY(2);
5708 }
5709 if (nargs > 3) {
5710 CHECK_ARITY(3);
5711 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005712 /*
5713 * take care of possible last (position) argument
5714 */
Owen Taylor3473f882001-02-23 17:55:21 +00005715 if (nargs == 3) {
5716 CAST_TO_NUMBER;
5717 CHECK_TYPE(XPATH_NUMBER);
5718 len = valuePop(ctxt);
5719 le = len->floatval;
5720 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005721 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005722
Owen Taylor3473f882001-02-23 17:55:21 +00005723 CAST_TO_NUMBER;
5724 CHECK_TYPE(XPATH_NUMBER);
5725 start = valuePop(ctxt);
5726 in = start->floatval;
5727 xmlXPathFreeObject(start);
5728 CAST_TO_STRING;
5729 CHECK_TYPE(XPATH_STRING);
5730 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005731 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005732
Daniel Veillard97ac1312001-05-30 19:14:17 +00005733 /*
5734 * If last pos not present, calculate last position
5735 */
5736 if (nargs != 3)
5737 le = m;
5738
5739 /*
5740 * To meet our requirements, initial index calculations
5741 * must be done before we convert to integer format
5742 *
5743 * First we normalize indices
5744 */
5745 in -= 1.0;
5746 le += in;
5747 if (in < 0.0)
5748 in = 0.0;
5749 if (le > (double)m)
5750 le = (double)m;
5751
5752 /*
5753 * Now we go to integer form, rounding up
5754 */
Owen Taylor3473f882001-02-23 17:55:21 +00005755 i = (int) in;
5756 if (((double)i) != in) i++;
5757
Owen Taylor3473f882001-02-23 17:55:21 +00005758 l = (int) le;
5759 if (((double)l) != le) l++;
5760
Daniel Veillard97ac1312001-05-30 19:14:17 +00005761 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005762
5763 /* number of chars to copy */
5764 l -= i;
5765
Daniel Veillard97ac1312001-05-30 19:14:17 +00005766 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005767 if (ret == NULL)
5768 valuePush(ctxt, xmlXPathNewCString(""));
5769 else {
5770 valuePush(ctxt, xmlXPathNewString(ret));
5771 xmlFree(ret);
5772 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005773
Owen Taylor3473f882001-02-23 17:55:21 +00005774 xmlXPathFreeObject(str);
5775}
5776
5777/**
5778 * xmlXPathSubstringBeforeFunction:
5779 * @ctxt: the XPath Parser context
5780 * @nargs: the number of arguments
5781 *
5782 * Implement the substring-before() XPath function
5783 * string substring-before(string, string)
5784 * The substring-before function returns the substring of the first
5785 * argument string that precedes the first occurrence of the second
5786 * argument string in the first argument string, or the empty string
5787 * if the first argument string does not contain the second argument
5788 * string. For example, substring-before("1999/04/01","/") returns 1999.
5789 */
5790void
5791xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5792 xmlXPathObjectPtr str;
5793 xmlXPathObjectPtr find;
5794 xmlBufferPtr target;
5795 const xmlChar *point;
5796 int offset;
5797
5798 CHECK_ARITY(2);
5799 CAST_TO_STRING;
5800 find = valuePop(ctxt);
5801 CAST_TO_STRING;
5802 str = valuePop(ctxt);
5803
5804 target = xmlBufferCreate();
5805 if (target) {
5806 point = xmlStrstr(str->stringval, find->stringval);
5807 if (point) {
5808 offset = (int)(point - str->stringval);
5809 xmlBufferAdd(target, str->stringval, offset);
5810 }
5811 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5812 xmlBufferFree(target);
5813 }
5814
5815 xmlXPathFreeObject(str);
5816 xmlXPathFreeObject(find);
5817}
5818
5819/**
5820 * xmlXPathSubstringAfterFunction:
5821 * @ctxt: the XPath Parser context
5822 * @nargs: the number of arguments
5823 *
5824 * Implement the substring-after() XPath function
5825 * string substring-after(string, string)
5826 * The substring-after function returns the substring of the first
5827 * argument string that follows the first occurrence of the second
5828 * argument string in the first argument string, or the empty stringi
5829 * if the first argument string does not contain the second argument
5830 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5831 * and substring-after("1999/04/01","19") returns 99/04/01.
5832 */
5833void
5834xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5835 xmlXPathObjectPtr str;
5836 xmlXPathObjectPtr find;
5837 xmlBufferPtr target;
5838 const xmlChar *point;
5839 int offset;
5840
5841 CHECK_ARITY(2);
5842 CAST_TO_STRING;
5843 find = valuePop(ctxt);
5844 CAST_TO_STRING;
5845 str = valuePop(ctxt);
5846
5847 target = xmlBufferCreate();
5848 if (target) {
5849 point = xmlStrstr(str->stringval, find->stringval);
5850 if (point) {
5851 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5852 xmlBufferAdd(target, &str->stringval[offset],
5853 xmlStrlen(str->stringval) - offset);
5854 }
5855 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5856 xmlBufferFree(target);
5857 }
5858
5859 xmlXPathFreeObject(str);
5860 xmlXPathFreeObject(find);
5861}
5862
5863/**
5864 * xmlXPathNormalizeFunction:
5865 * @ctxt: the XPath Parser context
5866 * @nargs: the number of arguments
5867 *
5868 * Implement the normalize-space() XPath function
5869 * string normalize-space(string?)
5870 * The normalize-space function returns the argument string with white
5871 * space normalized by stripping leading and trailing whitespace
5872 * and replacing sequences of whitespace characters by a single
5873 * space. Whitespace characters are the same allowed by the S production
5874 * in XML. If the argument is omitted, it defaults to the context
5875 * node converted to a string, in other words the value of the context node.
5876 */
5877void
5878xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5879 xmlXPathObjectPtr obj = NULL;
5880 xmlChar *source = NULL;
5881 xmlBufferPtr target;
5882 xmlChar blank;
5883
5884 if (nargs == 0) {
5885 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005886 valuePush(ctxt,
5887 xmlXPathWrapString(
5888 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005889 nargs = 1;
5890 }
5891
5892 CHECK_ARITY(1);
5893 CAST_TO_STRING;
5894 CHECK_TYPE(XPATH_STRING);
5895 obj = valuePop(ctxt);
5896 source = obj->stringval;
5897
5898 target = xmlBufferCreate();
5899 if (target && source) {
5900
5901 /* Skip leading whitespaces */
5902 while (IS_BLANK(*source))
5903 source++;
5904
5905 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5906 blank = 0;
5907 while (*source) {
5908 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005909 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005910 } else {
5911 if (blank) {
5912 xmlBufferAdd(target, &blank, 1);
5913 blank = 0;
5914 }
5915 xmlBufferAdd(target, source, 1);
5916 }
5917 source++;
5918 }
5919
5920 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5921 xmlBufferFree(target);
5922 }
5923 xmlXPathFreeObject(obj);
5924}
5925
5926/**
5927 * xmlXPathTranslateFunction:
5928 * @ctxt: the XPath Parser context
5929 * @nargs: the number of arguments
5930 *
5931 * Implement the translate() XPath function
5932 * string translate(string, string, string)
5933 * The translate function returns the first argument string with
5934 * occurrences of characters in the second argument string replaced
5935 * by the character at the corresponding position in the third argument
5936 * string. For example, translate("bar","abc","ABC") returns the string
5937 * BAr. If there is a character in the second argument string with no
5938 * character at a corresponding position in the third argument string
5939 * (because the second argument string is longer than the third argument
5940 * string), then occurrences of that character in the first argument
5941 * string are removed. For example, translate("--aaa--","abc-","ABC")
5942 * returns "AAA". If a character occurs more than once in second
5943 * argument string, then the first occurrence determines the replacement
5944 * character. If the third argument string is longer than the second
5945 * argument string, then excess characters are ignored.
5946 */
5947void
5948xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005949 xmlXPathObjectPtr str;
5950 xmlXPathObjectPtr from;
5951 xmlXPathObjectPtr to;
5952 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005953 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005954 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005955 xmlChar *point;
5956 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005957
Daniel Veillarde043ee12001-04-16 14:08:07 +00005958 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005959
Daniel Veillarde043ee12001-04-16 14:08:07 +00005960 CAST_TO_STRING;
5961 to = valuePop(ctxt);
5962 CAST_TO_STRING;
5963 from = valuePop(ctxt);
5964 CAST_TO_STRING;
5965 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005966
Daniel Veillarde043ee12001-04-16 14:08:07 +00005967 target = xmlBufferCreate();
5968 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005969 max = xmlUTF8Strlen(to->stringval);
5970 for (cptr = str->stringval; (ch=*cptr); ) {
5971 offset = xmlUTF8Strloc(from->stringval, cptr);
5972 if (offset >= 0) {
5973 if (offset < max) {
5974 point = xmlUTF8Strpos(to->stringval, offset);
5975 if (point)
5976 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5977 }
5978 } else
5979 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5980
5981 /* Step to next character in input */
5982 cptr++;
5983 if ( ch & 0x80 ) {
5984 /* if not simple ascii, verify proper format */
5985 if ( (ch & 0xc0) != 0xc0 ) {
5986 xmlGenericError(xmlGenericErrorContext,
5987 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5988 break;
5989 }
5990 /* then skip over remaining bytes for this char */
5991 while ( (ch <<= 1) & 0x80 )
5992 if ( (*cptr++ & 0xc0) != 0x80 ) {
5993 xmlGenericError(xmlGenericErrorContext,
5994 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5995 break;
5996 }
5997 if (ch & 0x80) /* must have had error encountered */
5998 break;
5999 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006000 }
Owen Taylor3473f882001-02-23 17:55:21 +00006001 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006002 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6003 xmlBufferFree(target);
6004 xmlXPathFreeObject(str);
6005 xmlXPathFreeObject(from);
6006 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006007}
6008
6009/**
6010 * xmlXPathBooleanFunction:
6011 * @ctxt: the XPath Parser context
6012 * @nargs: the number of arguments
6013 *
6014 * Implement the boolean() XPath function
6015 * boolean boolean(object)
6016 * he boolean function converts its argument to a boolean as follows:
6017 * - a number is true if and only if it is neither positive or
6018 * negative zero nor NaN
6019 * - a node-set is true if and only if it is non-empty
6020 * - a string is true if and only if its length is non-zero
6021 */
6022void
6023xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6024 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006025
6026 CHECK_ARITY(1);
6027 cur = valuePop(ctxt);
6028 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006029 cur = xmlXPathConvertBoolean(cur);
6030 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006031}
6032
6033/**
6034 * xmlXPathNotFunction:
6035 * @ctxt: the XPath Parser context
6036 * @nargs: the number of arguments
6037 *
6038 * Implement the not() XPath function
6039 * boolean not(boolean)
6040 * The not function returns true if its argument is false,
6041 * and false otherwise.
6042 */
6043void
6044xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6045 CHECK_ARITY(1);
6046 CAST_TO_BOOLEAN;
6047 CHECK_TYPE(XPATH_BOOLEAN);
6048 ctxt->value->boolval = ! ctxt->value->boolval;
6049}
6050
6051/**
6052 * xmlXPathTrueFunction:
6053 * @ctxt: the XPath Parser context
6054 * @nargs: the number of arguments
6055 *
6056 * Implement the true() XPath function
6057 * boolean true()
6058 */
6059void
6060xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6061 CHECK_ARITY(0);
6062 valuePush(ctxt, xmlXPathNewBoolean(1));
6063}
6064
6065/**
6066 * xmlXPathFalseFunction:
6067 * @ctxt: the XPath Parser context
6068 * @nargs: the number of arguments
6069 *
6070 * Implement the false() XPath function
6071 * boolean false()
6072 */
6073void
6074xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6075 CHECK_ARITY(0);
6076 valuePush(ctxt, xmlXPathNewBoolean(0));
6077}
6078
6079/**
6080 * xmlXPathLangFunction:
6081 * @ctxt: the XPath Parser context
6082 * @nargs: the number of arguments
6083 *
6084 * Implement the lang() XPath function
6085 * boolean lang(string)
6086 * The lang function returns true or false depending on whether the
6087 * language of the context node as specified by xml:lang attributes
6088 * is the same as or is a sublanguage of the language specified by
6089 * the argument string. The language of the context node is determined
6090 * by the value of the xml:lang attribute on the context node, or, if
6091 * the context node has no xml:lang attribute, by the value of the
6092 * xml:lang attribute on the nearest ancestor of the context node that
6093 * has an xml:lang attribute. If there is no such attribute, then lang
6094 * returns false. If there is such an attribute, then lang returns
6095 * true if the attribute value is equal to the argument ignoring case,
6096 * or if there is some suffix starting with - such that the attribute
6097 * value is equal to the argument ignoring that suffix of the attribute
6098 * value and ignoring case.
6099 */
6100void
6101xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6102 xmlXPathObjectPtr val;
6103 const xmlChar *theLang;
6104 const xmlChar *lang;
6105 int ret = 0;
6106 int i;
6107
6108 CHECK_ARITY(1);
6109 CAST_TO_STRING;
6110 CHECK_TYPE(XPATH_STRING);
6111 val = valuePop(ctxt);
6112 lang = val->stringval;
6113 theLang = xmlNodeGetLang(ctxt->context->node);
6114 if ((theLang != NULL) && (lang != NULL)) {
6115 for (i = 0;lang[i] != 0;i++)
6116 if (toupper(lang[i]) != toupper(theLang[i]))
6117 goto not_equal;
6118 ret = 1;
6119 }
6120not_equal:
6121 xmlXPathFreeObject(val);
6122 valuePush(ctxt, xmlXPathNewBoolean(ret));
6123}
6124
6125/**
6126 * xmlXPathNumberFunction:
6127 * @ctxt: the XPath Parser context
6128 * @nargs: the number of arguments
6129 *
6130 * Implement the number() XPath function
6131 * number number(object?)
6132 */
6133void
6134xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6135 xmlXPathObjectPtr cur;
6136 double res;
6137
6138 if (nargs == 0) {
6139 if (ctxt->context->node == NULL) {
6140 valuePush(ctxt, xmlXPathNewFloat(0.0));
6141 } else {
6142 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6143
6144 res = xmlXPathStringEvalNumber(content);
6145 valuePush(ctxt, xmlXPathNewFloat(res));
6146 xmlFree(content);
6147 }
6148 return;
6149 }
6150
6151 CHECK_ARITY(1);
6152 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006153 cur = xmlXPathConvertNumber(cur);
6154 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006155}
6156
6157/**
6158 * xmlXPathSumFunction:
6159 * @ctxt: the XPath Parser context
6160 * @nargs: the number of arguments
6161 *
6162 * Implement the sum() XPath function
6163 * number sum(node-set)
6164 * The sum function returns the sum of the values of the nodes in
6165 * the argument node-set.
6166 */
6167void
6168xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6169 xmlXPathObjectPtr cur;
6170 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006171 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006172
6173 CHECK_ARITY(1);
6174 if ((ctxt->value == NULL) ||
6175 ((ctxt->value->type != XPATH_NODESET) &&
6176 (ctxt->value->type != XPATH_XSLT_TREE)))
6177 XP_ERROR(XPATH_INVALID_TYPE);
6178 cur = valuePop(ctxt);
6179
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006180 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006181 valuePush(ctxt, xmlXPathNewFloat(0.0));
6182 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006183 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6184 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006185 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006186 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006187 }
6188 xmlXPathFreeObject(cur);
6189}
6190
6191/**
6192 * xmlXPathFloorFunction:
6193 * @ctxt: the XPath Parser context
6194 * @nargs: the number of arguments
6195 *
6196 * Implement the floor() XPath function
6197 * number floor(number)
6198 * The floor function returns the largest (closest to positive infinity)
6199 * number that is not greater than the argument and that is an integer.
6200 */
6201void
6202xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6203 CHECK_ARITY(1);
6204 CAST_TO_NUMBER;
6205 CHECK_TYPE(XPATH_NUMBER);
6206#if 0
6207 ctxt->value->floatval = floor(ctxt->value->floatval);
6208#else
6209 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6210 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6211#endif
6212}
6213
6214/**
6215 * xmlXPathCeilingFunction:
6216 * @ctxt: the XPath Parser context
6217 * @nargs: the number of arguments
6218 *
6219 * Implement the ceiling() XPath function
6220 * number ceiling(number)
6221 * The ceiling function returns the smallest (closest to negative infinity)
6222 * number that is not less than the argument and that is an integer.
6223 */
6224void
6225xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6226 double f;
6227
6228 CHECK_ARITY(1);
6229 CAST_TO_NUMBER;
6230 CHECK_TYPE(XPATH_NUMBER);
6231
6232#if 0
6233 ctxt->value->floatval = ceil(ctxt->value->floatval);
6234#else
6235 f = (double)((int) ctxt->value->floatval);
6236 if (f != ctxt->value->floatval)
6237 ctxt->value->floatval = f + 1;
6238#endif
6239}
6240
6241/**
6242 * xmlXPathRoundFunction:
6243 * @ctxt: the XPath Parser context
6244 * @nargs: the number of arguments
6245 *
6246 * Implement the round() XPath function
6247 * number round(number)
6248 * The round function returns the number that is closest to the
6249 * argument and that is an integer. If there are two such numbers,
6250 * then the one that is even is returned.
6251 */
6252void
6253xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6254 double f;
6255
6256 CHECK_ARITY(1);
6257 CAST_TO_NUMBER;
6258 CHECK_TYPE(XPATH_NUMBER);
6259
6260 if ((ctxt->value->floatval == xmlXPathNAN) ||
6261 (ctxt->value->floatval == xmlXPathPINF) ||
6262 (ctxt->value->floatval == xmlXPathNINF) ||
6263 (ctxt->value->floatval == 0.0))
6264 return;
6265
6266#if 0
6267 f = floor(ctxt->value->floatval);
6268#else
6269 f = (double)((int) ctxt->value->floatval);
6270#endif
6271 if (ctxt->value->floatval < f + 0.5)
6272 ctxt->value->floatval = f;
6273 else
6274 ctxt->value->floatval = f + 1;
6275}
6276
6277/************************************************************************
6278 * *
6279 * The Parser *
6280 * *
6281 ************************************************************************/
6282
6283/*
6284 * a couple of forward declarations since we use a recursive call based
6285 * implementation.
6286 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006287static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006288static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006289static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006290#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006291static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6292#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006293#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006294static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006295#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006296static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6297 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006298
6299/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006300 * xmlXPathCurrentChar:
6301 * @ctxt: the XPath parser context
6302 * @cur: pointer to the beginning of the char
6303 * @len: pointer to the length of the char read
6304 *
6305 * The current char value, if using UTF-8 this may actaully span multiple
6306 * bytes in the input buffer.
6307 *
6308 * Returns the current char value and its lenght
6309 */
6310
6311static int
6312xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6313 unsigned char c;
6314 unsigned int val;
6315 const xmlChar *cur;
6316
6317 if (ctxt == NULL)
6318 return(0);
6319 cur = ctxt->cur;
6320
6321 /*
6322 * We are supposed to handle UTF8, check it's valid
6323 * From rfc2044: encoding of the Unicode values on UTF-8:
6324 *
6325 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6326 * 0000 0000-0000 007F 0xxxxxxx
6327 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6328 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6329 *
6330 * Check for the 0x110000 limit too
6331 */
6332 c = *cur;
6333 if (c & 0x80) {
6334 if ((cur[1] & 0xc0) != 0x80)
6335 goto encoding_error;
6336 if ((c & 0xe0) == 0xe0) {
6337
6338 if ((cur[2] & 0xc0) != 0x80)
6339 goto encoding_error;
6340 if ((c & 0xf0) == 0xf0) {
6341 if (((c & 0xf8) != 0xf0) ||
6342 ((cur[3] & 0xc0) != 0x80))
6343 goto encoding_error;
6344 /* 4-byte code */
6345 *len = 4;
6346 val = (cur[0] & 0x7) << 18;
6347 val |= (cur[1] & 0x3f) << 12;
6348 val |= (cur[2] & 0x3f) << 6;
6349 val |= cur[3] & 0x3f;
6350 } else {
6351 /* 3-byte code */
6352 *len = 3;
6353 val = (cur[0] & 0xf) << 12;
6354 val |= (cur[1] & 0x3f) << 6;
6355 val |= cur[2] & 0x3f;
6356 }
6357 } else {
6358 /* 2-byte code */
6359 *len = 2;
6360 val = (cur[0] & 0x1f) << 6;
6361 val |= cur[1] & 0x3f;
6362 }
6363 if (!IS_CHAR(val)) {
6364 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6365 }
6366 return(val);
6367 } else {
6368 /* 1-byte code */
6369 *len = 1;
6370 return((int) *cur);
6371 }
6372encoding_error:
6373 /*
6374 * If we detect an UTF8 error that probably mean that the
6375 * input encoding didn't get properly advertized in the
6376 * declaration header. Report the error and switch the encoding
6377 * to ISO-Latin-1 (if you don't like this policy, just declare the
6378 * encoding !)
6379 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006380 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006381 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006382}
6383
6384/**
Owen Taylor3473f882001-02-23 17:55:21 +00006385 * xmlXPathParseNCName:
6386 * @ctxt: the XPath Parser context
6387 *
6388 * parse an XML namespace non qualified name.
6389 *
6390 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6391 *
6392 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6393 * CombiningChar | Extender
6394 *
6395 * Returns the namespace name or NULL
6396 */
6397
6398xmlChar *
6399xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006400 const xmlChar *in;
6401 xmlChar *ret;
6402 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006403
Daniel Veillard2156a562001-04-28 12:24:34 +00006404 /*
6405 * Accelerator for simple ASCII names
6406 */
6407 in = ctxt->cur;
6408 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6409 ((*in >= 0x41) && (*in <= 0x5A)) ||
6410 (*in == '_')) {
6411 in++;
6412 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6413 ((*in >= 0x41) && (*in <= 0x5A)) ||
6414 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006415 (*in == '_') || (*in == '.') ||
6416 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006417 in++;
6418 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6419 (*in == '[') || (*in == ']') || (*in == ':') ||
6420 (*in == '@') || (*in == '*')) {
6421 count = in - ctxt->cur;
6422 if (count == 0)
6423 return(NULL);
6424 ret = xmlStrndup(ctxt->cur, count);
6425 ctxt->cur = in;
6426 return(ret);
6427 }
6428 }
6429 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006430}
6431
Daniel Veillard2156a562001-04-28 12:24:34 +00006432
Owen Taylor3473f882001-02-23 17:55:21 +00006433/**
6434 * xmlXPathParseQName:
6435 * @ctxt: the XPath Parser context
6436 * @prefix: a xmlChar **
6437 *
6438 * parse an XML qualified name
6439 *
6440 * [NS 5] QName ::= (Prefix ':')? LocalPart
6441 *
6442 * [NS 6] Prefix ::= NCName
6443 *
6444 * [NS 7] LocalPart ::= NCName
6445 *
6446 * Returns the function returns the local part, and prefix is updated
6447 * to get the Prefix if any.
6448 */
6449
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006450static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006451xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6452 xmlChar *ret = NULL;
6453
6454 *prefix = NULL;
6455 ret = xmlXPathParseNCName(ctxt);
6456 if (CUR == ':') {
6457 *prefix = ret;
6458 NEXT;
6459 ret = xmlXPathParseNCName(ctxt);
6460 }
6461 return(ret);
6462}
6463
6464/**
6465 * xmlXPathParseName:
6466 * @ctxt: the XPath Parser context
6467 *
6468 * parse an XML name
6469 *
6470 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6471 * CombiningChar | Extender
6472 *
6473 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6474 *
6475 * Returns the namespace name or NULL
6476 */
6477
6478xmlChar *
6479xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006480 const xmlChar *in;
6481 xmlChar *ret;
6482 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006483
Daniel Veillard61d80a22001-04-27 17:13:01 +00006484 /*
6485 * Accelerator for simple ASCII names
6486 */
6487 in = ctxt->cur;
6488 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6489 ((*in >= 0x41) && (*in <= 0x5A)) ||
6490 (*in == '_') || (*in == ':')) {
6491 in++;
6492 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6493 ((*in >= 0x41) && (*in <= 0x5A)) ||
6494 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006495 (*in == '_') || (*in == '-') ||
6496 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006497 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006498 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006499 count = in - ctxt->cur;
6500 ret = xmlStrndup(ctxt->cur, count);
6501 ctxt->cur = in;
6502 return(ret);
6503 }
6504 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006505 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006506}
6507
Daniel Veillard61d80a22001-04-27 17:13:01 +00006508static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006509xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006510 xmlChar buf[XML_MAX_NAMELEN + 5];
6511 int len = 0, l;
6512 int c;
6513
6514 /*
6515 * Handler for more complex cases
6516 */
6517 c = CUR_CHAR(l);
6518 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006519 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6520 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006521 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006522 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006523 return(NULL);
6524 }
6525
6526 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6527 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6528 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006529 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006530 (IS_COMBINING(c)) ||
6531 (IS_EXTENDER(c)))) {
6532 COPY_BUF(l,buf,len,c);
6533 NEXTL(l);
6534 c = CUR_CHAR(l);
6535 if (len >= XML_MAX_NAMELEN) {
6536 /*
6537 * Okay someone managed to make a huge name, so he's ready to pay
6538 * for the processing speed.
6539 */
6540 xmlChar *buffer;
6541 int max = len * 2;
6542
6543 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6544 if (buffer == NULL) {
6545 XP_ERROR0(XPATH_MEMORY_ERROR);
6546 }
6547 memcpy(buffer, buf, len);
6548 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6549 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006550 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006551 (IS_COMBINING(c)) ||
6552 (IS_EXTENDER(c))) {
6553 if (len + 10 > max) {
6554 max *= 2;
6555 buffer = (xmlChar *) xmlRealloc(buffer,
6556 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006557 if (buffer == NULL) {
6558 XP_ERROR0(XPATH_MEMORY_ERROR);
6559 }
6560 }
6561 COPY_BUF(l,buffer,len,c);
6562 NEXTL(l);
6563 c = CUR_CHAR(l);
6564 }
6565 buffer[len] = 0;
6566 return(buffer);
6567 }
6568 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006569 if (len == 0)
6570 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006571 return(xmlStrndup(buf, len));
6572}
Owen Taylor3473f882001-02-23 17:55:21 +00006573/**
6574 * xmlXPathStringEvalNumber:
6575 * @str: A string to scan
6576 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006577 * [30a] Float ::= Number ('e' Digits?)?
6578 *
Owen Taylor3473f882001-02-23 17:55:21 +00006579 * [30] Number ::= Digits ('.' Digits?)?
6580 * | '.' Digits
6581 * [31] Digits ::= [0-9]+
6582 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006583 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006584 * In complement of the Number expression, this function also handles
6585 * negative values : '-' Number.
6586 *
6587 * Returns the double value.
6588 */
6589double
6590xmlXPathStringEvalNumber(const xmlChar *str) {
6591 const xmlChar *cur = str;
6592 double ret = 0.0;
6593 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006594 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006595 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006596 int exponent = 0;
6597 int is_exponent_negative = 0;
6598
Owen Taylor3473f882001-02-23 17:55:21 +00006599 while (IS_BLANK(*cur)) cur++;
6600 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6601 return(xmlXPathNAN);
6602 }
6603 if (*cur == '-') {
6604 isneg = 1;
6605 cur++;
6606 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006607 /*
6608 * tmp is a workaroudn against a gcc compiler bug
6609 */
Owen Taylor3473f882001-02-23 17:55:21 +00006610 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006611 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006612 ok = 1;
6613 cur++;
6614 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006615 ret = (double) tmp;
6616
Owen Taylor3473f882001-02-23 17:55:21 +00006617 if (*cur == '.') {
6618 cur++;
6619 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6620 return(xmlXPathNAN);
6621 }
6622 while ((*cur >= '0') && (*cur <= '9')) {
6623 mult /= 10;
6624 ret = ret + (*cur - '0') * mult;
6625 cur++;
6626 }
6627 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006628 if ((*cur == 'e') || (*cur == 'E')) {
6629 cur++;
6630 if (*cur == '-') {
6631 is_exponent_negative = 1;
6632 cur++;
6633 }
6634 while ((*cur >= '0') && (*cur <= '9')) {
6635 exponent = exponent * 10 + (*cur - '0');
6636 cur++;
6637 }
6638 }
Owen Taylor3473f882001-02-23 17:55:21 +00006639 while (IS_BLANK(*cur)) cur++;
6640 if (*cur != 0) return(xmlXPathNAN);
6641 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006642 if (is_exponent_negative) exponent = -exponent;
6643 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006644 return(ret);
6645}
6646
6647/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006648 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006649 * @ctxt: the XPath Parser context
6650 *
6651 * [30] Number ::= Digits ('.' Digits?)?
6652 * | '.' Digits
6653 * [31] Digits ::= [0-9]+
6654 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006655 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006656 *
6657 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006658static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006659xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6660{
Owen Taylor3473f882001-02-23 17:55:21 +00006661 double ret = 0.0;
6662 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006663 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006664 int exponent = 0;
6665 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006666
6667 CHECK_ERROR;
6668 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6669 XP_ERROR(XPATH_NUMBER_ERROR);
6670 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006671 /*
6672 * Try to work around a gcc optimizer bug
6673 */
Owen Taylor3473f882001-02-23 17:55:21 +00006674 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006675 tmp = tmp * 10 + (CUR - '0');
6676 ok = 1;
6677 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006678 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006679 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006680 if (CUR == '.') {
6681 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006682 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6683 XP_ERROR(XPATH_NUMBER_ERROR);
6684 }
6685 while ((CUR >= '0') && (CUR <= '9')) {
6686 mult /= 10;
6687 ret = ret + (CUR - '0') * mult;
6688 NEXT;
6689 }
Owen Taylor3473f882001-02-23 17:55:21 +00006690 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006691 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006692 NEXT;
6693 if (CUR == '-') {
6694 is_exponent_negative = 1;
6695 NEXT;
6696 }
6697 while ((CUR >= '0') && (CUR <= '9')) {
6698 exponent = exponent * 10 + (CUR - '0');
6699 NEXT;
6700 }
6701 if (is_exponent_negative)
6702 exponent = -exponent;
6703 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006704 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006705 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006706 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006707}
6708
6709/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006710 * xmlXPathParseLiteral:
6711 * @ctxt: the XPath Parser context
6712 *
6713 * Parse a Literal
6714 *
6715 * [29] Literal ::= '"' [^"]* '"'
6716 * | "'" [^']* "'"
6717 *
6718 * Returns the value found or NULL in case of error
6719 */
6720static xmlChar *
6721xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6722 const xmlChar *q;
6723 xmlChar *ret = NULL;
6724
6725 if (CUR == '"') {
6726 NEXT;
6727 q = CUR_PTR;
6728 while ((IS_CHAR(CUR)) && (CUR != '"'))
6729 NEXT;
6730 if (!IS_CHAR(CUR)) {
6731 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6732 } else {
6733 ret = xmlStrndup(q, CUR_PTR - q);
6734 NEXT;
6735 }
6736 } else if (CUR == '\'') {
6737 NEXT;
6738 q = CUR_PTR;
6739 while ((IS_CHAR(CUR)) && (CUR != '\''))
6740 NEXT;
6741 if (!IS_CHAR(CUR)) {
6742 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6743 } else {
6744 ret = xmlStrndup(q, CUR_PTR - q);
6745 NEXT;
6746 }
6747 } else {
6748 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6749 }
6750 return(ret);
6751}
6752
6753/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006754 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006755 * @ctxt: the XPath Parser context
6756 *
6757 * Parse a Literal and push it on the stack.
6758 *
6759 * [29] Literal ::= '"' [^"]* '"'
6760 * | "'" [^']* "'"
6761 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006762 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006763 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006764static void
6765xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006766 const xmlChar *q;
6767 xmlChar *ret = NULL;
6768
6769 if (CUR == '"') {
6770 NEXT;
6771 q = CUR_PTR;
6772 while ((IS_CHAR(CUR)) && (CUR != '"'))
6773 NEXT;
6774 if (!IS_CHAR(CUR)) {
6775 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6776 } else {
6777 ret = xmlStrndup(q, CUR_PTR - q);
6778 NEXT;
6779 }
6780 } else if (CUR == '\'') {
6781 NEXT;
6782 q = CUR_PTR;
6783 while ((IS_CHAR(CUR)) && (CUR != '\''))
6784 NEXT;
6785 if (!IS_CHAR(CUR)) {
6786 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6787 } else {
6788 ret = xmlStrndup(q, CUR_PTR - q);
6789 NEXT;
6790 }
6791 } else {
6792 XP_ERROR(XPATH_START_LITERAL_ERROR);
6793 }
6794 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006795 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6796 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006797 xmlFree(ret);
6798}
6799
6800/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006801 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006802 * @ctxt: the XPath Parser context
6803 *
6804 * Parse a VariableReference, evaluate it and push it on the stack.
6805 *
6806 * The variable bindings consist of a mapping from variable names
6807 * to variable values. The value of a variable is an object, which
6808 * of any of the types that are possible for the value of an expression,
6809 * and may also be of additional types not specified here.
6810 *
6811 * Early evaluation is possible since:
6812 * The variable bindings [...] used to evaluate a subexpression are
6813 * always the same as those used to evaluate the containing expression.
6814 *
6815 * [36] VariableReference ::= '$' QName
6816 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006817static void
6818xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006819 xmlChar *name;
6820 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006821
6822 SKIP_BLANKS;
6823 if (CUR != '$') {
6824 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6825 }
6826 NEXT;
6827 name = xmlXPathParseQName(ctxt, &prefix);
6828 if (name == NULL) {
6829 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6830 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006831 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006832 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6833 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006834 SKIP_BLANKS;
6835}
6836
6837/**
6838 * xmlXPathIsNodeType:
6839 * @ctxt: the XPath Parser context
6840 * @name: a name string
6841 *
6842 * Is the name given a NodeType one.
6843 *
6844 * [38] NodeType ::= 'comment'
6845 * | 'text'
6846 * | 'processing-instruction'
6847 * | 'node'
6848 *
6849 * Returns 1 if true 0 otherwise
6850 */
6851int
6852xmlXPathIsNodeType(const xmlChar *name) {
6853 if (name == NULL)
6854 return(0);
6855
6856 if (xmlStrEqual(name, BAD_CAST "comment"))
6857 return(1);
6858 if (xmlStrEqual(name, BAD_CAST "text"))
6859 return(1);
6860 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6861 return(1);
6862 if (xmlStrEqual(name, BAD_CAST "node"))
6863 return(1);
6864 return(0);
6865}
6866
6867/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006868 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006869 * @ctxt: the XPath Parser context
6870 *
6871 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6872 * [17] Argument ::= Expr
6873 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006874 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006875 * pushed on the stack
6876 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006877static void
6878xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006879 xmlChar *name;
6880 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006881 int nbargs = 0;
6882
6883 name = xmlXPathParseQName(ctxt, &prefix);
6884 if (name == NULL) {
6885 XP_ERROR(XPATH_EXPR_ERROR);
6886 }
6887 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006888#ifdef DEBUG_EXPR
6889 if (prefix == NULL)
6890 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6891 name);
6892 else
6893 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6894 prefix, name);
6895#endif
6896
Owen Taylor3473f882001-02-23 17:55:21 +00006897 if (CUR != '(') {
6898 XP_ERROR(XPATH_EXPR_ERROR);
6899 }
6900 NEXT;
6901 SKIP_BLANKS;
6902
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006903 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006904 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006905 int op1 = ctxt->comp->last;
6906 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006907 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006908 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006909 nbargs++;
6910 if (CUR == ')') break;
6911 if (CUR != ',') {
6912 XP_ERROR(XPATH_EXPR_ERROR);
6913 }
6914 NEXT;
6915 SKIP_BLANKS;
6916 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006917 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6918 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006919 NEXT;
6920 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006921}
6922
6923/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006924 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006925 * @ctxt: the XPath Parser context
6926 *
6927 * [15] PrimaryExpr ::= VariableReference
6928 * | '(' Expr ')'
6929 * | Literal
6930 * | Number
6931 * | FunctionCall
6932 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006933 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006934 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006935static void
6936xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006937 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006938 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006939 else if (CUR == '(') {
6940 NEXT;
6941 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006942 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006943 if (CUR != ')') {
6944 XP_ERROR(XPATH_EXPR_ERROR);
6945 }
6946 NEXT;
6947 SKIP_BLANKS;
6948 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006949 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006950 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006951 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006952 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006953 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006954 }
6955 SKIP_BLANKS;
6956}
6957
6958/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006959 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006960 * @ctxt: the XPath Parser context
6961 *
6962 * [20] FilterExpr ::= PrimaryExpr
6963 * | FilterExpr Predicate
6964 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006965 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006966 * Square brackets are used to filter expressions in the same way that
6967 * they are used in location paths. It is an error if the expression to
6968 * be filtered does not evaluate to a node-set. The context node list
6969 * used for evaluating the expression in square brackets is the node-set
6970 * to be filtered listed in document order.
6971 */
6972
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006973static void
6974xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6975 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006976 CHECK_ERROR;
6977 SKIP_BLANKS;
6978
6979 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006980 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006981 SKIP_BLANKS;
6982 }
6983
6984
6985}
6986
6987/**
6988 * xmlXPathScanName:
6989 * @ctxt: the XPath Parser context
6990 *
6991 * Trickery: parse an XML name but without consuming the input flow
6992 * Needed to avoid insanity in the parser state.
6993 *
6994 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6995 * CombiningChar | Extender
6996 *
6997 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6998 *
6999 * [6] Names ::= Name (S Name)*
7000 *
7001 * Returns the Name parsed or NULL
7002 */
7003
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007004static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007005xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7006 xmlChar buf[XML_MAX_NAMELEN];
7007 int len = 0;
7008
7009 SKIP_BLANKS;
7010 if (!IS_LETTER(CUR) && (CUR != '_') &&
7011 (CUR != ':')) {
7012 return(NULL);
7013 }
7014
7015 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7016 (NXT(len) == '.') || (NXT(len) == '-') ||
7017 (NXT(len) == '_') || (NXT(len) == ':') ||
7018 (IS_COMBINING(NXT(len))) ||
7019 (IS_EXTENDER(NXT(len)))) {
7020 buf[len] = NXT(len);
7021 len++;
7022 if (len >= XML_MAX_NAMELEN) {
7023 xmlGenericError(xmlGenericErrorContext,
7024 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7025 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7026 (NXT(len) == '.') || (NXT(len) == '-') ||
7027 (NXT(len) == '_') || (NXT(len) == ':') ||
7028 (IS_COMBINING(NXT(len))) ||
7029 (IS_EXTENDER(NXT(len))))
7030 len++;
7031 break;
7032 }
7033 }
7034 return(xmlStrndup(buf, len));
7035}
7036
7037/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007038 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007039 * @ctxt: the XPath Parser context
7040 *
7041 * [19] PathExpr ::= LocationPath
7042 * | FilterExpr
7043 * | FilterExpr '/' RelativeLocationPath
7044 * | FilterExpr '//' RelativeLocationPath
7045 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007046 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007047 * The / operator and // operators combine an arbitrary expression
7048 * and a relative location path. It is an error if the expression
7049 * does not evaluate to a node-set.
7050 * The / operator does composition in the same way as when / is
7051 * used in a location path. As in location paths, // is short for
7052 * /descendant-or-self::node()/.
7053 */
7054
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007055static void
7056xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007057 int lc = 1; /* Should we branch to LocationPath ? */
7058 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7059
7060 SKIP_BLANKS;
7061 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7062 (CUR == '\'') || (CUR == '"')) {
7063 lc = 0;
7064 } else if (CUR == '*') {
7065 /* relative or absolute location path */
7066 lc = 1;
7067 } else if (CUR == '/') {
7068 /* relative or absolute location path */
7069 lc = 1;
7070 } else if (CUR == '@') {
7071 /* relative abbreviated attribute location path */
7072 lc = 1;
7073 } else if (CUR == '.') {
7074 /* relative abbreviated attribute location path */
7075 lc = 1;
7076 } else {
7077 /*
7078 * Problem is finding if we have a name here whether it's:
7079 * - a nodetype
7080 * - a function call in which case it's followed by '('
7081 * - an axis in which case it's followed by ':'
7082 * - a element name
7083 * We do an a priori analysis here rather than having to
7084 * maintain parsed token content through the recursive function
7085 * calls. This looks uglier but makes the code quite easier to
7086 * read/write/debug.
7087 */
7088 SKIP_BLANKS;
7089 name = xmlXPathScanName(ctxt);
7090 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7091#ifdef DEBUG_STEP
7092 xmlGenericError(xmlGenericErrorContext,
7093 "PathExpr: Axis\n");
7094#endif
7095 lc = 1;
7096 xmlFree(name);
7097 } else if (name != NULL) {
7098 int len =xmlStrlen(name);
7099 int blank = 0;
7100
7101
7102 while (NXT(len) != 0) {
7103 if (NXT(len) == '/') {
7104 /* element name */
7105#ifdef DEBUG_STEP
7106 xmlGenericError(xmlGenericErrorContext,
7107 "PathExpr: AbbrRelLocation\n");
7108#endif
7109 lc = 1;
7110 break;
7111 } else if (IS_BLANK(NXT(len))) {
7112 /* skip to next */
7113 blank = 1;
7114 } else if (NXT(len) == ':') {
7115#ifdef DEBUG_STEP
7116 xmlGenericError(xmlGenericErrorContext,
7117 "PathExpr: AbbrRelLocation\n");
7118#endif
7119 lc = 1;
7120 break;
7121 } else if ((NXT(len) == '(')) {
7122 /* Note Type or Function */
7123 if (xmlXPathIsNodeType(name)) {
7124#ifdef DEBUG_STEP
7125 xmlGenericError(xmlGenericErrorContext,
7126 "PathExpr: Type search\n");
7127#endif
7128 lc = 1;
7129 } else {
7130#ifdef DEBUG_STEP
7131 xmlGenericError(xmlGenericErrorContext,
7132 "PathExpr: function call\n");
7133#endif
7134 lc = 0;
7135 }
7136 break;
7137 } else if ((NXT(len) == '[')) {
7138 /* element name */
7139#ifdef DEBUG_STEP
7140 xmlGenericError(xmlGenericErrorContext,
7141 "PathExpr: AbbrRelLocation\n");
7142#endif
7143 lc = 1;
7144 break;
7145 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7146 (NXT(len) == '=')) {
7147 lc = 1;
7148 break;
7149 } else {
7150 lc = 1;
7151 break;
7152 }
7153 len++;
7154 }
7155 if (NXT(len) == 0) {
7156#ifdef DEBUG_STEP
7157 xmlGenericError(xmlGenericErrorContext,
7158 "PathExpr: AbbrRelLocation\n");
7159#endif
7160 /* element name */
7161 lc = 1;
7162 }
7163 xmlFree(name);
7164 } else {
7165 /* make sure all cases are covered explicitely */
7166 XP_ERROR(XPATH_EXPR_ERROR);
7167 }
7168 }
7169
7170 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007171 if (CUR == '/') {
7172 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7173 } else {
7174 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007175 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007176 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007177 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007178 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007179 CHECK_ERROR;
7180 if ((CUR == '/') && (NXT(1) == '/')) {
7181 SKIP(2);
7182 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007183
7184 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7185 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7186 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7187
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007188 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007189 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007190 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007191 }
7192 }
7193 SKIP_BLANKS;
7194}
7195
7196/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007197 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007198 * @ctxt: the XPath Parser context
7199 *
7200 * [18] UnionExpr ::= PathExpr
7201 * | UnionExpr '|' PathExpr
7202 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007203 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007204 */
7205
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007206static void
7207xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7208 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007209 CHECK_ERROR;
7210 SKIP_BLANKS;
7211 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007212 int op1 = ctxt->comp->last;
7213 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007214
7215 NEXT;
7216 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007217 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007218
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007219 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7220
Owen Taylor3473f882001-02-23 17:55:21 +00007221 SKIP_BLANKS;
7222 }
Owen Taylor3473f882001-02-23 17:55:21 +00007223}
7224
7225/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007226 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007227 * @ctxt: the XPath Parser context
7228 *
7229 * [27] UnaryExpr ::= UnionExpr
7230 * | '-' UnaryExpr
7231 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007232 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007233 */
7234
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007235static void
7236xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007237 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007238 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007239
7240 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007241 while (CUR == '-') {
7242 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007243 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007244 NEXT;
7245 SKIP_BLANKS;
7246 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007247
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007248 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007249 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007250 if (found) {
7251 if (minus)
7252 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7253 else
7254 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007255 }
7256}
7257
7258/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007259 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007260 * @ctxt: the XPath Parser context
7261 *
7262 * [26] MultiplicativeExpr ::= UnaryExpr
7263 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7264 * | MultiplicativeExpr 'div' UnaryExpr
7265 * | MultiplicativeExpr 'mod' UnaryExpr
7266 * [34] MultiplyOperator ::= '*'
7267 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007268 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007269 */
7270
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007271static void
7272xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7273 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007274 CHECK_ERROR;
7275 SKIP_BLANKS;
7276 while ((CUR == '*') ||
7277 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7278 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7279 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007280 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007281
7282 if (CUR == '*') {
7283 op = 0;
7284 NEXT;
7285 } else if (CUR == 'd') {
7286 op = 1;
7287 SKIP(3);
7288 } else if (CUR == 'm') {
7289 op = 2;
7290 SKIP(3);
7291 }
7292 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007293 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007294 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007295 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007296 SKIP_BLANKS;
7297 }
7298}
7299
7300/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007301 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007302 * @ctxt: the XPath Parser context
7303 *
7304 * [25] AdditiveExpr ::= MultiplicativeExpr
7305 * | AdditiveExpr '+' MultiplicativeExpr
7306 * | AdditiveExpr '-' MultiplicativeExpr
7307 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007308 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007309 */
7310
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007311static void
7312xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007313
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007314 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007315 CHECK_ERROR;
7316 SKIP_BLANKS;
7317 while ((CUR == '+') || (CUR == '-')) {
7318 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007319 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007320
7321 if (CUR == '+') plus = 1;
7322 else plus = 0;
7323 NEXT;
7324 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007325 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007326 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007327 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007328 SKIP_BLANKS;
7329 }
7330}
7331
7332/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007333 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007334 * @ctxt: the XPath Parser context
7335 *
7336 * [24] RelationalExpr ::= AdditiveExpr
7337 * | RelationalExpr '<' AdditiveExpr
7338 * | RelationalExpr '>' AdditiveExpr
7339 * | RelationalExpr '<=' AdditiveExpr
7340 * | RelationalExpr '>=' AdditiveExpr
7341 *
7342 * A <= B > C is allowed ? Answer from James, yes with
7343 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7344 * which is basically what got implemented.
7345 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007346 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007347 * on the stack
7348 */
7349
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007350static void
7351xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7352 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007353 CHECK_ERROR;
7354 SKIP_BLANKS;
7355 while ((CUR == '<') ||
7356 (CUR == '>') ||
7357 ((CUR == '<') && (NXT(1) == '=')) ||
7358 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007359 int inf, strict;
7360 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007361
7362 if (CUR == '<') inf = 1;
7363 else inf = 0;
7364 if (NXT(1) == '=') strict = 0;
7365 else strict = 1;
7366 NEXT;
7367 if (!strict) NEXT;
7368 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007369 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007370 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007371 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007372 SKIP_BLANKS;
7373 }
7374}
7375
7376/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007377 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007378 * @ctxt: the XPath Parser context
7379 *
7380 * [23] EqualityExpr ::= RelationalExpr
7381 * | EqualityExpr '=' RelationalExpr
7382 * | EqualityExpr '!=' RelationalExpr
7383 *
7384 * A != B != C is allowed ? Answer from James, yes with
7385 * (RelationalExpr = RelationalExpr) = RelationalExpr
7386 * (RelationalExpr != RelationalExpr) != RelationalExpr
7387 * which is basically what got implemented.
7388 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007389 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007390 *
7391 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007392static void
7393xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7394 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007395 CHECK_ERROR;
7396 SKIP_BLANKS;
7397 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007398 int eq;
7399 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007400
7401 if (CUR == '=') eq = 1;
7402 else eq = 0;
7403 NEXT;
7404 if (!eq) NEXT;
7405 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007406 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007407 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007408 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007409 SKIP_BLANKS;
7410 }
7411}
7412
7413/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007414 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007415 * @ctxt: the XPath Parser context
7416 *
7417 * [22] AndExpr ::= EqualityExpr
7418 * | AndExpr 'and' EqualityExpr
7419 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007420 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007421 *
7422 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007423static void
7424xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7425 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007426 CHECK_ERROR;
7427 SKIP_BLANKS;
7428 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007429 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007430 SKIP(3);
7431 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007432 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007433 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007434 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007435 SKIP_BLANKS;
7436 }
7437}
7438
7439/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007440 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007441 * @ctxt: the XPath Parser context
7442 *
7443 * [14] Expr ::= OrExpr
7444 * [21] OrExpr ::= AndExpr
7445 * | OrExpr 'or' AndExpr
7446 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007447 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007448 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007449static void
7450xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7451 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007452 CHECK_ERROR;
7453 SKIP_BLANKS;
7454 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007455 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007456 SKIP(2);
7457 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007458 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007459 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007460 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7461 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007462 SKIP_BLANKS;
7463 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007464 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7465 /* more ops could be optimized too */
7466 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7467 }
Owen Taylor3473f882001-02-23 17:55:21 +00007468}
7469
7470/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007471 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007472 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007473 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007474 *
7475 * [8] Predicate ::= '[' PredicateExpr ']'
7476 * [9] PredicateExpr ::= Expr
7477 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007478 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007479 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007480static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007481xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007482 int op1 = ctxt->comp->last;
7483
7484 SKIP_BLANKS;
7485 if (CUR != '[') {
7486 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7487 }
7488 NEXT;
7489 SKIP_BLANKS;
7490
7491 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007492 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007493 CHECK_ERROR;
7494
7495 if (CUR != ']') {
7496 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7497 }
7498
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007499 if (filter)
7500 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7501 else
7502 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007503
7504 NEXT;
7505 SKIP_BLANKS;
7506}
7507
7508/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007509 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007510 * @ctxt: the XPath Parser context
7511 * @test: pointer to a xmlXPathTestVal
7512 * @type: pointer to a xmlXPathTypeVal
7513 * @prefix: placeholder for a possible name prefix
7514 *
7515 * [7] NodeTest ::= NameTest
7516 * | NodeType '(' ')'
7517 * | 'processing-instruction' '(' Literal ')'
7518 *
7519 * [37] NameTest ::= '*'
7520 * | NCName ':' '*'
7521 * | QName
7522 * [38] NodeType ::= 'comment'
7523 * | 'text'
7524 * | 'processing-instruction'
7525 * | 'node'
7526 *
7527 * Returns the name found and update @test, @type and @prefix appropriately
7528 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007529static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007530xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7531 xmlXPathTypeVal *type, const xmlChar **prefix,
7532 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007533 int blanks;
7534
7535 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7536 STRANGE;
7537 return(NULL);
7538 }
7539 *type = 0;
7540 *test = 0;
7541 *prefix = NULL;
7542 SKIP_BLANKS;
7543
7544 if ((name == NULL) && (CUR == '*')) {
7545 /*
7546 * All elements
7547 */
7548 NEXT;
7549 *test = NODE_TEST_ALL;
7550 return(NULL);
7551 }
7552
7553 if (name == NULL)
7554 name = xmlXPathParseNCName(ctxt);
7555 if (name == NULL) {
7556 XP_ERROR0(XPATH_EXPR_ERROR);
7557 }
7558
7559 blanks = IS_BLANK(CUR);
7560 SKIP_BLANKS;
7561 if (CUR == '(') {
7562 NEXT;
7563 /*
7564 * NodeType or PI search
7565 */
7566 if (xmlStrEqual(name, BAD_CAST "comment"))
7567 *type = NODE_TYPE_COMMENT;
7568 else if (xmlStrEqual(name, BAD_CAST "node"))
7569 *type = NODE_TYPE_NODE;
7570 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7571 *type = NODE_TYPE_PI;
7572 else if (xmlStrEqual(name, BAD_CAST "text"))
7573 *type = NODE_TYPE_TEXT;
7574 else {
7575 if (name != NULL)
7576 xmlFree(name);
7577 XP_ERROR0(XPATH_EXPR_ERROR);
7578 }
7579
7580 *test = NODE_TEST_TYPE;
7581
7582 SKIP_BLANKS;
7583 if (*type == NODE_TYPE_PI) {
7584 /*
7585 * Specific case: search a PI by name.
7586 */
Owen Taylor3473f882001-02-23 17:55:21 +00007587 if (name != NULL)
7588 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007589 name = NULL;
7590 if (CUR != ')') {
7591 name = xmlXPathParseLiteral(ctxt);
7592 CHECK_ERROR 0;
7593 SKIP_BLANKS;
7594 }
Owen Taylor3473f882001-02-23 17:55:21 +00007595 }
7596 if (CUR != ')') {
7597 if (name != NULL)
7598 xmlFree(name);
7599 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7600 }
7601 NEXT;
7602 return(name);
7603 }
7604 *test = NODE_TEST_NAME;
7605 if ((!blanks) && (CUR == ':')) {
7606 NEXT;
7607
7608 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007609 * Since currently the parser context don't have a
7610 * namespace list associated:
7611 * The namespace name for this prefix can be computed
7612 * only at evaluation time. The compilation is done
7613 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007614 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007615#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007616 *prefix = xmlXPathNsLookup(ctxt->context, name);
7617 if (name != NULL)
7618 xmlFree(name);
7619 if (*prefix == NULL) {
7620 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7621 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007622#else
7623 *prefix = name;
7624#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007625
7626 if (CUR == '*') {
7627 /*
7628 * All elements
7629 */
7630 NEXT;
7631 *test = NODE_TEST_ALL;
7632 return(NULL);
7633 }
7634
7635 name = xmlXPathParseNCName(ctxt);
7636 if (name == NULL) {
7637 XP_ERROR0(XPATH_EXPR_ERROR);
7638 }
7639 }
7640 return(name);
7641}
7642
7643/**
7644 * xmlXPathIsAxisName:
7645 * @name: a preparsed name token
7646 *
7647 * [6] AxisName ::= 'ancestor'
7648 * | 'ancestor-or-self'
7649 * | 'attribute'
7650 * | 'child'
7651 * | 'descendant'
7652 * | 'descendant-or-self'
7653 * | 'following'
7654 * | 'following-sibling'
7655 * | 'namespace'
7656 * | 'parent'
7657 * | 'preceding'
7658 * | 'preceding-sibling'
7659 * | 'self'
7660 *
7661 * Returns the axis or 0
7662 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007663static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007664xmlXPathIsAxisName(const xmlChar *name) {
7665 xmlXPathAxisVal ret = 0;
7666 switch (name[0]) {
7667 case 'a':
7668 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7669 ret = AXIS_ANCESTOR;
7670 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7671 ret = AXIS_ANCESTOR_OR_SELF;
7672 if (xmlStrEqual(name, BAD_CAST "attribute"))
7673 ret = AXIS_ATTRIBUTE;
7674 break;
7675 case 'c':
7676 if (xmlStrEqual(name, BAD_CAST "child"))
7677 ret = AXIS_CHILD;
7678 break;
7679 case 'd':
7680 if (xmlStrEqual(name, BAD_CAST "descendant"))
7681 ret = AXIS_DESCENDANT;
7682 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7683 ret = AXIS_DESCENDANT_OR_SELF;
7684 break;
7685 case 'f':
7686 if (xmlStrEqual(name, BAD_CAST "following"))
7687 ret = AXIS_FOLLOWING;
7688 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7689 ret = AXIS_FOLLOWING_SIBLING;
7690 break;
7691 case 'n':
7692 if (xmlStrEqual(name, BAD_CAST "namespace"))
7693 ret = AXIS_NAMESPACE;
7694 break;
7695 case 'p':
7696 if (xmlStrEqual(name, BAD_CAST "parent"))
7697 ret = AXIS_PARENT;
7698 if (xmlStrEqual(name, BAD_CAST "preceding"))
7699 ret = AXIS_PRECEDING;
7700 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7701 ret = AXIS_PRECEDING_SIBLING;
7702 break;
7703 case 's':
7704 if (xmlStrEqual(name, BAD_CAST "self"))
7705 ret = AXIS_SELF;
7706 break;
7707 }
7708 return(ret);
7709}
7710
7711/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007712 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007713 * @ctxt: the XPath Parser context
7714 *
7715 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7716 * | AbbreviatedStep
7717 *
7718 * [12] AbbreviatedStep ::= '.' | '..'
7719 *
7720 * [5] AxisSpecifier ::= AxisName '::'
7721 * | AbbreviatedAxisSpecifier
7722 *
7723 * [13] AbbreviatedAxisSpecifier ::= '@'?
7724 *
7725 * Modified for XPtr range support as:
7726 *
7727 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7728 * | AbbreviatedStep
7729 * | 'range-to' '(' Expr ')' Predicate*
7730 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007731 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007732 * A location step of . is short for self::node(). This is
7733 * particularly useful in conjunction with //. For example, the
7734 * location path .//para is short for
7735 * self::node()/descendant-or-self::node()/child::para
7736 * and so will select all para descendant elements of the context
7737 * node.
7738 * Similarly, a location step of .. is short for parent::node().
7739 * For example, ../title is short for parent::node()/child::title
7740 * and so will select the title children of the parent of the context
7741 * node.
7742 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007743static void
7744xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007745#ifdef LIBXML_XPTR_ENABLED
7746 int rangeto = 0;
7747 int op2 = -1;
7748#endif
7749
Owen Taylor3473f882001-02-23 17:55:21 +00007750 SKIP_BLANKS;
7751 if ((CUR == '.') && (NXT(1) == '.')) {
7752 SKIP(2);
7753 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007754 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7755 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007756 } else if (CUR == '.') {
7757 NEXT;
7758 SKIP_BLANKS;
7759 } else {
7760 xmlChar *name = NULL;
7761 const xmlChar *prefix = NULL;
7762 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007763 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007764 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007765 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007766
7767 /*
7768 * The modification needed for XPointer change to the production
7769 */
7770#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007771 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007772 name = xmlXPathParseNCName(ctxt);
7773 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007774 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007775 xmlFree(name);
7776 SKIP_BLANKS;
7777 if (CUR != '(') {
7778 XP_ERROR(XPATH_EXPR_ERROR);
7779 }
7780 NEXT;
7781 SKIP_BLANKS;
7782
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007783 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007784 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007785 CHECK_ERROR;
7786
7787 SKIP_BLANKS;
7788 if (CUR != ')') {
7789 XP_ERROR(XPATH_EXPR_ERROR);
7790 }
7791 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007792 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007793 goto eval_predicates;
7794 }
7795 }
7796#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007797 if (CUR == '*') {
7798 axis = AXIS_CHILD;
7799 } else {
7800 if (name == NULL)
7801 name = xmlXPathParseNCName(ctxt);
7802 if (name != NULL) {
7803 axis = xmlXPathIsAxisName(name);
7804 if (axis != 0) {
7805 SKIP_BLANKS;
7806 if ((CUR == ':') && (NXT(1) == ':')) {
7807 SKIP(2);
7808 xmlFree(name);
7809 name = NULL;
7810 } else {
7811 /* an element name can conflict with an axis one :-\ */
7812 axis = AXIS_CHILD;
7813 }
Owen Taylor3473f882001-02-23 17:55:21 +00007814 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007815 axis = AXIS_CHILD;
7816 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007817 } else if (CUR == '@') {
7818 NEXT;
7819 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007820 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007821 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007822 }
Owen Taylor3473f882001-02-23 17:55:21 +00007823 }
7824
7825 CHECK_ERROR;
7826
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007827 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007828 if (test == 0)
7829 return;
7830
7831#ifdef DEBUG_STEP
7832 xmlGenericError(xmlGenericErrorContext,
7833 "Basis : computing new set\n");
7834#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007835
Owen Taylor3473f882001-02-23 17:55:21 +00007836#ifdef DEBUG_STEP
7837 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007838 if (ctxt->value == NULL)
7839 xmlGenericError(xmlGenericErrorContext, "no value\n");
7840 else if (ctxt->value->nodesetval == NULL)
7841 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7842 else
7843 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007844#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007845
7846eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007847 op1 = ctxt->comp->last;
7848 ctxt->comp->last = -1;
7849
Owen Taylor3473f882001-02-23 17:55:21 +00007850 SKIP_BLANKS;
7851 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007852 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007853 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007854
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007855#ifdef LIBXML_XPTR_ENABLED
7856 if (rangeto) {
7857 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7858 } else
7859#endif
7860 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7861 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007862
Owen Taylor3473f882001-02-23 17:55:21 +00007863 }
7864#ifdef DEBUG_STEP
7865 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007866 if (ctxt->value == NULL)
7867 xmlGenericError(xmlGenericErrorContext, "no value\n");
7868 else if (ctxt->value->nodesetval == NULL)
7869 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7870 else
7871 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7872 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007873#endif
7874}
7875
7876/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007877 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007878 * @ctxt: the XPath Parser context
7879 *
7880 * [3] RelativeLocationPath ::= Step
7881 * | RelativeLocationPath '/' Step
7882 * | AbbreviatedRelativeLocationPath
7883 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007885 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007886 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007887static void
Owen Taylor3473f882001-02-23 17:55:21 +00007888#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007889xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007890#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007891xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007892#endif
7893(xmlXPathParserContextPtr ctxt) {
7894 SKIP_BLANKS;
7895 if ((CUR == '/') && (NXT(1) == '/')) {
7896 SKIP(2);
7897 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007898 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7899 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007900 } else if (CUR == '/') {
7901 NEXT;
7902 SKIP_BLANKS;
7903 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007904 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007905 SKIP_BLANKS;
7906 while (CUR == '/') {
7907 if ((CUR == '/') && (NXT(1) == '/')) {
7908 SKIP(2);
7909 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007910 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007911 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007912 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007913 } else if (CUR == '/') {
7914 NEXT;
7915 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007916 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007917 }
7918 SKIP_BLANKS;
7919 }
7920}
7921
7922/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007923 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007924 * @ctxt: the XPath Parser context
7925 *
7926 * [1] LocationPath ::= RelativeLocationPath
7927 * | AbsoluteLocationPath
7928 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7929 * | AbbreviatedAbsoluteLocationPath
7930 * [10] AbbreviatedAbsoluteLocationPath ::=
7931 * '//' RelativeLocationPath
7932 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007933 * Compile a location path
7934 *
Owen Taylor3473f882001-02-23 17:55:21 +00007935 * // is short for /descendant-or-self::node()/. For example,
7936 * //para is short for /descendant-or-self::node()/child::para and
7937 * so will select any para element in the document (even a para element
7938 * that is a document element will be selected by //para since the
7939 * document element node is a child of the root node); div//para is
7940 * short for div/descendant-or-self::node()/child::para and so will
7941 * select all para descendants of div children.
7942 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007943static void
7944xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007945 SKIP_BLANKS;
7946 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007947 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007948 } else {
7949 while (CUR == '/') {
7950 if ((CUR == '/') && (NXT(1) == '/')) {
7951 SKIP(2);
7952 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007953 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7954 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007955 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007956 } else if (CUR == '/') {
7957 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007958 SKIP_BLANKS;
7959 if ((CUR != 0 ) &&
7960 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7961 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007962 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007963 }
7964 }
7965 }
7966}
7967
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007968/************************************************************************
7969 * *
7970 * XPath precompiled expression evaluation *
7971 * *
7972 ************************************************************************/
7973
Daniel Veillardf06307e2001-07-03 10:35:50 +00007974static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007975xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7976
7977/**
7978 * xmlXPathNodeCollectAndTest:
7979 * @ctxt: the XPath Parser context
7980 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007981 * @first: pointer to the first element in document order
7982 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007983 *
7984 * This is the function implementing a step: based on the current list
7985 * of nodes, it builds up a new list, looking at all nodes under that
7986 * axis and selecting them it also do the predicate filtering
7987 *
7988 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007989 *
7990 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007991 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007992static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007993xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007994 xmlXPathStepOpPtr op,
7995 xmlNodePtr * first, xmlNodePtr * last)
7996{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007997 xmlXPathAxisVal axis = op->value;
7998 xmlXPathTestVal test = op->value2;
7999 xmlXPathTypeVal type = op->value3;
8000 const xmlChar *prefix = op->value4;
8001 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008002 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008003
8004#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008005 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008006#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008007 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008008 xmlNodeSetPtr ret, list;
8009 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008010 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008011 xmlNodePtr cur = NULL;
8012 xmlXPathObjectPtr obj;
8013 xmlNodeSetPtr nodelist;
8014 xmlNodePtr tmp;
8015
Daniel Veillardf06307e2001-07-03 10:35:50 +00008016 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008017 obj = valuePop(ctxt);
8018 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008019 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008020 URI = xmlXPathNsLookup(ctxt->context, prefix);
8021 if (URI == NULL)
8022 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008023 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008024#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008025 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008026#endif
8027 switch (axis) {
8028 case AXIS_ANCESTOR:
8029#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008030 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008031#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008032 first = NULL;
8033 next = xmlXPathNextAncestor;
8034 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008035 case AXIS_ANCESTOR_OR_SELF:
8036#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008037 xmlGenericError(xmlGenericErrorContext,
8038 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008039#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008040 first = NULL;
8041 next = xmlXPathNextAncestorOrSelf;
8042 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008043 case AXIS_ATTRIBUTE:
8044#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008045 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008046#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008047 first = NULL;
8048 last = NULL;
8049 next = xmlXPathNextAttribute;
8050 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008051 case AXIS_CHILD:
8052#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008053 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008054#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008055 last = NULL;
8056 next = xmlXPathNextChild;
8057 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008058 case AXIS_DESCENDANT:
8059#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008060 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008061#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008062 last = NULL;
8063 next = xmlXPathNextDescendant;
8064 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008065 case AXIS_DESCENDANT_OR_SELF:
8066#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008067 xmlGenericError(xmlGenericErrorContext,
8068 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008069#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008070 last = NULL;
8071 next = xmlXPathNextDescendantOrSelf;
8072 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008073 case AXIS_FOLLOWING:
8074#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008075 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008076#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008077 last = NULL;
8078 next = xmlXPathNextFollowing;
8079 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008080 case AXIS_FOLLOWING_SIBLING:
8081#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008082 xmlGenericError(xmlGenericErrorContext,
8083 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008084#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008085 last = NULL;
8086 next = xmlXPathNextFollowingSibling;
8087 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008088 case AXIS_NAMESPACE:
8089#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008090 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008091#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008092 first = NULL;
8093 last = NULL;
8094 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8095 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008096 case AXIS_PARENT:
8097#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008098 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008099#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008100 first = NULL;
8101 next = xmlXPathNextParent;
8102 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008103 case AXIS_PRECEDING:
8104#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008105 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008106#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008107 first = NULL;
8108 next = xmlXPathNextPrecedingInternal;
8109 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008110 case AXIS_PRECEDING_SIBLING:
8111#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008112 xmlGenericError(xmlGenericErrorContext,
8113 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008114#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008115 first = NULL;
8116 next = xmlXPathNextPrecedingSibling;
8117 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008118 case AXIS_SELF:
8119#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008120 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008121#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008122 first = NULL;
8123 last = NULL;
8124 next = xmlXPathNextSelf;
8125 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008126 }
8127 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008128 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008129
8130 nodelist = obj->nodesetval;
8131 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008132 xmlXPathFreeObject(obj);
8133 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8134 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008135 }
8136 addNode = xmlXPathNodeSetAddUnique;
8137 ret = NULL;
8138#ifdef DEBUG_STEP
8139 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008140 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008141 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008142 case NODE_TEST_NONE:
8143 xmlGenericError(xmlGenericErrorContext,
8144 " searching for none !!!\n");
8145 break;
8146 case NODE_TEST_TYPE:
8147 xmlGenericError(xmlGenericErrorContext,
8148 " searching for type %d\n", type);
8149 break;
8150 case NODE_TEST_PI:
8151 xmlGenericError(xmlGenericErrorContext,
8152 " searching for PI !!!\n");
8153 break;
8154 case NODE_TEST_ALL:
8155 xmlGenericError(xmlGenericErrorContext,
8156 " searching for *\n");
8157 break;
8158 case NODE_TEST_NS:
8159 xmlGenericError(xmlGenericErrorContext,
8160 " searching for namespace %s\n",
8161 prefix);
8162 break;
8163 case NODE_TEST_NAME:
8164 xmlGenericError(xmlGenericErrorContext,
8165 " searching for name %s\n", name);
8166 if (prefix != NULL)
8167 xmlGenericError(xmlGenericErrorContext,
8168 " with namespace %s\n", prefix);
8169 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008170 }
8171 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8172#endif
8173 /*
8174 * 2.3 Node Tests
8175 * - For the attribute axis, the principal node type is attribute.
8176 * - For the namespace axis, the principal node type is namespace.
8177 * - For other axes, the principal node type is element.
8178 *
8179 * A node test * is true for any node of the
8180 * principal node type. For example, child::* willi
8181 * select all element children of the context node
8182 */
8183 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008184 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008185 ctxt->context->node = nodelist->nodeTab[i];
8186
Daniel Veillardf06307e2001-07-03 10:35:50 +00008187 cur = NULL;
8188 list = xmlXPathNodeSetCreate(NULL);
8189 do {
8190 cur = next(ctxt, cur);
8191 if (cur == NULL)
8192 break;
8193 if ((first != NULL) && (*first == cur))
8194 break;
8195 if (((t % 256) == 0) &&
8196 (first != NULL) && (*first != NULL) &&
8197 (xmlXPathCmpNodes(*first, cur) >= 0))
8198 break;
8199 if ((last != NULL) && (*last == cur))
8200 break;
8201 if (((t % 256) == 0) &&
8202 (last != NULL) && (*last != NULL) &&
8203 (xmlXPathCmpNodes(cur, *last) >= 0))
8204 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008205 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008206#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008207 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8208#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008209 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008210 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008211 ctxt->context->node = tmp;
8212 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008213 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008214 if ((cur->type == type) ||
8215 ((type == NODE_TYPE_NODE) &&
8216 ((cur->type == XML_DOCUMENT_NODE) ||
8217 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8218 (cur->type == XML_ELEMENT_NODE) ||
8219 (cur->type == XML_PI_NODE) ||
8220 (cur->type == XML_COMMENT_NODE) ||
8221 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008222 (cur->type == XML_TEXT_NODE))) ||
8223 ((type == NODE_TYPE_TEXT) &&
8224 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008225#ifdef DEBUG_STEP
8226 n++;
8227#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008228 addNode(list, cur);
8229 }
8230 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008231 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008232 if (cur->type == XML_PI_NODE) {
8233 if ((name != NULL) &&
8234 (!xmlStrEqual(name, cur->name)))
8235 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008236#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008237 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008238#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008239 addNode(list, cur);
8240 }
8241 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008242 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008243 if (axis == AXIS_ATTRIBUTE) {
8244 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008245#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008246 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008247#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008248 addNode(list, cur);
8249 }
8250 } else if (axis == AXIS_NAMESPACE) {
8251 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008252#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008253 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008254#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008255 addNode(list, cur);
8256 }
8257 } else {
8258 if (cur->type == XML_ELEMENT_NODE) {
8259 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008260#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008261 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008262#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008263 addNode(list, cur);
8264 } else if ((cur->ns != NULL) &&
8265 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008266#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008267 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008268#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008269 addNode(list, cur);
8270 }
8271 }
8272 }
8273 break;
8274 case NODE_TEST_NS:{
8275 TODO;
8276 break;
8277 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008278 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008279 switch (cur->type) {
8280 case XML_ELEMENT_NODE:
8281 if (xmlStrEqual(name, cur->name)) {
8282 if (prefix == NULL) {
8283 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008284#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008285 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008286#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008287 addNode(list, cur);
8288 }
8289 } else {
8290 if ((cur->ns != NULL) &&
8291 (xmlStrEqual(URI,
8292 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008293#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008294 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008295#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008296 addNode(list, cur);
8297 }
8298 }
8299 }
8300 break;
8301 case XML_ATTRIBUTE_NODE:{
8302 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008303
Daniel Veillardf06307e2001-07-03 10:35:50 +00008304 if (xmlStrEqual(name, attr->name)) {
8305 if (prefix == NULL) {
8306 if ((attr->ns == NULL) ||
8307 (attr->ns->prefix == NULL)) {
8308#ifdef DEBUG_STEP
8309 n++;
8310#endif
8311 addNode(list,
8312 (xmlNodePtr) attr);
8313 }
8314 } else {
8315 if ((attr->ns != NULL) &&
8316 (xmlStrEqual(URI,
8317 attr->ns->
8318 href))) {
8319#ifdef DEBUG_STEP
8320 n++;
8321#endif
8322 addNode(list,
8323 (xmlNodePtr) attr);
8324 }
8325 }
8326 }
8327 break;
8328 }
8329 case XML_NAMESPACE_DECL:
8330 if (cur->type == XML_NAMESPACE_DECL) {
8331 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008332
Daniel Veillardf06307e2001-07-03 10:35:50 +00008333 if ((ns->prefix != NULL) && (name != NULL)
8334 && (xmlStrEqual(ns->prefix, name))) {
8335#ifdef DEBUG_STEP
8336 n++;
8337#endif
8338 addNode(list, cur);
8339 }
8340 }
8341 break;
8342 default:
8343 break;
8344 }
8345 break;
8346 break;
8347 }
8348 } while (cur != NULL);
8349
8350 /*
8351 * If there is some predicate filtering do it now
8352 */
8353 if (op->ch2 != -1) {
8354 xmlXPathObjectPtr obj2;
8355
8356 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8357 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8358 CHECK_TYPE0(XPATH_NODESET);
8359 obj2 = valuePop(ctxt);
8360 list = obj2->nodesetval;
8361 obj2->nodesetval = NULL;
8362 xmlXPathFreeObject(obj2);
8363 }
8364 if (ret == NULL) {
8365 ret = list;
8366 } else {
8367 ret = xmlXPathNodeSetMerge(ret, list);
8368 xmlXPathFreeNodeSet(list);
8369 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008370 }
8371 ctxt->context->node = tmp;
8372#ifdef DEBUG_STEP
8373 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008374 "\nExamined %d nodes, found %d nodes at that step\n",
8375 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008376#endif
8377 xmlXPathFreeObject(obj);
8378 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008379 return(t);
8380}
8381
8382/**
8383 * xmlXPathNodeCollectAndTestNth:
8384 * @ctxt: the XPath Parser context
8385 * @op: the XPath precompiled step operation
8386 * @indx: the index to collect
8387 * @first: pointer to the first element in document order
8388 * @last: pointer to the last element in document order
8389 *
8390 * This is the function implementing a step: based on the current list
8391 * of nodes, it builds up a new list, looking at all nodes under that
8392 * axis and selecting them it also do the predicate filtering
8393 *
8394 * Pushes the new NodeSet resulting from the search.
8395 * Returns the number of node traversed
8396 */
8397static int
8398xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8399 xmlXPathStepOpPtr op, int indx,
8400 xmlNodePtr * first, xmlNodePtr * last)
8401{
8402 xmlXPathAxisVal axis = op->value;
8403 xmlXPathTestVal test = op->value2;
8404 xmlXPathTypeVal type = op->value3;
8405 const xmlChar *prefix = op->value4;
8406 const xmlChar *name = op->value5;
8407 const xmlChar *URI = NULL;
8408 int n = 0, t = 0;
8409
8410 int i;
8411 xmlNodeSetPtr list;
8412 xmlXPathTraversalFunction next = NULL;
8413 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8414 xmlNodePtr cur = NULL;
8415 xmlXPathObjectPtr obj;
8416 xmlNodeSetPtr nodelist;
8417 xmlNodePtr tmp;
8418
8419 CHECK_TYPE0(XPATH_NODESET);
8420 obj = valuePop(ctxt);
8421 addNode = xmlXPathNodeSetAdd;
8422 if (prefix != NULL) {
8423 URI = xmlXPathNsLookup(ctxt->context, prefix);
8424 if (URI == NULL)
8425 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8426 }
8427#ifdef DEBUG_STEP_NTH
8428 xmlGenericError(xmlGenericErrorContext, "new step : ");
8429 if (first != NULL) {
8430 if (*first != NULL)
8431 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8432 (*first)->name);
8433 else
8434 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8435 }
8436 if (last != NULL) {
8437 if (*last != NULL)
8438 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8439 (*last)->name);
8440 else
8441 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8442 }
8443#endif
8444 switch (axis) {
8445 case AXIS_ANCESTOR:
8446#ifdef DEBUG_STEP_NTH
8447 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8448#endif
8449 first = NULL;
8450 next = xmlXPathNextAncestor;
8451 break;
8452 case AXIS_ANCESTOR_OR_SELF:
8453#ifdef DEBUG_STEP_NTH
8454 xmlGenericError(xmlGenericErrorContext,
8455 "axis 'ancestors-or-self' ");
8456#endif
8457 first = NULL;
8458 next = xmlXPathNextAncestorOrSelf;
8459 break;
8460 case AXIS_ATTRIBUTE:
8461#ifdef DEBUG_STEP_NTH
8462 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8463#endif
8464 first = NULL;
8465 last = NULL;
8466 next = xmlXPathNextAttribute;
8467 break;
8468 case AXIS_CHILD:
8469#ifdef DEBUG_STEP_NTH
8470 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8471#endif
8472 last = NULL;
8473 next = xmlXPathNextChild;
8474 break;
8475 case AXIS_DESCENDANT:
8476#ifdef DEBUG_STEP_NTH
8477 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8478#endif
8479 last = NULL;
8480 next = xmlXPathNextDescendant;
8481 break;
8482 case AXIS_DESCENDANT_OR_SELF:
8483#ifdef DEBUG_STEP_NTH
8484 xmlGenericError(xmlGenericErrorContext,
8485 "axis 'descendant-or-self' ");
8486#endif
8487 last = NULL;
8488 next = xmlXPathNextDescendantOrSelf;
8489 break;
8490 case AXIS_FOLLOWING:
8491#ifdef DEBUG_STEP_NTH
8492 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8493#endif
8494 last = NULL;
8495 next = xmlXPathNextFollowing;
8496 break;
8497 case AXIS_FOLLOWING_SIBLING:
8498#ifdef DEBUG_STEP_NTH
8499 xmlGenericError(xmlGenericErrorContext,
8500 "axis 'following-siblings' ");
8501#endif
8502 last = NULL;
8503 next = xmlXPathNextFollowingSibling;
8504 break;
8505 case AXIS_NAMESPACE:
8506#ifdef DEBUG_STEP_NTH
8507 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8508#endif
8509 last = NULL;
8510 first = NULL;
8511 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8512 break;
8513 case AXIS_PARENT:
8514#ifdef DEBUG_STEP_NTH
8515 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8516#endif
8517 first = NULL;
8518 next = xmlXPathNextParent;
8519 break;
8520 case AXIS_PRECEDING:
8521#ifdef DEBUG_STEP_NTH
8522 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8523#endif
8524 first = NULL;
8525 next = xmlXPathNextPrecedingInternal;
8526 break;
8527 case AXIS_PRECEDING_SIBLING:
8528#ifdef DEBUG_STEP_NTH
8529 xmlGenericError(xmlGenericErrorContext,
8530 "axis 'preceding-sibling' ");
8531#endif
8532 first = NULL;
8533 next = xmlXPathNextPrecedingSibling;
8534 break;
8535 case AXIS_SELF:
8536#ifdef DEBUG_STEP_NTH
8537 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8538#endif
8539 first = NULL;
8540 last = NULL;
8541 next = xmlXPathNextSelf;
8542 break;
8543 }
8544 if (next == NULL)
8545 return(0);
8546
8547 nodelist = obj->nodesetval;
8548 if (nodelist == NULL) {
8549 xmlXPathFreeObject(obj);
8550 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8551 return(0);
8552 }
8553 addNode = xmlXPathNodeSetAddUnique;
8554#ifdef DEBUG_STEP_NTH
8555 xmlGenericError(xmlGenericErrorContext,
8556 " context contains %d nodes\n", nodelist->nodeNr);
8557 switch (test) {
8558 case NODE_TEST_NONE:
8559 xmlGenericError(xmlGenericErrorContext,
8560 " searching for none !!!\n");
8561 break;
8562 case NODE_TEST_TYPE:
8563 xmlGenericError(xmlGenericErrorContext,
8564 " searching for type %d\n", type);
8565 break;
8566 case NODE_TEST_PI:
8567 xmlGenericError(xmlGenericErrorContext,
8568 " searching for PI !!!\n");
8569 break;
8570 case NODE_TEST_ALL:
8571 xmlGenericError(xmlGenericErrorContext,
8572 " searching for *\n");
8573 break;
8574 case NODE_TEST_NS:
8575 xmlGenericError(xmlGenericErrorContext,
8576 " searching for namespace %s\n",
8577 prefix);
8578 break;
8579 case NODE_TEST_NAME:
8580 xmlGenericError(xmlGenericErrorContext,
8581 " searching for name %s\n", name);
8582 if (prefix != NULL)
8583 xmlGenericError(xmlGenericErrorContext,
8584 " with namespace %s\n", prefix);
8585 break;
8586 }
8587 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8588#endif
8589 /*
8590 * 2.3 Node Tests
8591 * - For the attribute axis, the principal node type is attribute.
8592 * - For the namespace axis, the principal node type is namespace.
8593 * - For other axes, the principal node type is element.
8594 *
8595 * A node test * is true for any node of the
8596 * principal node type. For example, child::* willi
8597 * select all element children of the context node
8598 */
8599 tmp = ctxt->context->node;
8600 list = xmlXPathNodeSetCreate(NULL);
8601 for (i = 0; i < nodelist->nodeNr; i++) {
8602 ctxt->context->node = nodelist->nodeTab[i];
8603
8604 cur = NULL;
8605 n = 0;
8606 do {
8607 cur = next(ctxt, cur);
8608 if (cur == NULL)
8609 break;
8610 if ((first != NULL) && (*first == cur))
8611 break;
8612 if (((t % 256) == 0) &&
8613 (first != NULL) && (*first != NULL) &&
8614 (xmlXPathCmpNodes(*first, cur) >= 0))
8615 break;
8616 if ((last != NULL) && (*last == cur))
8617 break;
8618 if (((t % 256) == 0) &&
8619 (last != NULL) && (*last != NULL) &&
8620 (xmlXPathCmpNodes(cur, *last) >= 0))
8621 break;
8622 t++;
8623 switch (test) {
8624 case NODE_TEST_NONE:
8625 ctxt->context->node = tmp;
8626 STRANGE return(0);
8627 case NODE_TEST_TYPE:
8628 if ((cur->type == type) ||
8629 ((type == NODE_TYPE_NODE) &&
8630 ((cur->type == XML_DOCUMENT_NODE) ||
8631 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8632 (cur->type == XML_ELEMENT_NODE) ||
8633 (cur->type == XML_PI_NODE) ||
8634 (cur->type == XML_COMMENT_NODE) ||
8635 (cur->type == XML_CDATA_SECTION_NODE) ||
8636 (cur->type == XML_TEXT_NODE)))) {
8637 n++;
8638 if (n == indx)
8639 addNode(list, cur);
8640 }
8641 break;
8642 case NODE_TEST_PI:
8643 if (cur->type == XML_PI_NODE) {
8644 if ((name != NULL) &&
8645 (!xmlStrEqual(name, cur->name)))
8646 break;
8647 n++;
8648 if (n == indx)
8649 addNode(list, cur);
8650 }
8651 break;
8652 case NODE_TEST_ALL:
8653 if (axis == AXIS_ATTRIBUTE) {
8654 if (cur->type == XML_ATTRIBUTE_NODE) {
8655 n++;
8656 if (n == indx)
8657 addNode(list, cur);
8658 }
8659 } else if (axis == AXIS_NAMESPACE) {
8660 if (cur->type == XML_NAMESPACE_DECL) {
8661 n++;
8662 if (n == indx)
8663 addNode(list, cur);
8664 }
8665 } else {
8666 if (cur->type == XML_ELEMENT_NODE) {
8667 if (prefix == NULL) {
8668 n++;
8669 if (n == indx)
8670 addNode(list, cur);
8671 } else if ((cur->ns != NULL) &&
8672 (xmlStrEqual(URI, cur->ns->href))) {
8673 n++;
8674 if (n == indx)
8675 addNode(list, cur);
8676 }
8677 }
8678 }
8679 break;
8680 case NODE_TEST_NS:{
8681 TODO;
8682 break;
8683 }
8684 case NODE_TEST_NAME:
8685 switch (cur->type) {
8686 case XML_ELEMENT_NODE:
8687 if (xmlStrEqual(name, cur->name)) {
8688 if (prefix == NULL) {
8689 if (cur->ns == NULL) {
8690 n++;
8691 if (n == indx)
8692 addNode(list, cur);
8693 }
8694 } else {
8695 if ((cur->ns != NULL) &&
8696 (xmlStrEqual(URI,
8697 cur->ns->href))) {
8698 n++;
8699 if (n == indx)
8700 addNode(list, cur);
8701 }
8702 }
8703 }
8704 break;
8705 case XML_ATTRIBUTE_NODE:{
8706 xmlAttrPtr attr = (xmlAttrPtr) cur;
8707
8708 if (xmlStrEqual(name, attr->name)) {
8709 if (prefix == NULL) {
8710 if ((attr->ns == NULL) ||
8711 (attr->ns->prefix == NULL)) {
8712 n++;
8713 if (n == indx)
8714 addNode(list, cur);
8715 }
8716 } else {
8717 if ((attr->ns != NULL) &&
8718 (xmlStrEqual(URI,
8719 attr->ns->
8720 href))) {
8721 n++;
8722 if (n == indx)
8723 addNode(list, cur);
8724 }
8725 }
8726 }
8727 break;
8728 }
8729 case XML_NAMESPACE_DECL:
8730 if (cur->type == XML_NAMESPACE_DECL) {
8731 xmlNsPtr ns = (xmlNsPtr) cur;
8732
8733 if ((ns->prefix != NULL) && (name != NULL)
8734 && (xmlStrEqual(ns->prefix, name))) {
8735 n++;
8736 if (n == indx)
8737 addNode(list, cur);
8738 }
8739 }
8740 break;
8741 default:
8742 break;
8743 }
8744 break;
8745 break;
8746 }
8747 } while (n < indx);
8748 }
8749 ctxt->context->node = tmp;
8750#ifdef DEBUG_STEP_NTH
8751 xmlGenericError(xmlGenericErrorContext,
8752 "\nExamined %d nodes, found %d nodes at that step\n",
8753 t, list->nodeNr);
8754#endif
8755 xmlXPathFreeObject(obj);
8756 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8757 return(t);
8758}
8759
8760/**
8761 * xmlXPathCompOpEvalFirst:
8762 * @ctxt: the XPath parser context with the compiled expression
8763 * @op: an XPath compiled operation
8764 * @first: the first elem found so far
8765 *
8766 * Evaluate the Precompiled XPath operation searching only the first
8767 * element in document order
8768 *
8769 * Returns the number of examined objects.
8770 */
8771static int
8772xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8773 xmlXPathStepOpPtr op, xmlNodePtr * first)
8774{
8775 int total = 0, cur;
8776 xmlXPathCompExprPtr comp;
8777 xmlXPathObjectPtr arg1, arg2;
8778
8779 comp = ctxt->comp;
8780 switch (op->op) {
8781 case XPATH_OP_END:
8782 return (0);
8783 case XPATH_OP_UNION:
8784 total =
8785 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8786 first);
8787 if ((ctxt->value != NULL)
8788 && (ctxt->value->type == XPATH_NODESET)
8789 && (ctxt->value->nodesetval != NULL)
8790 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8791 /*
8792 * limit tree traversing to first node in the result
8793 */
8794 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8795 *first = ctxt->value->nodesetval->nodeTab[0];
8796 }
8797 cur =
8798 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8799 first);
8800 CHECK_TYPE0(XPATH_NODESET);
8801 arg2 = valuePop(ctxt);
8802
8803 CHECK_TYPE0(XPATH_NODESET);
8804 arg1 = valuePop(ctxt);
8805
8806 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8807 arg2->nodesetval);
8808 valuePush(ctxt, arg1);
8809 xmlXPathFreeObject(arg2);
8810 /* optimizer */
8811 if (total > cur)
8812 xmlXPathCompSwap(op);
8813 return (total + cur);
8814 case XPATH_OP_ROOT:
8815 xmlXPathRoot(ctxt);
8816 return (0);
8817 case XPATH_OP_NODE:
8818 if (op->ch1 != -1)
8819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8820 if (op->ch2 != -1)
8821 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8822 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8823 return (total);
8824 case XPATH_OP_RESET:
8825 if (op->ch1 != -1)
8826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8827 if (op->ch2 != -1)
8828 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8829 ctxt->context->node = NULL;
8830 return (total);
8831 case XPATH_OP_COLLECT:{
8832 if (op->ch1 == -1)
8833 return (total);
8834
8835 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8836
8837 /*
8838 * Optimization for [n] selection where n is a number
8839 */
8840 if ((op->ch2 != -1) &&
8841 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8842 (comp->steps[op->ch2].ch1 == -1) &&
8843 (comp->steps[op->ch2].ch2 != -1) &&
8844 (comp->steps[comp->steps[op->ch2].ch2].op ==
8845 XPATH_OP_VALUE)) {
8846 xmlXPathObjectPtr val;
8847
8848 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8849 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8850 int indx = (int) val->floatval;
8851
8852 if (val->floatval == (float) indx) {
8853 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8854 first, NULL);
8855 return (total);
8856 }
8857 }
8858 }
8859 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8860 return (total);
8861 }
8862 case XPATH_OP_VALUE:
8863 valuePush(ctxt,
8864 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8865 return (0);
8866 case XPATH_OP_SORT:
8867 if (op->ch1 != -1)
8868 total +=
8869 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8870 first);
8871 if ((ctxt->value != NULL)
8872 && (ctxt->value->type == XPATH_NODESET)
8873 && (ctxt->value->nodesetval != NULL))
8874 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8875 return (total);
8876 default:
8877 return (xmlXPathCompOpEval(ctxt, op));
8878 }
8879}
8880
8881/**
8882 * xmlXPathCompOpEvalLast:
8883 * @ctxt: the XPath parser context with the compiled expression
8884 * @op: an XPath compiled operation
8885 * @last: the last elem found so far
8886 *
8887 * Evaluate the Precompiled XPath operation searching only the last
8888 * element in document order
8889 *
8890 * Returns the number of node traversed
8891 */
8892static int
8893xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8894 xmlNodePtr * last)
8895{
8896 int total = 0, cur;
8897 xmlXPathCompExprPtr comp;
8898 xmlXPathObjectPtr arg1, arg2;
8899
8900 comp = ctxt->comp;
8901 switch (op->op) {
8902 case XPATH_OP_END:
8903 return (0);
8904 case XPATH_OP_UNION:
8905 total =
8906 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8907 if ((ctxt->value != NULL)
8908 && (ctxt->value->type == XPATH_NODESET)
8909 && (ctxt->value->nodesetval != NULL)
8910 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8911 /*
8912 * limit tree traversing to first node in the result
8913 */
8914 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8915 *last =
8916 ctxt->value->nodesetval->nodeTab[ctxt->value->
8917 nodesetval->nodeNr -
8918 1];
8919 }
8920 cur =
8921 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8922 if ((ctxt->value != NULL)
8923 && (ctxt->value->type == XPATH_NODESET)
8924 && (ctxt->value->nodesetval != NULL)
8925 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8926 }
8927 CHECK_TYPE0(XPATH_NODESET);
8928 arg2 = valuePop(ctxt);
8929
8930 CHECK_TYPE0(XPATH_NODESET);
8931 arg1 = valuePop(ctxt);
8932
8933 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8934 arg2->nodesetval);
8935 valuePush(ctxt, arg1);
8936 xmlXPathFreeObject(arg2);
8937 /* optimizer */
8938 if (total > cur)
8939 xmlXPathCompSwap(op);
8940 return (total + cur);
8941 case XPATH_OP_ROOT:
8942 xmlXPathRoot(ctxt);
8943 return (0);
8944 case XPATH_OP_NODE:
8945 if (op->ch1 != -1)
8946 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8947 if (op->ch2 != -1)
8948 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8949 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8950 return (total);
8951 case XPATH_OP_RESET:
8952 if (op->ch1 != -1)
8953 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8954 if (op->ch2 != -1)
8955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8956 ctxt->context->node = NULL;
8957 return (total);
8958 case XPATH_OP_COLLECT:{
8959 if (op->ch1 == -1)
8960 return (0);
8961
8962 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8963
8964 /*
8965 * Optimization for [n] selection where n is a number
8966 */
8967 if ((op->ch2 != -1) &&
8968 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8969 (comp->steps[op->ch2].ch1 == -1) &&
8970 (comp->steps[op->ch2].ch2 != -1) &&
8971 (comp->steps[comp->steps[op->ch2].ch2].op ==
8972 XPATH_OP_VALUE)) {
8973 xmlXPathObjectPtr val;
8974
8975 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8976 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8977 int indx = (int) val->floatval;
8978
8979 if (val->floatval == (float) indx) {
8980 total +=
8981 xmlXPathNodeCollectAndTestNth(ctxt, op,
8982 indx, NULL,
8983 last);
8984 return (total);
8985 }
8986 }
8987 }
8988 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8989 return (total);
8990 }
8991 case XPATH_OP_VALUE:
8992 valuePush(ctxt,
8993 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8994 return (0);
8995 case XPATH_OP_SORT:
8996 if (op->ch1 != -1)
8997 total +=
8998 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8999 last);
9000 if ((ctxt->value != NULL)
9001 && (ctxt->value->type == XPATH_NODESET)
9002 && (ctxt->value->nodesetval != NULL))
9003 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9004 return (total);
9005 default:
9006 return (xmlXPathCompOpEval(ctxt, op));
9007 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009008}
9009
Owen Taylor3473f882001-02-23 17:55:21 +00009010/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009011 * xmlXPathCompOpEval:
9012 * @ctxt: the XPath parser context with the compiled expression
9013 * @op: an XPath compiled operation
9014 *
9015 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009016 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009017 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009018static int
9019xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9020{
9021 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009022 int equal, ret;
9023 xmlXPathCompExprPtr comp;
9024 xmlXPathObjectPtr arg1, arg2;
9025
9026 comp = ctxt->comp;
9027 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 case XPATH_OP_END:
9029 return (0);
9030 case XPATH_OP_AND:
9031 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9032 xmlXPathBooleanFunction(ctxt, 1);
9033 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9034 return (total);
9035 arg2 = valuePop(ctxt);
9036 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9037 xmlXPathBooleanFunction(ctxt, 1);
9038 arg1 = valuePop(ctxt);
9039 arg1->boolval &= arg2->boolval;
9040 valuePush(ctxt, arg1);
9041 xmlXPathFreeObject(arg2);
9042 return (total);
9043 case XPATH_OP_OR:
9044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9045 xmlXPathBooleanFunction(ctxt, 1);
9046 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9047 return (total);
9048 arg2 = valuePop(ctxt);
9049 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9050 xmlXPathBooleanFunction(ctxt, 1);
9051 arg1 = valuePop(ctxt);
9052 arg1->boolval |= arg2->boolval;
9053 valuePush(ctxt, arg1);
9054 xmlXPathFreeObject(arg2);
9055 return (total);
9056 case XPATH_OP_EQUAL:
9057 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9059 equal = xmlXPathEqualValues(ctxt);
9060 if (op->value)
9061 valuePush(ctxt, xmlXPathNewBoolean(equal));
9062 else
9063 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9064 return (total);
9065 case XPATH_OP_CMP:
9066 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9067 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9068 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9069 valuePush(ctxt, xmlXPathNewBoolean(ret));
9070 return (total);
9071 case XPATH_OP_PLUS:
9072 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9073 if (op->ch2 != -1)
9074 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9075 if (op->value == 0)
9076 xmlXPathSubValues(ctxt);
9077 else if (op->value == 1)
9078 xmlXPathAddValues(ctxt);
9079 else if (op->value == 2)
9080 xmlXPathValueFlipSign(ctxt);
9081 else if (op->value == 3) {
9082 CAST_TO_NUMBER;
9083 CHECK_TYPE0(XPATH_NUMBER);
9084 }
9085 return (total);
9086 case XPATH_OP_MULT:
9087 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9088 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9089 if (op->value == 0)
9090 xmlXPathMultValues(ctxt);
9091 else if (op->value == 1)
9092 xmlXPathDivValues(ctxt);
9093 else if (op->value == 2)
9094 xmlXPathModValues(ctxt);
9095 return (total);
9096 case XPATH_OP_UNION:
9097 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9098 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9099 CHECK_TYPE0(XPATH_NODESET);
9100 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009101
Daniel Veillardf06307e2001-07-03 10:35:50 +00009102 CHECK_TYPE0(XPATH_NODESET);
9103 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009104
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9106 arg2->nodesetval);
9107 valuePush(ctxt, arg1);
9108 xmlXPathFreeObject(arg2);
9109 return (total);
9110 case XPATH_OP_ROOT:
9111 xmlXPathRoot(ctxt);
9112 return (total);
9113 case XPATH_OP_NODE:
9114 if (op->ch1 != -1)
9115 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9116 if (op->ch2 != -1)
9117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9118 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9119 return (total);
9120 case XPATH_OP_RESET:
9121 if (op->ch1 != -1)
9122 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9123 if (op->ch2 != -1)
9124 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9125 ctxt->context->node = NULL;
9126 return (total);
9127 case XPATH_OP_COLLECT:{
9128 if (op->ch1 == -1)
9129 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009130
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009132
Daniel Veillardf06307e2001-07-03 10:35:50 +00009133 /*
9134 * Optimization for [n] selection where n is a number
9135 */
9136 if ((op->ch2 != -1) &&
9137 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9138 (comp->steps[op->ch2].ch1 == -1) &&
9139 (comp->steps[op->ch2].ch2 != -1) &&
9140 (comp->steps[comp->steps[op->ch2].ch2].op ==
9141 XPATH_OP_VALUE)) {
9142 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009143
Daniel Veillardf06307e2001-07-03 10:35:50 +00009144 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9145 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9146 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009147
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 if (val->floatval == (float) indx) {
9149 total +=
9150 xmlXPathNodeCollectAndTestNth(ctxt, op,
9151 indx, NULL,
9152 NULL);
9153 return (total);
9154 }
9155 }
9156 }
9157 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9158 return (total);
9159 }
9160 case XPATH_OP_VALUE:
9161 valuePush(ctxt,
9162 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9163 return (total);
9164 case XPATH_OP_VARIABLE:{
9165 if (op->ch1 != -1)
9166 total +=
9167 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9168 if (op->value5 == NULL)
9169 valuePush(ctxt,
9170 xmlXPathVariableLookup(ctxt->context,
9171 op->value4));
9172 else {
9173 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009174
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9176 if (URI == NULL) {
9177 xmlGenericError(xmlGenericErrorContext,
9178 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9179 op->value4, op->value5);
9180 return (total);
9181 }
9182 valuePush(ctxt,
9183 xmlXPathVariableLookupNS(ctxt->context,
9184 op->value4, URI));
9185 }
9186 return (total);
9187 }
9188 case XPATH_OP_FUNCTION:{
9189 xmlXPathFunction func;
9190 const xmlChar *oldFunc, *oldFuncURI;
9191
9192 if (op->ch1 != -1)
9193 total +=
9194 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9195 if (op->cache != NULL)
9196 func = (xmlXPathFunction) op->cache;
9197 else {
9198 const xmlChar *URI = NULL;
9199
9200 if (op->value5 == NULL)
9201 func =
9202 xmlXPathFunctionLookup(ctxt->context,
9203 op->value4);
9204 else {
9205 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9206 if (URI == NULL) {
9207 xmlGenericError(xmlGenericErrorContext,
9208 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9209 op->value4, op->value5);
9210 return (total);
9211 }
9212 func = xmlXPathFunctionLookupNS(ctxt->context,
9213 op->value4, URI);
9214 }
9215 if (func == NULL) {
9216 xmlGenericError(xmlGenericErrorContext,
9217 "xmlXPathRunEval: function %s not found\n",
9218 op->value4);
9219 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
9220 return (total);
9221 }
9222 op->cache = (void *) func;
9223 op->cacheURI = (void *) URI;
9224 }
9225 oldFunc = ctxt->context->function;
9226 oldFuncURI = ctxt->context->functionURI;
9227 ctxt->context->function = op->value4;
9228 ctxt->context->functionURI = op->cacheURI;
9229 func(ctxt, op->value);
9230 ctxt->context->function = oldFunc;
9231 ctxt->context->functionURI = oldFuncURI;
9232 return (total);
9233 }
9234 case XPATH_OP_ARG:
9235 if (op->ch1 != -1)
9236 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9237 if (op->ch2 != -1)
9238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9239 return (total);
9240 case XPATH_OP_PREDICATE:
9241 case XPATH_OP_FILTER:{
9242 xmlXPathObjectPtr res;
9243 xmlXPathObjectPtr obj, tmp;
9244 xmlNodeSetPtr newset = NULL;
9245 xmlNodeSetPtr oldset;
9246 xmlNodePtr oldnode;
9247 int i;
9248
9249 /*
9250 * Optimization for ()[1] selection i.e. the first elem
9251 */
9252 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9253 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9254 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9255 xmlXPathObjectPtr val;
9256
9257 val = comp->steps[op->ch2].value4;
9258 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9259 (val->floatval == 1.0)) {
9260 xmlNodePtr first = NULL;
9261
9262 total +=
9263 xmlXPathCompOpEvalFirst(ctxt,
9264 &comp->steps[op->ch1],
9265 &first);
9266 /*
9267 * The nodeset should be in document order,
9268 * Keep only the first value
9269 */
9270 if ((ctxt->value != NULL) &&
9271 (ctxt->value->type == XPATH_NODESET) &&
9272 (ctxt->value->nodesetval != NULL) &&
9273 (ctxt->value->nodesetval->nodeNr > 1))
9274 ctxt->value->nodesetval->nodeNr = 1;
9275 return (total);
9276 }
9277 }
9278 /*
9279 * Optimization for ()[last()] selection i.e. the last elem
9280 */
9281 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9282 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9283 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9284 int f = comp->steps[op->ch2].ch1;
9285
9286 if ((f != -1) &&
9287 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9288 (comp->steps[f].value5 == NULL) &&
9289 (comp->steps[f].value == 0) &&
9290 (comp->steps[f].value4 != NULL) &&
9291 (xmlStrEqual
9292 (comp->steps[f].value4, BAD_CAST "last"))) {
9293 xmlNodePtr last = NULL;
9294
9295 total +=
9296 xmlXPathCompOpEvalLast(ctxt,
9297 &comp->steps[op->ch1],
9298 &last);
9299 /*
9300 * The nodeset should be in document order,
9301 * Keep only the last value
9302 */
9303 if ((ctxt->value != NULL) &&
9304 (ctxt->value->type == XPATH_NODESET) &&
9305 (ctxt->value->nodesetval != NULL) &&
9306 (ctxt->value->nodesetval->nodeTab != NULL) &&
9307 (ctxt->value->nodesetval->nodeNr > 1)) {
9308 ctxt->value->nodesetval->nodeTab[0] =
9309 ctxt->value->nodesetval->nodeTab[ctxt->
9310 value->
9311 nodesetval->
9312 nodeNr -
9313 1];
9314 ctxt->value->nodesetval->nodeNr = 1;
9315 }
9316 return (total);
9317 }
9318 }
9319
9320 if (op->ch1 != -1)
9321 total +=
9322 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9323 if (op->ch2 == -1)
9324 return (total);
9325 if (ctxt->value == NULL)
9326 return (total);
9327
9328 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009329
9330#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009331 /*
9332 * Hum are we filtering the result of an XPointer expression
9333 */
9334 if (ctxt->value->type == XPATH_LOCATIONSET) {
9335 xmlLocationSetPtr newlocset = NULL;
9336 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009337
Daniel Veillardf06307e2001-07-03 10:35:50 +00009338 /*
9339 * Extract the old locset, and then evaluate the result of the
9340 * expression for all the element in the locset. use it to grow
9341 * up a new locset.
9342 */
9343 CHECK_TYPE0(XPATH_LOCATIONSET);
9344 obj = valuePop(ctxt);
9345 oldlocset = obj->user;
9346 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009347
Daniel Veillardf06307e2001-07-03 10:35:50 +00009348 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9349 ctxt->context->contextSize = 0;
9350 ctxt->context->proximityPosition = 0;
9351 if (op->ch2 != -1)
9352 total +=
9353 xmlXPathCompOpEval(ctxt,
9354 &comp->steps[op->ch2]);
9355 res = valuePop(ctxt);
9356 if (res != NULL)
9357 xmlXPathFreeObject(res);
9358 valuePush(ctxt, obj);
9359 CHECK_ERROR0;
9360 return (total);
9361 }
9362 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009363
Daniel Veillardf06307e2001-07-03 10:35:50 +00009364 for (i = 0; i < oldlocset->locNr; i++) {
9365 /*
9366 * Run the evaluation with a node list made of a
9367 * single item in the nodelocset.
9368 */
9369 ctxt->context->node = oldlocset->locTab[i]->user;
9370 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9371 valuePush(ctxt, tmp);
9372 ctxt->context->contextSize = oldlocset->locNr;
9373 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009374
Daniel Veillardf06307e2001-07-03 10:35:50 +00009375 if (op->ch2 != -1)
9376 total +=
9377 xmlXPathCompOpEval(ctxt,
9378 &comp->steps[op->ch2]);
9379 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009380
Daniel Veillardf06307e2001-07-03 10:35:50 +00009381 /*
9382 * The result of the evaluation need to be tested to
9383 * decided whether the filter succeeded or not
9384 */
9385 res = valuePop(ctxt);
9386 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9387 xmlXPtrLocationSetAdd(newlocset,
9388 xmlXPathObjectCopy
9389 (oldlocset->locTab[i]));
9390 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009391
Daniel Veillardf06307e2001-07-03 10:35:50 +00009392 /*
9393 * Cleanup
9394 */
9395 if (res != NULL)
9396 xmlXPathFreeObject(res);
9397 if (ctxt->value == tmp) {
9398 res = valuePop(ctxt);
9399 xmlXPathFreeObject(res);
9400 }
9401
9402 ctxt->context->node = NULL;
9403 }
9404
9405 /*
9406 * The result is used as the new evaluation locset.
9407 */
9408 xmlXPathFreeObject(obj);
9409 ctxt->context->node = NULL;
9410 ctxt->context->contextSize = -1;
9411 ctxt->context->proximityPosition = -1;
9412 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9413 ctxt->context->node = oldnode;
9414 return (total);
9415 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009416#endif /* LIBXML_XPTR_ENABLED */
9417
Daniel Veillardf06307e2001-07-03 10:35:50 +00009418 /*
9419 * Extract the old set, and then evaluate the result of the
9420 * expression for all the element in the set. use it to grow
9421 * up a new set.
9422 */
9423 CHECK_TYPE0(XPATH_NODESET);
9424 obj = valuePop(ctxt);
9425 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009426
Daniel Veillardf06307e2001-07-03 10:35:50 +00009427 oldnode = ctxt->context->node;
9428 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009429
Daniel Veillardf06307e2001-07-03 10:35:50 +00009430 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9431 ctxt->context->contextSize = 0;
9432 ctxt->context->proximityPosition = 0;
9433 if (op->ch2 != -1)
9434 total +=
9435 xmlXPathCompOpEval(ctxt,
9436 &comp->steps[op->ch2]);
9437 res = valuePop(ctxt);
9438 if (res != NULL)
9439 xmlXPathFreeObject(res);
9440 valuePush(ctxt, obj);
9441 ctxt->context->node = oldnode;
9442 CHECK_ERROR0;
9443 } else {
9444 /*
9445 * Initialize the new set.
9446 */
9447 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009448
Daniel Veillardf06307e2001-07-03 10:35:50 +00009449 for (i = 0; i < oldset->nodeNr; i++) {
9450 /*
9451 * Run the evaluation with a node list made of
9452 * a single item in the nodeset.
9453 */
9454 ctxt->context->node = oldset->nodeTab[i];
9455 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9456 valuePush(ctxt, tmp);
9457 ctxt->context->contextSize = oldset->nodeNr;
9458 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009459
Daniel Veillardf06307e2001-07-03 10:35:50 +00009460 if (op->ch2 != -1)
9461 total +=
9462 xmlXPathCompOpEval(ctxt,
9463 &comp->steps[op->ch2]);
9464 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009465
Daniel Veillardf06307e2001-07-03 10:35:50 +00009466 /*
9467 * The result of the evaluation need to be tested to
9468 * decided whether the filter succeeded or not
9469 */
9470 res = valuePop(ctxt);
9471 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9472 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9473 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009474
Daniel Veillardf06307e2001-07-03 10:35:50 +00009475 /*
9476 * Cleanup
9477 */
9478 if (res != NULL)
9479 xmlXPathFreeObject(res);
9480 if (ctxt->value == tmp) {
9481 res = valuePop(ctxt);
9482 xmlXPathFreeObject(res);
9483 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009484
Daniel Veillardf06307e2001-07-03 10:35:50 +00009485 ctxt->context->node = NULL;
9486 }
9487
9488 /*
9489 * The result is used as the new evaluation set.
9490 */
9491 xmlXPathFreeObject(obj);
9492 ctxt->context->node = NULL;
9493 ctxt->context->contextSize = -1;
9494 ctxt->context->proximityPosition = -1;
9495 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9496 }
9497 ctxt->context->node = oldnode;
9498 return (total);
9499 }
9500 case XPATH_OP_SORT:
9501 if (op->ch1 != -1)
9502 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9503 if ((ctxt->value != NULL) &&
9504 (ctxt->value->type == XPATH_NODESET) &&
9505 (ctxt->value->nodesetval != NULL))
9506 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9507 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009508#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009509 case XPATH_OP_RANGETO:{
9510 xmlXPathObjectPtr range;
9511 xmlXPathObjectPtr res, obj;
9512 xmlXPathObjectPtr tmp;
9513 xmlLocationSetPtr newset = NULL;
9514 xmlNodeSetPtr oldset;
9515 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009516
Daniel Veillardf06307e2001-07-03 10:35:50 +00009517 if (op->ch1 != -1)
9518 total +=
9519 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9520 if (op->ch2 == -1)
9521 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009522
Daniel Veillardf06307e2001-07-03 10:35:50 +00009523 CHECK_TYPE0(XPATH_NODESET);
9524 obj = valuePop(ctxt);
9525 oldset = obj->nodesetval;
9526 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009527
Daniel Veillardf06307e2001-07-03 10:35:50 +00009528 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009529
Daniel Veillardf06307e2001-07-03 10:35:50 +00009530 if (oldset != NULL) {
9531 for (i = 0; i < oldset->nodeNr; i++) {
9532 /*
9533 * Run the evaluation with a node list made of a single item
9534 * in the nodeset.
9535 */
9536 ctxt->context->node = oldset->nodeTab[i];
9537 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9538 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009539
Daniel Veillardf06307e2001-07-03 10:35:50 +00009540 if (op->ch2 != -1)
9541 total +=
9542 xmlXPathCompOpEval(ctxt,
9543 &comp->steps[op->ch2]);
9544 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009545
Daniel Veillardf06307e2001-07-03 10:35:50 +00009546 /*
9547 * The result of the evaluation need to be tested to
9548 * decided whether the filter succeeded or not
9549 */
9550 res = valuePop(ctxt);
9551 range =
9552 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9553 res);
9554 if (range != NULL) {
9555 xmlXPtrLocationSetAdd(newset, range);
9556 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009557
Daniel Veillardf06307e2001-07-03 10:35:50 +00009558 /*
9559 * Cleanup
9560 */
9561 if (res != NULL)
9562 xmlXPathFreeObject(res);
9563 if (ctxt->value == tmp) {
9564 res = valuePop(ctxt);
9565 xmlXPathFreeObject(res);
9566 }
9567
9568 ctxt->context->node = NULL;
9569 }
9570 }
9571
9572 /*
9573 * The result is used as the new evaluation set.
9574 */
9575 xmlXPathFreeObject(obj);
9576 ctxt->context->node = NULL;
9577 ctxt->context->contextSize = -1;
9578 ctxt->context->proximityPosition = -1;
9579 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9580 return (total);
9581 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009582#endif /* LIBXML_XPTR_ENABLED */
9583 }
9584 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009585 "XPath: unknown precompiled operation %d\n", op->op);
9586 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009587}
9588
9589/**
9590 * xmlXPathRunEval:
9591 * @ctxt: the XPath parser context with the compiled expression
9592 *
9593 * Evaluate the Precompiled XPath expression in the given context.
9594 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009595static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009596xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9597 xmlXPathCompExprPtr comp;
9598
9599 if ((ctxt == NULL) || (ctxt->comp == NULL))
9600 return;
9601
9602 if (ctxt->valueTab == NULL) {
9603 /* Allocate the value stack */
9604 ctxt->valueTab = (xmlXPathObjectPtr *)
9605 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9606 if (ctxt->valueTab == NULL) {
9607 xmlFree(ctxt);
9608 xmlGenericError(xmlGenericErrorContext,
9609 "xmlXPathRunEval: out of memory\n");
9610 return;
9611 }
9612 ctxt->valueNr = 0;
9613 ctxt->valueMax = 10;
9614 ctxt->value = NULL;
9615 }
9616 comp = ctxt->comp;
9617 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9618}
9619
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009620/************************************************************************
9621 * *
9622 * Public interfaces *
9623 * *
9624 ************************************************************************/
9625
9626/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009627 * xmlXPathEvalPredicate:
9628 * @ctxt: the XPath context
9629 * @res: the Predicate Expression evaluation result
9630 *
9631 * Evaluate a predicate result for the current node.
9632 * A PredicateExpr is evaluated by evaluating the Expr and converting
9633 * the result to a boolean. If the result is a number, the result will
9634 * be converted to true if the number is equal to the position of the
9635 * context node in the context node list (as returned by the position
9636 * function) and will be converted to false otherwise; if the result
9637 * is not a number, then the result will be converted as if by a call
9638 * to the boolean function.
9639 *
9640 * Return 1 if predicate is true, 0 otherwise
9641 */
9642int
9643xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9644 if (res == NULL) return(0);
9645 switch (res->type) {
9646 case XPATH_BOOLEAN:
9647 return(res->boolval);
9648 case XPATH_NUMBER:
9649 return(res->floatval == ctxt->proximityPosition);
9650 case XPATH_NODESET:
9651 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009652 if (res->nodesetval == NULL)
9653 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009654 return(res->nodesetval->nodeNr != 0);
9655 case XPATH_STRING:
9656 return((res->stringval != NULL) &&
9657 (xmlStrlen(res->stringval) != 0));
9658 default:
9659 STRANGE
9660 }
9661 return(0);
9662}
9663
9664/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009665 * xmlXPathEvaluatePredicateResult:
9666 * @ctxt: the XPath Parser context
9667 * @res: the Predicate Expression evaluation result
9668 *
9669 * Evaluate a predicate result for the current node.
9670 * A PredicateExpr is evaluated by evaluating the Expr and converting
9671 * the result to a boolean. If the result is a number, the result will
9672 * be converted to true if the number is equal to the position of the
9673 * context node in the context node list (as returned by the position
9674 * function) and will be converted to false otherwise; if the result
9675 * is not a number, then the result will be converted as if by a call
9676 * to the boolean function.
9677 *
9678 * Return 1 if predicate is true, 0 otherwise
9679 */
9680int
9681xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9682 xmlXPathObjectPtr res) {
9683 if (res == NULL) return(0);
9684 switch (res->type) {
9685 case XPATH_BOOLEAN:
9686 return(res->boolval);
9687 case XPATH_NUMBER:
9688 return(res->floatval == ctxt->context->proximityPosition);
9689 case XPATH_NODESET:
9690 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009691 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009692 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009693 return(res->nodesetval->nodeNr != 0);
9694 case XPATH_STRING:
9695 return((res->stringval != NULL) &&
9696 (xmlStrlen(res->stringval) != 0));
9697 default:
9698 STRANGE
9699 }
9700 return(0);
9701}
9702
9703/**
9704 * xmlXPathCompile:
9705 * @str: the XPath expression
9706 *
9707 * Compile an XPath expression
9708 *
9709 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9710 * the caller has to free the object.
9711 */
9712xmlXPathCompExprPtr
9713xmlXPathCompile(const xmlChar *str) {
9714 xmlXPathParserContextPtr ctxt;
9715 xmlXPathCompExprPtr comp;
9716
9717 xmlXPathInit();
9718
9719 ctxt = xmlXPathNewParserContext(str, NULL);
9720 xmlXPathCompileExpr(ctxt);
9721
Daniel Veillard40af6492001-04-22 08:50:55 +00009722 if (*ctxt->cur != 0) {
9723 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9724 comp = NULL;
9725 } else {
9726 comp = ctxt->comp;
9727 ctxt->comp = NULL;
9728 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009729 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009730#ifdef DEBUG_EVAL_COUNTS
9731 if (comp != NULL) {
9732 comp->string = xmlStrdup(str);
9733 comp->nb = 0;
9734 }
9735#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009736 return(comp);
9737}
9738
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009739/**
9740 * xmlXPathCompiledEval:
9741 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009742 * @ctx: the XPath context
9743 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009744 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009745 *
9746 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9747 * the caller has to free the object.
9748 */
9749xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009750xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009751 xmlXPathParserContextPtr ctxt;
9752 xmlXPathObjectPtr res, tmp, init = NULL;
9753 int stack = 0;
9754
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009755 if ((comp == NULL) || (ctx == NULL))
9756 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009757 xmlXPathInit();
9758
9759 CHECK_CONTEXT(ctx)
9760
Daniel Veillardf06307e2001-07-03 10:35:50 +00009761#ifdef DEBUG_EVAL_COUNTS
9762 comp->nb++;
9763 if ((comp->string != NULL) && (comp->nb > 100)) {
9764 fprintf(stderr, "100 x %s\n", comp->string);
9765 comp->nb = 0;
9766 }
9767#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009768 ctxt = xmlXPathCompParserContext(comp, ctx);
9769 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009770
9771 if (ctxt->value == NULL) {
9772 xmlGenericError(xmlGenericErrorContext,
9773 "xmlXPathEval: evaluation failed\n");
9774 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009775 } else {
9776 res = valuePop(ctxt);
9777 }
9778
Daniel Veillardf06307e2001-07-03 10:35:50 +00009779
Owen Taylor3473f882001-02-23 17:55:21 +00009780 do {
9781 tmp = valuePop(ctxt);
9782 if (tmp != NULL) {
9783 if (tmp != init)
9784 stack++;
9785 xmlXPathFreeObject(tmp);
9786 }
9787 } while (tmp != NULL);
9788 if ((stack != 0) && (res != NULL)) {
9789 xmlGenericError(xmlGenericErrorContext,
9790 "xmlXPathEval: %d object left on the stack\n",
9791 stack);
9792 }
9793 if (ctxt->error != XPATH_EXPRESSION_OK) {
9794 xmlXPathFreeObject(res);
9795 res = NULL;
9796 }
9797
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009798
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009799 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009800 xmlXPathFreeParserContext(ctxt);
9801 return(res);
9802}
9803
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009804/**
9805 * xmlXPathEvalExpr:
9806 * @ctxt: the XPath Parser context
9807 *
9808 * Parse and evaluate an XPath expression in the given context,
9809 * then push the result on the context stack
9810 */
9811void
9812xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9813 xmlXPathCompileExpr(ctxt);
9814 xmlXPathRunEval(ctxt);
9815}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009816
9817/**
9818 * xmlXPathEval:
9819 * @str: the XPath expression
9820 * @ctx: the XPath context
9821 *
9822 * Evaluate the XPath Location Path in the given context.
9823 *
9824 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9825 * the caller has to free the object.
9826 */
9827xmlXPathObjectPtr
9828xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9829 xmlXPathParserContextPtr ctxt;
9830 xmlXPathObjectPtr res, tmp, init = NULL;
9831 int stack = 0;
9832
9833 xmlXPathInit();
9834
9835 CHECK_CONTEXT(ctx)
9836
9837 ctxt = xmlXPathNewParserContext(str, ctx);
9838 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009839
9840 if (ctxt->value == NULL) {
9841 xmlGenericError(xmlGenericErrorContext,
9842 "xmlXPathEval: evaluation failed\n");
9843 res = NULL;
9844 } else if (*ctxt->cur != 0) {
9845 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9846 res = NULL;
9847 } else {
9848 res = valuePop(ctxt);
9849 }
9850
9851 do {
9852 tmp = valuePop(ctxt);
9853 if (tmp != NULL) {
9854 if (tmp != init)
9855 stack++;
9856 xmlXPathFreeObject(tmp);
9857 }
9858 } while (tmp != NULL);
9859 if ((stack != 0) && (res != NULL)) {
9860 xmlGenericError(xmlGenericErrorContext,
9861 "xmlXPathEval: %d object left on the stack\n",
9862 stack);
9863 }
9864 if (ctxt->error != XPATH_EXPRESSION_OK) {
9865 xmlXPathFreeObject(res);
9866 res = NULL;
9867 }
9868
Owen Taylor3473f882001-02-23 17:55:21 +00009869 xmlXPathFreeParserContext(ctxt);
9870 return(res);
9871}
9872
9873/**
9874 * xmlXPathEvalExpression:
9875 * @str: the XPath expression
9876 * @ctxt: the XPath context
9877 *
9878 * Evaluate the XPath expression in the given context.
9879 *
9880 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9881 * the caller has to free the object.
9882 */
9883xmlXPathObjectPtr
9884xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9885 xmlXPathParserContextPtr pctxt;
9886 xmlXPathObjectPtr res, tmp;
9887 int stack = 0;
9888
9889 xmlXPathInit();
9890
9891 CHECK_CONTEXT(ctxt)
9892
9893 pctxt = xmlXPathNewParserContext(str, ctxt);
9894 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009895
9896 if (*pctxt->cur != 0) {
9897 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9898 res = NULL;
9899 } else {
9900 res = valuePop(pctxt);
9901 }
9902 do {
9903 tmp = valuePop(pctxt);
9904 if (tmp != NULL) {
9905 xmlXPathFreeObject(tmp);
9906 stack++;
9907 }
9908 } while (tmp != NULL);
9909 if ((stack != 0) && (res != NULL)) {
9910 xmlGenericError(xmlGenericErrorContext,
9911 "xmlXPathEvalExpression: %d object left on the stack\n",
9912 stack);
9913 }
9914 xmlXPathFreeParserContext(pctxt);
9915 return(res);
9916}
9917
9918/**
9919 * xmlXPathRegisterAllFunctions:
9920 * @ctxt: the XPath context
9921 *
9922 * Registers all default XPath functions in this context
9923 */
9924void
9925xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9926{
9927 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9928 xmlXPathBooleanFunction);
9929 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9930 xmlXPathCeilingFunction);
9931 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9932 xmlXPathCountFunction);
9933 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9934 xmlXPathConcatFunction);
9935 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9936 xmlXPathContainsFunction);
9937 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9938 xmlXPathIdFunction);
9939 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9940 xmlXPathFalseFunction);
9941 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9942 xmlXPathFloorFunction);
9943 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9944 xmlXPathLastFunction);
9945 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9946 xmlXPathLangFunction);
9947 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9948 xmlXPathLocalNameFunction);
9949 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9950 xmlXPathNotFunction);
9951 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9952 xmlXPathNameFunction);
9953 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9954 xmlXPathNamespaceURIFunction);
9955 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9956 xmlXPathNormalizeFunction);
9957 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9958 xmlXPathNumberFunction);
9959 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9960 xmlXPathPositionFunction);
9961 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9962 xmlXPathRoundFunction);
9963 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9964 xmlXPathStringFunction);
9965 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9966 xmlXPathStringLengthFunction);
9967 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9968 xmlXPathStartsWithFunction);
9969 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9970 xmlXPathSubstringFunction);
9971 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9972 xmlXPathSubstringBeforeFunction);
9973 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9974 xmlXPathSubstringAfterFunction);
9975 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9976 xmlXPathSumFunction);
9977 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9978 xmlXPathTrueFunction);
9979 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9980 xmlXPathTranslateFunction);
9981}
9982
9983#endif /* LIBXML_XPATH_ENABLED */