blob: b98ebac3dc4bdc00a71f160ce2faeba224dac265 [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 Veillard5792e162001-04-30 17:44:45 +0000197 xmlXPathNAN = xmlXPathDivideBy(0.0, 0.0);
198 xmlXPathPINF = xmlXPathDivideBy(1.0, 0.0);
Daniel Veillard541d6552001-06-07 14:20:01 +0000199 xmlXPathNINF = xmlXPathDivideBy(-1.0, 0.0);
Owen Taylor3473f882001-02-23 17:55:21 +0000200
201 initialized = 1;
202}
203
204/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000205 * *
206 * Parser Types *
207 * *
208 ************************************************************************/
209
210/*
211 * Types are private:
212 */
213
214typedef enum {
215 XPATH_OP_END=0,
216 XPATH_OP_AND,
217 XPATH_OP_OR,
218 XPATH_OP_EQUAL,
219 XPATH_OP_CMP,
220 XPATH_OP_PLUS,
221 XPATH_OP_MULT,
222 XPATH_OP_UNION,
223 XPATH_OP_ROOT,
224 XPATH_OP_NODE,
225 XPATH_OP_RESET,
226 XPATH_OP_COLLECT,
227 XPATH_OP_VALUE,
228 XPATH_OP_VARIABLE,
229 XPATH_OP_FUNCTION,
230 XPATH_OP_ARG,
231 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000232 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000233 XPATH_OP_SORT
234#ifdef LIBXML_XPTR_ENABLED
235 ,XPATH_OP_RANGETO
236#endif
237} xmlXPathOp;
238
239typedef enum {
240 AXIS_ANCESTOR = 1,
241 AXIS_ANCESTOR_OR_SELF,
242 AXIS_ATTRIBUTE,
243 AXIS_CHILD,
244 AXIS_DESCENDANT,
245 AXIS_DESCENDANT_OR_SELF,
246 AXIS_FOLLOWING,
247 AXIS_FOLLOWING_SIBLING,
248 AXIS_NAMESPACE,
249 AXIS_PARENT,
250 AXIS_PRECEDING,
251 AXIS_PRECEDING_SIBLING,
252 AXIS_SELF
253} xmlXPathAxisVal;
254
255typedef enum {
256 NODE_TEST_NONE = 0,
257 NODE_TEST_TYPE = 1,
258 NODE_TEST_PI = 2,
259 NODE_TEST_ALL = 3,
260 NODE_TEST_NS = 4,
261 NODE_TEST_NAME = 5
262} xmlXPathTestVal;
263
264typedef enum {
265 NODE_TYPE_NODE = 0,
266 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
267 NODE_TYPE_TEXT = XML_TEXT_NODE,
268 NODE_TYPE_PI = XML_PI_NODE
269} xmlXPathTypeVal;
270
271
272typedef struct _xmlXPathStepOp xmlXPathStepOp;
273typedef xmlXPathStepOp *xmlXPathStepOpPtr;
274struct _xmlXPathStepOp {
275 xmlXPathOp op;
276 int ch1;
277 int ch2;
278 int value;
279 int value2;
280 int value3;
281 void *value4;
282 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000283 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000284 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000285};
286
287struct _xmlXPathCompExpr {
288 int nbStep;
289 int maxStep;
290 xmlXPathStepOp *steps; /* ops for computation */
291 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000292#ifdef DEBUG_EVAL_COUNTS
293 int nb;
294 xmlChar *string;
295#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000296};
297
298/************************************************************************
299 * *
300 * Parser Type functions *
301 * *
302 ************************************************************************/
303
304/**
305 * xmlXPathNewCompExpr:
306 *
307 * Create a new Xpath component
308 *
309 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
310 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000311static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000312xmlXPathNewCompExpr(void) {
313 xmlXPathCompExprPtr cur;
314
315 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
316 if (cur == NULL) {
317 xmlGenericError(xmlGenericErrorContext,
318 "xmlXPathNewCompExpr : malloc failed\n");
319 return(NULL);
320 }
321 memset(cur, 0, sizeof(xmlXPathCompExpr));
322 cur->maxStep = 10;
323 cur->nbStep = 0;
324 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
325 sizeof(xmlXPathStepOp));
326 if (cur->steps == NULL) {
327 xmlGenericError(xmlGenericErrorContext,
328 "xmlXPathNewCompExpr : malloc failed\n");
329 xmlFree(cur);
330 return(NULL);
331 }
332 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
333 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000334#ifdef DEBUG_EVAL_COUNTS
335 cur->nb = 0;
336#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000337 return(cur);
338}
339
340/**
341 * xmlXPathFreeCompExpr:
342 * @comp: an XPATH comp
343 *
344 * Free up the memory allocated by @comp
345 */
346void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000347xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
348{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000349 xmlXPathStepOpPtr op;
350 int i;
351
352 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000353 return;
354 for (i = 0; i < comp->nbStep; i++) {
355 op = &comp->steps[i];
356 if (op->value4 != NULL) {
357 if (op->op == XPATH_OP_VALUE)
358 xmlXPathFreeObject(op->value4);
359 else
360 xmlFree(op->value4);
361 }
362 if (op->value5 != NULL)
363 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000364 }
365 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000366 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000367 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000368#ifdef DEBUG_EVAL_COUNTS
369 if (comp->string != NULL) {
370 xmlFree(comp->string);
371 }
372#endif
373
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000374 xmlFree(comp);
375}
376
377/**
378 * xmlXPathCompExprAdd:
379 * @comp: the compiled expression
380 * @ch1: first child index
381 * @ch2: second child index
382 * @op: an op
383 * @value: the first int value
384 * @value2: the second int value
385 * @value3: the third int value
386 * @value4: the first string value
387 * @value5: the second string value
388 *
389 * Add an step to an XPath Compiled Expression
390 *
391 * Returns -1 in case of failure, the index otherwise
392 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000393static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000394xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
395 xmlXPathOp op, int value,
396 int value2, int value3, void *value4, void *value5) {
397 if (comp->nbStep >= comp->maxStep) {
398 xmlXPathStepOp *real;
399
400 comp->maxStep *= 2;
401 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
402 comp->maxStep * sizeof(xmlXPathStepOp));
403 if (real == NULL) {
404 comp->maxStep /= 2;
405 xmlGenericError(xmlGenericErrorContext,
406 "xmlXPathCompExprAdd : realloc failed\n");
407 return(-1);
408 }
409 comp->steps = real;
410 }
411 comp->last = comp->nbStep;
412 comp->steps[comp->nbStep].ch1 = ch1;
413 comp->steps[comp->nbStep].ch2 = ch2;
414 comp->steps[comp->nbStep].op = op;
415 comp->steps[comp->nbStep].value = value;
416 comp->steps[comp->nbStep].value2 = value2;
417 comp->steps[comp->nbStep].value3 = value3;
418 comp->steps[comp->nbStep].value4 = value4;
419 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000420 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000421 return(comp->nbStep++);
422}
423
Daniel Veillardf06307e2001-07-03 10:35:50 +0000424/**
425 * xmlXPathCompSwap:
426 * @comp: the compiled expression
427 * @op: operation index
428 *
429 * Swaps 2 operations in the compiled expression
430 * TODO: not thread safe, disable for multi-thread operations
431 *
432 * Returns -1 in case of failure, the index otherwise
433 */
434static void
435xmlXPathCompSwap(xmlXPathStepOpPtr op) {
436 int tmp;
437
438 tmp = op->ch1;
439 op->ch1 = op->ch2;
440 op->ch2 = tmp;
441}
442
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000443#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
444 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
445 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000446#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
447 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
448 (op), (val), (val2), (val3), (val4), (val5))
449
450#define PUSH_LEAVE_EXPR(op, val, val2) \
451xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
452
453#define PUSH_UNARY_EXPR(op, ch, val, val2) \
454xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
455
456#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
457xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
458
459/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000460 * *
461 * Debugging related functions *
462 * *
463 ************************************************************************/
464
465#define TODO \
466 xmlGenericError(xmlGenericErrorContext, \
467 "Unimplemented block at %s:%d\n", \
468 __FILE__, __LINE__);
469
470#define STRANGE \
471 xmlGenericError(xmlGenericErrorContext, \
472 "Internal error at %s:%d\n", \
473 __FILE__, __LINE__);
474
475#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000476static void
477xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000478 int i;
479 char shift[100];
480
481 for (i = 0;((i < depth) && (i < 25));i++)
482 shift[2 * i] = shift[2 * i + 1] = ' ';
483 shift[2 * i] = shift[2 * i + 1] = 0;
484 if (cur == NULL) {
485 fprintf(output, shift);
486 fprintf(output, "Node is NULL !\n");
487 return;
488
489 }
490
491 if ((cur->type == XML_DOCUMENT_NODE) ||
492 (cur->type == XML_HTML_DOCUMENT_NODE)) {
493 fprintf(output, shift);
494 fprintf(output, " /\n");
495 } else if (cur->type == XML_ATTRIBUTE_NODE)
496 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
497 else
498 xmlDebugDumpOneNode(output, cur, depth);
499}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000500static void
501xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000502 xmlNodePtr tmp;
503 int i;
504 char shift[100];
505
506 for (i = 0;((i < depth) && (i < 25));i++)
507 shift[2 * i] = shift[2 * i + 1] = ' ';
508 shift[2 * i] = shift[2 * i + 1] = 0;
509 if (cur == NULL) {
510 fprintf(output, shift);
511 fprintf(output, "Node is NULL !\n");
512 return;
513
514 }
515
516 while (cur != NULL) {
517 tmp = cur;
518 cur = cur->next;
519 xmlDebugDumpOneNode(output, tmp, depth);
520 }
521}
Owen Taylor3473f882001-02-23 17:55:21 +0000522
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000523static void
524xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000525 int i;
526 char shift[100];
527
528 for (i = 0;((i < depth) && (i < 25));i++)
529 shift[2 * i] = shift[2 * i + 1] = ' ';
530 shift[2 * i] = shift[2 * i + 1] = 0;
531
532 if (cur == NULL) {
533 fprintf(output, shift);
534 fprintf(output, "NodeSet is NULL !\n");
535 return;
536
537 }
538
Daniel Veillard911f49a2001-04-07 15:39:35 +0000539 if (cur != NULL) {
540 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
541 for (i = 0;i < cur->nodeNr;i++) {
542 fprintf(output, shift);
543 fprintf(output, "%d", i + 1);
544 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
545 }
Owen Taylor3473f882001-02-23 17:55:21 +0000546 }
547}
548
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000549static void
550xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000551 int i;
552 char shift[100];
553
554 for (i = 0;((i < depth) && (i < 25));i++)
555 shift[2 * i] = shift[2 * i + 1] = ' ';
556 shift[2 * i] = shift[2 * i + 1] = 0;
557
558 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
559 fprintf(output, shift);
560 fprintf(output, "Value Tree is NULL !\n");
561 return;
562
563 }
564
565 fprintf(output, shift);
566 fprintf(output, "%d", i + 1);
567 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
568}
Owen Taylor3473f882001-02-23 17:55:21 +0000569#if defined(LIBXML_XPTR_ENABLED)
570void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000571static void
572xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000573 int i;
574 char shift[100];
575
576 for (i = 0;((i < depth) && (i < 25));i++)
577 shift[2 * i] = shift[2 * i + 1] = ' ';
578 shift[2 * i] = shift[2 * i + 1] = 0;
579
580 if (cur == NULL) {
581 fprintf(output, shift);
582 fprintf(output, "LocationSet is NULL !\n");
583 return;
584
585 }
586
587 for (i = 0;i < cur->locNr;i++) {
588 fprintf(output, shift);
589 fprintf(output, "%d : ", i + 1);
590 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
591 }
592}
Daniel Veillard017b1082001-06-21 11:20:21 +0000593#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000594
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000595/**
596 * xmlXPathDebugDumpObject:
597 * @output: the FILE * to dump the output
598 * @cur: the object to inspect
599 * @depth: indentation level
600 *
601 * Dump the content of the object for debugging purposes
602 */
603void
604xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000605 int i;
606 char shift[100];
607
608 for (i = 0;((i < depth) && (i < 25));i++)
609 shift[2 * i] = shift[2 * i + 1] = ' ';
610 shift[2 * i] = shift[2 * i + 1] = 0;
611
612 fprintf(output, shift);
613
614 if (cur == NULL) {
615 fprintf(output, "Object is empty (NULL)\n");
616 return;
617 }
618 switch(cur->type) {
619 case XPATH_UNDEFINED:
620 fprintf(output, "Object is uninitialized\n");
621 break;
622 case XPATH_NODESET:
623 fprintf(output, "Object is a Node Set :\n");
624 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
625 break;
626 case XPATH_XSLT_TREE:
627 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000628 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000629 break;
630 case XPATH_BOOLEAN:
631 fprintf(output, "Object is a Boolean : ");
632 if (cur->boolval) fprintf(output, "true\n");
633 else fprintf(output, "false\n");
634 break;
635 case XPATH_NUMBER:
Daniel Veillard357c9602001-05-03 10:49:20 +0000636 switch (isinf(cur->floatval)) {
637 case 1:
638 fprintf(output, "Object is a number : +Infinity\n");
639 break;
640 case -1:
641 fprintf(output, "Object is a number : -Infinity\n");
642 break;
643 default:
644 if (isnan(cur->floatval)) {
645 fprintf(output, "Object is a number : NaN\n");
646 } else {
647 fprintf(output, "Object is a number : %0g\n", cur->floatval);
648 }
649 }
Owen Taylor3473f882001-02-23 17:55:21 +0000650 break;
651 case XPATH_STRING:
652 fprintf(output, "Object is a string : ");
653 xmlDebugDumpString(output, cur->stringval);
654 fprintf(output, "\n");
655 break;
656 case XPATH_POINT:
657 fprintf(output, "Object is a point : index %d in node", cur->index);
658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
659 fprintf(output, "\n");
660 break;
661 case XPATH_RANGE:
662 if ((cur->user2 == NULL) ||
663 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
664 fprintf(output, "Object is a collapsed range :\n");
665 fprintf(output, shift);
666 if (cur->index >= 0)
667 fprintf(output, "index %d in ", cur->index);
668 fprintf(output, "node\n");
669 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
670 depth + 1);
671 } else {
672 fprintf(output, "Object is a range :\n");
673 fprintf(output, shift);
674 fprintf(output, "From ");
675 if (cur->index >= 0)
676 fprintf(output, "index %d in ", cur->index);
677 fprintf(output, "node\n");
678 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
679 depth + 1);
680 fprintf(output, shift);
681 fprintf(output, "To ");
682 if (cur->index2 >= 0)
683 fprintf(output, "index %d in ", cur->index2);
684 fprintf(output, "node\n");
685 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
686 depth + 1);
687 fprintf(output, "\n");
688 }
689 break;
690 case XPATH_LOCATIONSET:
691#if defined(LIBXML_XPTR_ENABLED)
692 fprintf(output, "Object is a Location Set:\n");
693 xmlXPathDebugDumpLocationSet(output,
694 (xmlLocationSetPtr) cur->user, depth);
695#endif
696 break;
697 case XPATH_USERS:
698 fprintf(output, "Object is user defined\n");
699 break;
700 }
701}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000702
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000703static void
704xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000705 xmlXPathStepOpPtr op, int depth) {
706 int i;
707 char shift[100];
708
709 for (i = 0;((i < depth) && (i < 25));i++)
710 shift[2 * i] = shift[2 * i + 1] = ' ';
711 shift[2 * i] = shift[2 * i + 1] = 0;
712
713 fprintf(output, shift);
714 if (op == NULL) {
715 fprintf(output, "Step is NULL\n");
716 return;
717 }
718 switch (op->op) {
719 case XPATH_OP_END:
720 fprintf(output, "END"); break;
721 case XPATH_OP_AND:
722 fprintf(output, "AND"); break;
723 case XPATH_OP_OR:
724 fprintf(output, "OR"); break;
725 case XPATH_OP_EQUAL:
726 if (op->value)
727 fprintf(output, "EQUAL =");
728 else
729 fprintf(output, "EQUAL !=");
730 break;
731 case XPATH_OP_CMP:
732 if (op->value)
733 fprintf(output, "CMP <");
734 else
735 fprintf(output, "CMP >");
736 if (!op->value2)
737 fprintf(output, "=");
738 break;
739 case XPATH_OP_PLUS:
740 if (op->value == 0)
741 fprintf(output, "PLUS -");
742 else if (op->value == 1)
743 fprintf(output, "PLUS +");
744 else if (op->value == 2)
745 fprintf(output, "PLUS unary -");
746 else if (op->value == 3)
747 fprintf(output, "PLUS unary - -");
748 break;
749 case XPATH_OP_MULT:
750 if (op->value == 0)
751 fprintf(output, "MULT *");
752 else if (op->value == 1)
753 fprintf(output, "MULT div");
754 else
755 fprintf(output, "MULT mod");
756 break;
757 case XPATH_OP_UNION:
758 fprintf(output, "UNION"); break;
759 case XPATH_OP_ROOT:
760 fprintf(output, "ROOT"); break;
761 case XPATH_OP_NODE:
762 fprintf(output, "NODE"); break;
763 case XPATH_OP_RESET:
764 fprintf(output, "RESET"); break;
765 case XPATH_OP_SORT:
766 fprintf(output, "SORT"); break;
767 case XPATH_OP_COLLECT: {
768 xmlXPathAxisVal axis = op->value;
769 xmlXPathTestVal test = op->value2;
770 xmlXPathTypeVal type = op->value3;
771 const xmlChar *prefix = op->value4;
772 const xmlChar *name = op->value5;
773
774 fprintf(output, "COLLECT ");
775 switch (axis) {
776 case AXIS_ANCESTOR:
777 fprintf(output, " 'ancestors' "); break;
778 case AXIS_ANCESTOR_OR_SELF:
779 fprintf(output, " 'ancestors-or-self' "); break;
780 case AXIS_ATTRIBUTE:
781 fprintf(output, " 'attributes' "); break;
782 case AXIS_CHILD:
783 fprintf(output, " 'child' "); break;
784 case AXIS_DESCENDANT:
785 fprintf(output, " 'descendant' "); break;
786 case AXIS_DESCENDANT_OR_SELF:
787 fprintf(output, " 'descendant-or-self' "); break;
788 case AXIS_FOLLOWING:
789 fprintf(output, " 'following' "); break;
790 case AXIS_FOLLOWING_SIBLING:
791 fprintf(output, " 'following-siblings' "); break;
792 case AXIS_NAMESPACE:
793 fprintf(output, " 'namespace' "); break;
794 case AXIS_PARENT:
795 fprintf(output, " 'parent' "); break;
796 case AXIS_PRECEDING:
797 fprintf(output, " 'preceding' "); break;
798 case AXIS_PRECEDING_SIBLING:
799 fprintf(output, " 'preceding-sibling' "); break;
800 case AXIS_SELF:
801 fprintf(output, " 'self' "); break;
802 }
803 switch (test) {
804 case NODE_TEST_NONE:
805 fprintf(output, "'none' "); break;
806 case NODE_TEST_TYPE:
807 fprintf(output, "'type' "); break;
808 case NODE_TEST_PI:
809 fprintf(output, "'PI' "); break;
810 case NODE_TEST_ALL:
811 fprintf(output, "'all' "); break;
812 case NODE_TEST_NS:
813 fprintf(output, "'namespace' "); break;
814 case NODE_TEST_NAME:
815 fprintf(output, "'name' "); break;
816 }
817 switch (type) {
818 case NODE_TYPE_NODE:
819 fprintf(output, "'node' "); break;
820 case NODE_TYPE_COMMENT:
821 fprintf(output, "'comment' "); break;
822 case NODE_TYPE_TEXT:
823 fprintf(output, "'text' "); break;
824 case NODE_TYPE_PI:
825 fprintf(output, "'PI' "); break;
826 }
827 if (prefix != NULL)
828 fprintf(output, "%s:", prefix);
829 if (name != NULL)
830 fprintf(output, "%s", name);
831 break;
832
833 }
834 case XPATH_OP_VALUE: {
835 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
836
837 fprintf(output, "ELEM ");
838 xmlXPathDebugDumpObject(output, object, 0);
839 goto finish;
840 }
841 case XPATH_OP_VARIABLE: {
842 const xmlChar *prefix = op->value5;
843 const xmlChar *name = op->value4;
844
845 if (prefix != NULL)
846 fprintf(output, "VARIABLE %s:%s", prefix, name);
847 else
848 fprintf(output, "VARIABLE %s", name);
849 break;
850 }
851 case XPATH_OP_FUNCTION: {
852 int nbargs = op->value;
853 const xmlChar *prefix = op->value5;
854 const xmlChar *name = op->value4;
855
856 if (prefix != NULL)
857 fprintf(output, "FUNCTION %s:%s(%d args)",
858 prefix, name, nbargs);
859 else
860 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
861 break;
862 }
863 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
864 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000865 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000866#ifdef LIBXML_XPTR_ENABLED
867 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
868#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000869 default:
870 fprintf(output, "UNKNOWN %d\n", op->op); return;
871 }
872 fprintf(output, "\n");
873finish:
874 if (op->ch1 >= 0)
875 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
876 if (op->ch2 >= 0)
877 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
878}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000879
880void
881xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
882 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000883 int i;
884 char shift[100];
885
886 for (i = 0;((i < depth) && (i < 25));i++)
887 shift[2 * i] = shift[2 * i + 1] = ' ';
888 shift[2 * i] = shift[2 * i + 1] = 0;
889
890 fprintf(output, shift);
891
892 if (comp == NULL) {
893 fprintf(output, "Compiled Expression is NULL\n");
894 return;
895 }
896 fprintf(output, "Compiled Expression : %d elements\n",
897 comp->nbStep);
898 i = comp->last;
899 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
900}
Daniel Veillard017b1082001-06-21 11:20:21 +0000901#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000902
903/************************************************************************
904 * *
905 * Parser stacks related functions and macros *
906 * *
907 ************************************************************************/
908
909/*
910 * Generic function for accessing stacks in the Parser Context
911 */
912
913#define PUSH_AND_POP(type, name) \
914extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
915 if (ctxt->name##Nr >= ctxt->name##Max) { \
916 ctxt->name##Max *= 2; \
917 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
918 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
919 if (ctxt->name##Tab == NULL) { \
920 xmlGenericError(xmlGenericErrorContext, \
921 "realloc failed !\n"); \
922 return(0); \
923 } \
924 } \
925 ctxt->name##Tab[ctxt->name##Nr] = value; \
926 ctxt->name = value; \
927 return(ctxt->name##Nr++); \
928} \
929extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
930 type ret; \
931 if (ctxt->name##Nr <= 0) return(0); \
932 ctxt->name##Nr--; \
933 if (ctxt->name##Nr > 0) \
934 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
935 else \
936 ctxt->name = NULL; \
937 ret = ctxt->name##Tab[ctxt->name##Nr]; \
938 ctxt->name##Tab[ctxt->name##Nr] = 0; \
939 return(ret); \
940} \
941
942PUSH_AND_POP(xmlXPathObjectPtr, value)
943
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000944/**
945 * xmlXPathPopBoolean:
946 * @ctxt: an XPath parser context
947 *
948 * Pops a boolean from the stack, handling conversion if needed.
949 * Check error with #xmlXPathCheckError.
950 *
951 * Returns the boolean
952 */
953int
954xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
955 xmlXPathObjectPtr obj;
956 int ret;
957
958 obj = valuePop(ctxt);
959 if (obj == NULL) {
960 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
961 return(0);
962 }
963 ret = xmlXPathCastToBoolean(obj);
964 xmlXPathFreeObject(obj);
965 return(ret);
966}
967
968/**
969 * xmlXPathPopNumber:
970 * @ctxt: an XPath parser context
971 *
972 * Pops a number from the stack, handling conversion if needed.
973 * Check error with #xmlXPathCheckError.
974 *
975 * Returns the number
976 */
977double
978xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
979 xmlXPathObjectPtr obj;
980 double ret;
981
982 obj = valuePop(ctxt);
983 if (obj == NULL) {
984 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
985 return(0);
986 }
987 ret = xmlXPathCastToNumber(obj);
988 xmlXPathFreeObject(obj);
989 return(ret);
990}
991
992/**
993 * xmlXPathPopString:
994 * @ctxt: an XPath parser context
995 *
996 * Pops a string from the stack, handling conversion if needed.
997 * Check error with #xmlXPathCheckError.
998 *
999 * Returns the string
1000 */
1001xmlChar *
1002xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1003 xmlXPathObjectPtr obj;
1004 xmlChar * ret;
1005
1006 obj = valuePop(ctxt);
1007 if (obj == NULL) {
1008 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1009 return(NULL);
1010 }
1011 ret = xmlXPathCastToString(obj);
1012 /* TODO: needs refactoring somewhere else */
1013 if (obj->stringval == ret)
1014 obj->stringval = NULL;
1015 xmlXPathFreeObject(obj);
1016 return(ret);
1017}
1018
1019/**
1020 * xmlXPathPopNodeSet:
1021 * @ctxt: an XPath parser context
1022 *
1023 * Pops a node-set from the stack, handling conversion if needed.
1024 * Check error with #xmlXPathCheckError.
1025 *
1026 * Returns the node-set
1027 */
1028xmlNodeSetPtr
1029xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1030 xmlXPathObjectPtr obj;
1031 xmlNodeSetPtr ret;
1032
1033 if (ctxt->value == NULL) {
1034 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1035 return(NULL);
1036 }
1037 if (!xmlXPathStackIsNodeSet(ctxt)) {
1038 xmlXPathSetTypeError(ctxt);
1039 return(NULL);
1040 }
1041 obj = valuePop(ctxt);
1042 ret = obj->nodesetval;
1043 xmlXPathFreeNodeSetList(obj);
1044 return(ret);
1045}
1046
1047/**
1048 * xmlXPathPopExternal:
1049 * @ctxt: an XPath parser context
1050 *
1051 * Pops an external oject from the stack, handling conversion if needed.
1052 * Check error with #xmlXPathCheckError.
1053 *
1054 * Returns the object
1055 */
1056void *
1057xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1058 xmlXPathObjectPtr obj;
1059 void * ret;
1060
1061 if (ctxt->value == NULL) {
1062 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1063 return(NULL);
1064 }
1065 if (ctxt->value->type != XPATH_USERS) {
1066 xmlXPathSetTypeError(ctxt);
1067 return(NULL);
1068 }
1069 obj = valuePop(ctxt);
1070 ret = obj->user;
1071 xmlXPathFreeObject(obj);
1072 return(ret);
1073}
1074
Owen Taylor3473f882001-02-23 17:55:21 +00001075/*
1076 * Macros for accessing the content. Those should be used only by the parser,
1077 * and not exported.
1078 *
1079 * Dirty macros, i.e. one need to make assumption on the context to use them
1080 *
1081 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1082 * CUR returns the current xmlChar value, i.e. a 8 bit value
1083 * in ISO-Latin or UTF-8.
1084 * This should be used internally by the parser
1085 * only to compare to ASCII values otherwise it would break when
1086 * running with UTF-8 encoding.
1087 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1088 * to compare on ASCII based substring.
1089 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1090 * strings within the parser.
1091 * CURRENT Returns the current char value, with the full decoding of
1092 * UTF-8 if we are using this mode. It returns an int.
1093 * NEXT Skip to the next character, this does the proper decoding
1094 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1095 * It returns the pointer to the current xmlChar.
1096 */
1097
1098#define CUR (*ctxt->cur)
1099#define SKIP(val) ctxt->cur += (val)
1100#define NXT(val) ctxt->cur[(val)]
1101#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001102#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1103
1104#define COPY_BUF(l,b,i,v) \
1105 if (l == 1) b[i++] = (xmlChar) v; \
1106 else i += xmlCopyChar(l,&b[i],v)
1107
1108#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001109
1110#define SKIP_BLANKS \
1111 while (IS_BLANK(*(ctxt->cur))) NEXT
1112
1113#define CURRENT (*ctxt->cur)
1114#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1115
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001116
1117#ifndef DBL_DIG
1118#define DBL_DIG 16
1119#endif
1120#ifndef DBL_EPSILON
1121#define DBL_EPSILON 1E-9
1122#endif
1123
1124#define UPPER_DOUBLE 1E9
1125#define LOWER_DOUBLE 1E-5
1126
1127#define INTEGER_DIGITS DBL_DIG
1128#define FRACTION_DIGITS (DBL_DIG + 1)
1129#define EXPONENT_DIGITS (3 + 2)
1130
1131/**
1132 * xmlXPathFormatNumber:
1133 * @number: number to format
1134 * @buffer: output buffer
1135 * @buffersize: size of output buffer
1136 *
1137 * Convert the number into a string representation.
1138 */
1139static void
1140xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1141{
1142 switch (isinf(number)) {
1143 case 1:
1144 if (buffersize > (int)sizeof("+Infinity"))
1145 sprintf(buffer, "+Infinity");
1146 break;
1147 case -1:
1148 if (buffersize > (int)sizeof("-Infinity"))
1149 sprintf(buffer, "-Infinity");
1150 break;
1151 default:
1152 if (isnan(number)) {
1153 if (buffersize > (int)sizeof("NaN"))
1154 sprintf(buffer, "NaN");
1155 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001156 /* 3 is sign, decimal point, and terminating zero */
1157 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1158 int integer_place, fraction_place;
1159 char *ptr;
1160 char *after_fraction;
1161 double absolute_value;
1162 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001163
Bjorn Reese70a9da52001-04-21 16:57:29 +00001164 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001165
Bjorn Reese70a9da52001-04-21 16:57:29 +00001166 /*
1167 * First choose format - scientific or regular floating point.
1168 * In either case, result is in work, and after_fraction points
1169 * just past the fractional part.
1170 */
1171 if ( ((absolute_value > UPPER_DOUBLE) ||
1172 (absolute_value < LOWER_DOUBLE)) &&
1173 (absolute_value != 0.0) ) {
1174 /* Use scientific notation */
1175 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1176 fraction_place = DBL_DIG - 1;
1177 snprintf(work, sizeof(work),"%*.*e",
1178 integer_place, fraction_place, number);
1179 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001180 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001181 else {
1182 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001183 if (absolute_value > 0.0)
1184 integer_place = 1 + (int)log10(absolute_value);
1185 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001186 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001187 fraction_place = (integer_place > 0)
1188 ? DBL_DIG - integer_place
1189 : DBL_DIG;
1190 size = snprintf(work, sizeof(work), "%0.*f",
1191 fraction_place, number);
1192 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001193 }
1194
Bjorn Reese70a9da52001-04-21 16:57:29 +00001195 /* Remove fractional trailing zeroes */
1196 ptr = after_fraction;
1197 while (*(--ptr) == '0')
1198 ;
1199 if (*ptr != '.')
1200 ptr++;
1201 strcpy(ptr, after_fraction);
1202
1203 /* Finally copy result back to caller */
1204 size = strlen(work) + 1;
1205 if (size > buffersize) {
1206 work[buffersize - 1] = 0;
1207 size = buffersize;
1208 }
1209 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001210 }
1211 break;
1212 }
1213}
1214
Owen Taylor3473f882001-02-23 17:55:21 +00001215/************************************************************************
1216 * *
1217 * Error handling routines *
1218 * *
1219 ************************************************************************/
1220
1221
1222const char *xmlXPathErrorMessages[] = {
1223 "Ok",
1224 "Number encoding",
1225 "Unfinished litteral",
1226 "Start of litteral",
1227 "Expected $ for variable reference",
1228 "Undefined variable",
1229 "Invalid predicate",
1230 "Invalid expression",
1231 "Missing closing curly brace",
1232 "Unregistered function",
1233 "Invalid operand",
1234 "Invalid type",
1235 "Invalid number of arguments",
1236 "Invalid context size",
1237 "Invalid context position",
1238 "Memory allocation error",
1239 "Syntax error",
1240 "Resource error",
1241 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001242 "Undefined namespace prefix",
1243 "Encoding error",
1244 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001245};
1246
1247/**
1248 * xmlXPathError:
1249 * @ctxt: the XPath Parser context
1250 * @file: the file name
1251 * @line: the line number
1252 * @no: the error number
1253 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001254 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001255 */
1256void
1257xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1258 int line, int no) {
1259 int n;
1260 const xmlChar *cur;
1261 const xmlChar *base;
1262
1263 xmlGenericError(xmlGenericErrorContext,
1264 "Error %s:%d: %s\n", file, line,
1265 xmlXPathErrorMessages[no]);
1266
1267 cur = ctxt->cur;
1268 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001269 if ((cur == NULL) || (base == NULL))
1270 return;
1271
Owen Taylor3473f882001-02-23 17:55:21 +00001272 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1273 cur--;
1274 }
1275 n = 0;
1276 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1277 cur--;
1278 if ((*cur == '\n') || (*cur == '\r')) cur++;
1279 base = cur;
1280 n = 0;
1281 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1282 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1283 n++;
1284 }
1285 xmlGenericError(xmlGenericErrorContext, "\n");
1286 cur = ctxt->cur;
1287 while ((*cur == '\n') || (*cur == '\r'))
1288 cur--;
1289 n = 0;
1290 while ((cur != base) && (n++ < 80)) {
1291 xmlGenericError(xmlGenericErrorContext, " ");
1292 base++;
1293 }
1294 xmlGenericError(xmlGenericErrorContext,"^\n");
1295}
1296
1297
1298/************************************************************************
1299 * *
1300 * Routines to handle NodeSets *
1301 * *
1302 ************************************************************************/
1303
1304/**
1305 * xmlXPathCmpNodes:
1306 * @node1: the first node
1307 * @node2: the second node
1308 *
1309 * Compare two nodes w.r.t document order
1310 *
1311 * Returns -2 in case of error 1 if first point < second point, 0 if
1312 * that's the same node, -1 otherwise
1313 */
1314int
1315xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1316 int depth1, depth2;
1317 xmlNodePtr cur, root;
1318
1319 if ((node1 == NULL) || (node2 == NULL))
1320 return(-2);
1321 /*
1322 * a couple of optimizations which will avoid computations in most cases
1323 */
1324 if (node1 == node2)
1325 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001326 if ((node1->type == XML_NAMESPACE_DECL) ||
1327 (node2->type == XML_NAMESPACE_DECL))
1328 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001329 if (node1 == node2->prev)
1330 return(1);
1331 if (node1 == node2->next)
1332 return(-1);
1333
1334 /*
1335 * compute depth to root
1336 */
1337 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1338 if (cur == node1)
1339 return(1);
1340 depth2++;
1341 }
1342 root = cur;
1343 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1344 if (cur == node2)
1345 return(-1);
1346 depth1++;
1347 }
1348 /*
1349 * Distinct document (or distinct entities :-( ) case.
1350 */
1351 if (root != cur) {
1352 return(-2);
1353 }
1354 /*
1355 * get the nearest common ancestor.
1356 */
1357 while (depth1 > depth2) {
1358 depth1--;
1359 node1 = node1->parent;
1360 }
1361 while (depth2 > depth1) {
1362 depth2--;
1363 node2 = node2->parent;
1364 }
1365 while (node1->parent != node2->parent) {
1366 node1 = node1->parent;
1367 node2 = node2->parent;
1368 /* should not happen but just in case ... */
1369 if ((node1 == NULL) || (node2 == NULL))
1370 return(-2);
1371 }
1372 /*
1373 * Find who's first.
1374 */
1375 if (node1 == node2->next)
1376 return(-1);
1377 for (cur = node1->next;cur != NULL;cur = cur->next)
1378 if (cur == node2)
1379 return(1);
1380 return(-1); /* assume there is no sibling list corruption */
1381}
1382
1383/**
1384 * xmlXPathNodeSetSort:
1385 * @set: the node set
1386 *
1387 * Sort the node set in document order
1388 */
1389void
1390xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001391 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001392 xmlNodePtr tmp;
1393
1394 if (set == NULL)
1395 return;
1396
1397 /* Use Shell's sort to sort the node-set */
1398 len = set->nodeNr;
1399 for (incr = len / 2; incr > 0; incr /= 2) {
1400 for (i = incr; i < len; i++) {
1401 j = i - incr;
1402 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001403 if (xmlXPathCmpNodes(set->nodeTab[j],
1404 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001405 tmp = set->nodeTab[j];
1406 set->nodeTab[j] = set->nodeTab[j + incr];
1407 set->nodeTab[j + incr] = tmp;
1408 j -= incr;
1409 } else
1410 break;
1411 }
1412 }
1413 }
1414}
1415
1416#define XML_NODESET_DEFAULT 10
1417/**
1418 * xmlXPathNodeSetCreate:
1419 * @val: an initial xmlNodePtr, or NULL
1420 *
1421 * Create a new xmlNodeSetPtr of type double and of value @val
1422 *
1423 * Returns the newly created object.
1424 */
1425xmlNodeSetPtr
1426xmlXPathNodeSetCreate(xmlNodePtr val) {
1427 xmlNodeSetPtr ret;
1428
1429 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1430 if (ret == NULL) {
1431 xmlGenericError(xmlGenericErrorContext,
1432 "xmlXPathNewNodeSet: out of memory\n");
1433 return(NULL);
1434 }
1435 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1436 if (val != NULL) {
1437 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1438 sizeof(xmlNodePtr));
1439 if (ret->nodeTab == NULL) {
1440 xmlGenericError(xmlGenericErrorContext,
1441 "xmlXPathNewNodeSet: out of memory\n");
1442 return(NULL);
1443 }
1444 memset(ret->nodeTab, 0 ,
1445 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1446 ret->nodeMax = XML_NODESET_DEFAULT;
1447 ret->nodeTab[ret->nodeNr++] = val;
1448 }
1449 return(ret);
1450}
1451
1452/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001453 * xmlXPathNodeSetContains:
1454 * @cur: the node-set
1455 * @val: the node
1456 *
1457 * checks whether @cur contains @val
1458 *
1459 * Returns true (1) if @cur contains @val, false (0) otherwise
1460 */
1461int
1462xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1463 int i;
1464
1465 for (i = 0; i < cur->nodeNr; i++) {
1466 if (cur->nodeTab[i] == val)
1467 return(1);
1468 }
1469 return(0);
1470}
1471
1472/**
Owen Taylor3473f882001-02-23 17:55:21 +00001473 * xmlXPathNodeSetAdd:
1474 * @cur: the initial node set
1475 * @val: a new xmlNodePtr
1476 *
1477 * add a new xmlNodePtr ot an existing NodeSet
1478 */
1479void
1480xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1481 int i;
1482
1483 if (val == NULL) return;
1484
1485 /*
1486 * check against doublons
1487 */
1488 for (i = 0;i < cur->nodeNr;i++)
1489 if (cur->nodeTab[i] == val) return;
1490
1491 /*
1492 * grow the nodeTab if needed
1493 */
1494 if (cur->nodeMax == 0) {
1495 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1496 sizeof(xmlNodePtr));
1497 if (cur->nodeTab == NULL) {
1498 xmlGenericError(xmlGenericErrorContext,
1499 "xmlXPathNodeSetAdd: out of memory\n");
1500 return;
1501 }
1502 memset(cur->nodeTab, 0 ,
1503 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1504 cur->nodeMax = XML_NODESET_DEFAULT;
1505 } else if (cur->nodeNr == cur->nodeMax) {
1506 xmlNodePtr *temp;
1507
1508 cur->nodeMax *= 2;
1509 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1510 sizeof(xmlNodePtr));
1511 if (temp == NULL) {
1512 xmlGenericError(xmlGenericErrorContext,
1513 "xmlXPathNodeSetAdd: out of memory\n");
1514 return;
1515 }
1516 cur->nodeTab = temp;
1517 }
1518 cur->nodeTab[cur->nodeNr++] = val;
1519}
1520
1521/**
1522 * xmlXPathNodeSetAddUnique:
1523 * @cur: the initial node set
1524 * @val: a new xmlNodePtr
1525 *
1526 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1527 * when we are sure the node is not already in the set.
1528 */
1529void
1530xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1531 if (val == NULL) return;
1532
1533 /*
1534 * grow the nodeTab if needed
1535 */
1536 if (cur->nodeMax == 0) {
1537 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1538 sizeof(xmlNodePtr));
1539 if (cur->nodeTab == NULL) {
1540 xmlGenericError(xmlGenericErrorContext,
1541 "xmlXPathNodeSetAddUnique: out of memory\n");
1542 return;
1543 }
1544 memset(cur->nodeTab, 0 ,
1545 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1546 cur->nodeMax = XML_NODESET_DEFAULT;
1547 } else if (cur->nodeNr == cur->nodeMax) {
1548 xmlNodePtr *temp;
1549
1550 cur->nodeMax *= 2;
1551 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1552 sizeof(xmlNodePtr));
1553 if (temp == NULL) {
1554 xmlGenericError(xmlGenericErrorContext,
1555 "xmlXPathNodeSetAddUnique: out of memory\n");
1556 return;
1557 }
1558 cur->nodeTab = temp;
1559 }
1560 cur->nodeTab[cur->nodeNr++] = val;
1561}
1562
1563/**
1564 * xmlXPathNodeSetMerge:
1565 * @val1: the first NodeSet or NULL
1566 * @val2: the second NodeSet
1567 *
1568 * Merges two nodesets, all nodes from @val2 are added to @val1
1569 * if @val1 is NULL, a new set is created and copied from @val2
1570 *
1571 * Returns val1 once extended or NULL in case of error.
1572 */
1573xmlNodeSetPtr
1574xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001575 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001576
1577 if (val2 == NULL) return(val1);
1578 if (val1 == NULL) {
1579 val1 = xmlXPathNodeSetCreate(NULL);
1580 }
1581
1582 initNr = val1->nodeNr;
1583
1584 for (i = 0;i < val2->nodeNr;i++) {
1585 /*
1586 * check against doublons
1587 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001588 skip = 0;
1589 for (j = 0; j < initNr; j++) {
1590 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1591 skip = 1;
1592 break;
1593 }
1594 }
1595 if (skip)
1596 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001597
1598 /*
1599 * grow the nodeTab if needed
1600 */
1601 if (val1->nodeMax == 0) {
1602 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1603 sizeof(xmlNodePtr));
1604 if (val1->nodeTab == NULL) {
1605 xmlGenericError(xmlGenericErrorContext,
1606 "xmlXPathNodeSetMerge: out of memory\n");
1607 return(NULL);
1608 }
1609 memset(val1->nodeTab, 0 ,
1610 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1611 val1->nodeMax = XML_NODESET_DEFAULT;
1612 } else if (val1->nodeNr == val1->nodeMax) {
1613 xmlNodePtr *temp;
1614
1615 val1->nodeMax *= 2;
1616 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1617 sizeof(xmlNodePtr));
1618 if (temp == NULL) {
1619 xmlGenericError(xmlGenericErrorContext,
1620 "xmlXPathNodeSetMerge: out of memory\n");
1621 return(NULL);
1622 }
1623 val1->nodeTab = temp;
1624 }
1625 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1626 }
1627
1628 return(val1);
1629}
1630
1631/**
1632 * xmlXPathNodeSetDel:
1633 * @cur: the initial node set
1634 * @val: an xmlNodePtr
1635 *
1636 * Removes an xmlNodePtr from an existing NodeSet
1637 */
1638void
1639xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1640 int i;
1641
1642 if (cur == NULL) return;
1643 if (val == NULL) return;
1644
1645 /*
1646 * check against doublons
1647 */
1648 for (i = 0;i < cur->nodeNr;i++)
1649 if (cur->nodeTab[i] == val) break;
1650
1651 if (i >= cur->nodeNr) {
1652#ifdef DEBUG
1653 xmlGenericError(xmlGenericErrorContext,
1654 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1655 val->name);
1656#endif
1657 return;
1658 }
1659 cur->nodeNr--;
1660 for (;i < cur->nodeNr;i++)
1661 cur->nodeTab[i] = cur->nodeTab[i + 1];
1662 cur->nodeTab[cur->nodeNr] = NULL;
1663}
1664
1665/**
1666 * xmlXPathNodeSetRemove:
1667 * @cur: the initial node set
1668 * @val: the index to remove
1669 *
1670 * Removes an entry from an existing NodeSet list.
1671 */
1672void
1673xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1674 if (cur == NULL) return;
1675 if (val >= cur->nodeNr) return;
1676 cur->nodeNr--;
1677 for (;val < cur->nodeNr;val++)
1678 cur->nodeTab[val] = cur->nodeTab[val + 1];
1679 cur->nodeTab[cur->nodeNr] = NULL;
1680}
1681
1682/**
1683 * xmlXPathFreeNodeSet:
1684 * @obj: the xmlNodeSetPtr to free
1685 *
1686 * Free the NodeSet compound (not the actual nodes !).
1687 */
1688void
1689xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1690 if (obj == NULL) return;
1691 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001692 xmlFree(obj->nodeTab);
1693 }
Owen Taylor3473f882001-02-23 17:55:21 +00001694 xmlFree(obj);
1695}
1696
1697/**
1698 * xmlXPathFreeValueTree:
1699 * @obj: the xmlNodeSetPtr to free
1700 *
1701 * Free the NodeSet compound and the actual tree, this is different
1702 * from xmlXPathFreeNodeSet()
1703 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001704static void
Owen Taylor3473f882001-02-23 17:55:21 +00001705xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1706 int i;
1707
1708 if (obj == NULL) return;
1709 for (i = 0;i < obj->nodeNr;i++)
1710 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001711 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001712
1713 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001714 xmlFree(obj->nodeTab);
1715 }
Owen Taylor3473f882001-02-23 17:55:21 +00001716 xmlFree(obj);
1717}
1718
1719#if defined(DEBUG) || defined(DEBUG_STEP)
1720/**
1721 * xmlGenericErrorContextNodeSet:
1722 * @output: a FILE * for the output
1723 * @obj: the xmlNodeSetPtr to free
1724 *
1725 * Quick display of a NodeSet
1726 */
1727void
1728xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1729 int i;
1730
1731 if (output == NULL) output = xmlGenericErrorContext;
1732 if (obj == NULL) {
1733 fprintf(output, "NodeSet == NULL !\n");
1734 return;
1735 }
1736 if (obj->nodeNr == 0) {
1737 fprintf(output, "NodeSet is empty\n");
1738 return;
1739 }
1740 if (obj->nodeTab == NULL) {
1741 fprintf(output, " nodeTab == NULL !\n");
1742 return;
1743 }
1744 for (i = 0; i < obj->nodeNr; i++) {
1745 if (obj->nodeTab[i] == NULL) {
1746 fprintf(output, " NULL !\n");
1747 return;
1748 }
1749 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1750 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1751 fprintf(output, " /");
1752 else if (obj->nodeTab[i]->name == NULL)
1753 fprintf(output, " noname!");
1754 else fprintf(output, " %s", obj->nodeTab[i]->name);
1755 }
1756 fprintf(output, "\n");
1757}
1758#endif
1759
1760/**
1761 * xmlXPathNewNodeSet:
1762 * @val: the NodePtr value
1763 *
1764 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1765 * it with the single Node @val
1766 *
1767 * Returns the newly created object.
1768 */
1769xmlXPathObjectPtr
1770xmlXPathNewNodeSet(xmlNodePtr val) {
1771 xmlXPathObjectPtr ret;
1772
1773 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1774 if (ret == NULL) {
1775 xmlGenericError(xmlGenericErrorContext,
1776 "xmlXPathNewNodeSet: out of memory\n");
1777 return(NULL);
1778 }
1779 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1780 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001781 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001782 ret->nodesetval = xmlXPathNodeSetCreate(val);
1783 return(ret);
1784}
1785
1786/**
1787 * xmlXPathNewValueTree:
1788 * @val: the NodePtr value
1789 *
1790 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1791 * it with the tree root @val
1792 *
1793 * Returns the newly created object.
1794 */
1795xmlXPathObjectPtr
1796xmlXPathNewValueTree(xmlNodePtr val) {
1797 xmlXPathObjectPtr ret;
1798
1799 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1800 if (ret == NULL) {
1801 xmlGenericError(xmlGenericErrorContext,
1802 "xmlXPathNewNodeSet: out of memory\n");
1803 return(NULL);
1804 }
1805 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1806 ret->type = XPATH_XSLT_TREE;
1807 ret->nodesetval = xmlXPathNodeSetCreate(val);
1808 return(ret);
1809}
1810
1811/**
1812 * xmlXPathNewNodeSetList:
1813 * @val: an existing NodeSet
1814 *
1815 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1816 * it with the Nodeset @val
1817 *
1818 * Returns the newly created object.
1819 */
1820xmlXPathObjectPtr
1821xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1822 xmlXPathObjectPtr ret;
1823 int i;
1824
1825 if (val == NULL)
1826 ret = NULL;
1827 else if (val->nodeTab == NULL)
1828 ret = xmlXPathNewNodeSet(NULL);
1829 else
1830 {
1831 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1832 for (i = 1; i < val->nodeNr; ++i)
1833 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1834 }
1835
1836 return(ret);
1837}
1838
1839/**
1840 * xmlXPathWrapNodeSet:
1841 * @val: the NodePtr value
1842 *
1843 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1844 *
1845 * Returns the newly created object.
1846 */
1847xmlXPathObjectPtr
1848xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1849 xmlXPathObjectPtr ret;
1850
1851 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1852 if (ret == NULL) {
1853 xmlGenericError(xmlGenericErrorContext,
1854 "xmlXPathWrapNodeSet: out of memory\n");
1855 return(NULL);
1856 }
1857 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1858 ret->type = XPATH_NODESET;
1859 ret->nodesetval = val;
1860 return(ret);
1861}
1862
1863/**
1864 * xmlXPathFreeNodeSetList:
1865 * @obj: an existing NodeSetList object
1866 *
1867 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1868 * the list contrary to xmlXPathFreeObject().
1869 */
1870void
1871xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1872 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001873 xmlFree(obj);
1874}
1875
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001876/**
1877 * xmlXPathDifference:
1878 * @nodes1: a node-set
1879 * @nodes2: a node-set
1880 *
1881 * Implements the EXSLT - Sets difference() function:
1882 * node-set set:difference (node-set, node-set)
1883 *
1884 * Returns the difference between the two node sets, or nodes1 if
1885 * nodes2 is empty
1886 */
1887xmlNodeSetPtr
1888xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1889 xmlNodeSetPtr ret;
1890 int i, l1;
1891 xmlNodePtr cur;
1892
1893 if (xmlXPathNodeSetIsEmpty(nodes2))
1894 return(nodes1);
1895
1896 ret = xmlXPathNodeSetCreate(NULL);
1897 if (xmlXPathNodeSetIsEmpty(nodes1))
1898 return(ret);
1899
1900 l1 = xmlXPathNodeSetGetLength(nodes1);
1901
1902 for (i = 0; i < l1; i++) {
1903 cur = xmlXPathNodeSetItem(nodes1, i);
1904 if (!xmlXPathNodeSetContains(nodes2, cur))
1905 xmlXPathNodeSetAddUnique(ret, cur);
1906 }
1907 return(ret);
1908}
1909
1910/**
1911 * xmlXPathIntersection:
1912 * @nodes1: a node-set
1913 * @nodes2: a node-set
1914 *
1915 * Implements the EXSLT - Sets intersection() function:
1916 * node-set set:intersection (node-set, node-set)
1917 *
1918 * Returns a node set comprising the nodes that are within both the
1919 * node sets passed as arguments
1920 */
1921xmlNodeSetPtr
1922xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1923 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
1924 int i, l1;
1925 xmlNodePtr cur;
1926
1927 if (xmlXPathNodeSetIsEmpty(nodes1))
1928 return(ret);
1929 if (xmlXPathNodeSetIsEmpty(nodes2))
1930 return(ret);
1931
1932 l1 = xmlXPathNodeSetGetLength(nodes1);
1933
1934 for (i = 0; i < l1; i++) {
1935 cur = xmlXPathNodeSetItem(nodes1, i);
1936 if (xmlXPathNodeSetContains(nodes2, cur))
1937 xmlXPathNodeSetAddUnique(ret, cur);
1938 }
1939 return(ret);
1940}
1941
1942/**
1943 * xmlXPathDistinctSorted:
1944 * @nodes: a node-set, sorted by document order
1945 *
1946 * Implements the EXSLT - Sets distinct() function:
1947 * node-set set:distinct (node-set)
1948 *
1949 * Returns a subset of the nodes contained in @nodes, or @nodes if
1950 * it is empty
1951 */
1952xmlNodeSetPtr
1953xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
1954 xmlNodeSetPtr ret;
1955 xmlHashTablePtr hash;
1956 int i, l;
1957 xmlChar * strval;
1958 xmlNodePtr cur;
1959
1960 if (xmlXPathNodeSetIsEmpty(nodes))
1961 return(nodes);
1962
1963 ret = xmlXPathNodeSetCreate(NULL);
1964 l = xmlXPathNodeSetGetLength(nodes);
1965 hash = xmlHashCreate (l);
1966 for (i = 0; i < l; i++) {
1967 cur = xmlXPathNodeSetItem(nodes, i);
1968 strval = xmlXPathCastNodeToString(cur);
1969 if (xmlHashLookup(hash, strval) == NULL) {
1970 xmlHashAddEntry(hash, strval, strval);
1971 xmlXPathNodeSetAddUnique(ret, cur);
1972 } else {
1973 xmlFree(strval);
1974 }
1975 }
1976 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
1977 return(ret);
1978}
1979
1980/**
1981 * xmlXPathDistinct:
1982 * @nodes: a node-set
1983 *
1984 * Implements the EXSLT - Sets distinct() function:
1985 * node-set set:distinct (node-set)
1986 * @nodes is sorted by document order, then #exslSetsDistinctSorted
1987 * is called with the sorted node-set
1988 *
1989 * Returns a subset of the nodes contained in @nodes, or @nodes if
1990 * it is empty
1991 */
1992xmlNodeSetPtr
1993xmlXPathDistinct (xmlNodeSetPtr nodes) {
1994 if (xmlXPathNodeSetIsEmpty(nodes))
1995 return(nodes);
1996
1997 xmlXPathNodeSetSort(nodes);
1998 return(xmlXPathDistinctSorted(nodes));
1999}
2000
2001/**
2002 * xmlXPathHasSameNodes:
2003 * @nodes1: a node-set
2004 * @nodes2: a node-set
2005 *
2006 * Implements the EXSLT - Sets has-same-nodes function:
2007 * boolean set:has-same-node(node-set, node-set)
2008 *
2009 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2010 * otherwise
2011 */
2012int
2013xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2014 int i, l;
2015 xmlNodePtr cur;
2016
2017 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2018 xmlXPathNodeSetIsEmpty(nodes2))
2019 return(0);
2020
2021 l = xmlXPathNodeSetGetLength(nodes1);
2022 for (i = 0; i < l; i++) {
2023 cur = xmlXPathNodeSetItem(nodes1, i);
2024 if (xmlXPathNodeSetContains(nodes2, cur))
2025 return(1);
2026 }
2027 return(0);
2028}
2029
2030/**
2031 * xmlXPathNodeLeadingSorted:
2032 * @nodes: a node-set, sorted by document order
2033 * @node: a node
2034 *
2035 * Implements the EXSLT - Sets leading() function:
2036 * node-set set:leading (node-set, node-set)
2037 *
2038 * Returns the nodes in @nodes that precede @node in document order,
2039 * @nodes if @node is NULL or an empty node-set if @nodes
2040 * doesn't contain @node
2041 */
2042xmlNodeSetPtr
2043xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2044 int i, l;
2045 xmlNodePtr cur;
2046 xmlNodeSetPtr ret;
2047
2048 if (node == NULL)
2049 return(nodes);
2050
2051 ret = xmlXPathNodeSetCreate(NULL);
2052 if (xmlXPathNodeSetIsEmpty(nodes) ||
2053 (!xmlXPathNodeSetContains(nodes, node)))
2054 return(ret);
2055
2056 l = xmlXPathNodeSetGetLength(nodes);
2057 for (i = 0; i < l; i++) {
2058 cur = xmlXPathNodeSetItem(nodes, i);
2059 if (cur == node)
2060 break;
2061 xmlXPathNodeSetAddUnique(ret, cur);
2062 }
2063 return(ret);
2064}
2065
2066/**
2067 * xmlXPathNodeLeading:
2068 * @nodes: a node-set
2069 * @node: a node
2070 *
2071 * Implements the EXSLT - Sets leading() function:
2072 * node-set set:leading (node-set, node-set)
2073 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2074 * is called.
2075 *
2076 * Returns the nodes in @nodes that precede @node in document order,
2077 * @nodes if @node is NULL or an empty node-set if @nodes
2078 * doesn't contain @node
2079 */
2080xmlNodeSetPtr
2081xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2082 xmlXPathNodeSetSort(nodes);
2083 return(xmlXPathNodeLeadingSorted(nodes, node));
2084}
2085
2086/**
2087 * xmlXPathLeadingSorted:
2088 * @nodes1: a node-set, sorted by document order
2089 * @nodes2: a node-set, sorted by document order
2090 *
2091 * Implements the EXSLT - Sets leading() function:
2092 * node-set set:leading (node-set, node-set)
2093 *
2094 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2095 * in document order, @nodes1 if @nodes2 is NULL or empty or
2096 * an empty node-set if @nodes1 doesn't contain @nodes2
2097 */
2098xmlNodeSetPtr
2099xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2100 if (xmlXPathNodeSetIsEmpty(nodes2))
2101 return(nodes1);
2102 return(xmlXPathNodeLeadingSorted(nodes1,
2103 xmlXPathNodeSetItem(nodes2, 1)));
2104}
2105
2106/**
2107 * xmlXPathLeading:
2108 * @nodes1: a node-set
2109 * @nodes2: a node-set
2110 *
2111 * Implements the EXSLT - Sets leading() function:
2112 * node-set set:leading (node-set, node-set)
2113 * @nodes1 and @nodes2 are sorted by document order, then
2114 * #exslSetsLeadingSorted is called.
2115 *
2116 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2117 * in document order, @nodes1 if @nodes2 is NULL or empty or
2118 * an empty node-set if @nodes1 doesn't contain @nodes2
2119 */
2120xmlNodeSetPtr
2121xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2122 if (xmlXPathNodeSetIsEmpty(nodes2))
2123 return(nodes1);
2124 if (xmlXPathNodeSetIsEmpty(nodes1))
2125 return(xmlXPathNodeSetCreate(NULL));
2126 xmlXPathNodeSetSort(nodes1);
2127 xmlXPathNodeSetSort(nodes2);
2128 return(xmlXPathNodeLeadingSorted(nodes1,
2129 xmlXPathNodeSetItem(nodes2, 1)));
2130}
2131
2132/**
2133 * xmlXPathNodeTrailingSorted:
2134 * @nodes: a node-set, sorted by document order
2135 * @node: a node
2136 *
2137 * Implements the EXSLT - Sets trailing() function:
2138 * node-set set:trailing (node-set, node-set)
2139 *
2140 * Returns the nodes in @nodes that follow @node in document order,
2141 * @nodes if @node is NULL or an empty node-set if @nodes
2142 * doesn't contain @node
2143 */
2144xmlNodeSetPtr
2145xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2146 int i, l;
2147 xmlNodePtr cur;
2148 xmlNodeSetPtr ret;
2149
2150 if (node == NULL)
2151 return(nodes);
2152
2153 ret = xmlXPathNodeSetCreate(NULL);
2154 if (xmlXPathNodeSetIsEmpty(nodes) ||
2155 (!xmlXPathNodeSetContains(nodes, node)))
2156 return(ret);
2157
2158 l = xmlXPathNodeSetGetLength(nodes);
2159 for (i = 0; i < l; i++) {
2160 cur = xmlXPathNodeSetItem(nodes, i);
2161 if (cur == node)
2162 break;
2163 xmlXPathNodeSetAddUnique(ret, cur);
2164 }
2165 return(ret);
2166}
2167
2168/**
2169 * xmlXPathNodeTrailing:
2170 * @nodes: a node-set
2171 * @node: a node
2172 *
2173 * Implements the EXSLT - Sets trailing() function:
2174 * node-set set:trailing (node-set, node-set)
2175 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2176 * is called.
2177 *
2178 * Returns the nodes in @nodes that follow @node in document order,
2179 * @nodes if @node is NULL or an empty node-set if @nodes
2180 * doesn't contain @node
2181 */
2182xmlNodeSetPtr
2183xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2184 xmlXPathNodeSetSort(nodes);
2185 return(xmlXPathNodeTrailingSorted(nodes, node));
2186}
2187
2188/**
2189 * xmlXPathTrailingSorted:
2190 * @nodes1: a node-set, sorted by document order
2191 * @nodes2: a node-set, sorted by document order
2192 *
2193 * Implements the EXSLT - Sets trailing() function:
2194 * node-set set:trailing (node-set, node-set)
2195 *
2196 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2197 * in document order, @nodes1 if @nodes2 is NULL or empty or
2198 * an empty node-set if @nodes1 doesn't contain @nodes2
2199 */
2200xmlNodeSetPtr
2201xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2202 if (xmlXPathNodeSetIsEmpty(nodes2))
2203 return(nodes1);
2204 return(xmlXPathNodeTrailingSorted(nodes1,
2205 xmlXPathNodeSetItem(nodes2, 0)));
2206}
2207
2208/**
2209 * xmlXPathTrailing:
2210 * @nodes1: a node-set
2211 * @nodes2: a node-set
2212 *
2213 * Implements the EXSLT - Sets trailing() function:
2214 * node-set set:trailing (node-set, node-set)
2215 * @nodes1 and @nodes2 are sorted by document order, then
2216 * #xmlXPathTrailingSorted is called.
2217 *
2218 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2219 * in document order, @nodes1 if @nodes2 is NULL or empty or
2220 * an empty node-set if @nodes1 doesn't contain @nodes2
2221 */
2222xmlNodeSetPtr
2223xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2224 if (xmlXPathNodeSetIsEmpty(nodes2))
2225 return(nodes1);
2226 if (xmlXPathNodeSetIsEmpty(nodes1))
2227 return(xmlXPathNodeSetCreate(NULL));
2228 xmlXPathNodeSetSort(nodes1);
2229 xmlXPathNodeSetSort(nodes2);
2230 return(xmlXPathNodeTrailingSorted(nodes1,
2231 xmlXPathNodeSetItem(nodes2, 0)));
2232}
2233
Owen Taylor3473f882001-02-23 17:55:21 +00002234/************************************************************************
2235 * *
2236 * Routines to handle extra functions *
2237 * *
2238 ************************************************************************/
2239
2240/**
2241 * xmlXPathRegisterFunc:
2242 * @ctxt: the XPath context
2243 * @name: the function name
2244 * @f: the function implementation or NULL
2245 *
2246 * Register a new function. If @f is NULL it unregisters the function
2247 *
2248 * Returns 0 in case of success, -1 in case of error
2249 */
2250int
2251xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2252 xmlXPathFunction f) {
2253 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2254}
2255
2256/**
2257 * xmlXPathRegisterFuncNS:
2258 * @ctxt: the XPath context
2259 * @name: the function name
2260 * @ns_uri: the function namespace URI
2261 * @f: the function implementation or NULL
2262 *
2263 * Register a new function. If @f is NULL it unregisters the function
2264 *
2265 * Returns 0 in case of success, -1 in case of error
2266 */
2267int
2268xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2269 const xmlChar *ns_uri, xmlXPathFunction f) {
2270 if (ctxt == NULL)
2271 return(-1);
2272 if (name == NULL)
2273 return(-1);
2274
2275 if (ctxt->funcHash == NULL)
2276 ctxt->funcHash = xmlHashCreate(0);
2277 if (ctxt->funcHash == NULL)
2278 return(-1);
2279 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2280}
2281
2282/**
2283 * xmlXPathFunctionLookup:
2284 * @ctxt: the XPath context
2285 * @name: the function name
2286 *
2287 * Search in the Function array of the context for the given
2288 * function.
2289 *
2290 * Returns the xmlXPathFunction or NULL if not found
2291 */
2292xmlXPathFunction
2293xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2294 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2295}
2296
2297/**
2298 * xmlXPathFunctionLookupNS:
2299 * @ctxt: the XPath context
2300 * @name: the function name
2301 * @ns_uri: the function namespace URI
2302 *
2303 * Search in the Function array of the context for the given
2304 * function.
2305 *
2306 * Returns the xmlXPathFunction or NULL if not found
2307 */
2308xmlXPathFunction
2309xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2310 const xmlChar *ns_uri) {
2311 if (ctxt == NULL)
2312 return(NULL);
2313 if (ctxt->funcHash == NULL)
2314 return(NULL);
2315 if (name == NULL)
2316 return(NULL);
2317
2318 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2319}
2320
2321/**
2322 * xmlXPathRegisteredFuncsCleanup:
2323 * @ctxt: the XPath context
2324 *
2325 * Cleanup the XPath context data associated to registered functions
2326 */
2327void
2328xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2329 if (ctxt == NULL)
2330 return;
2331
2332 xmlHashFree(ctxt->funcHash, NULL);
2333 ctxt->funcHash = NULL;
2334}
2335
2336/************************************************************************
2337 * *
2338 * Routines to handle Variable *
2339 * *
2340 ************************************************************************/
2341
2342/**
2343 * xmlXPathRegisterVariable:
2344 * @ctxt: the XPath context
2345 * @name: the variable name
2346 * @value: the variable value or NULL
2347 *
2348 * Register a new variable value. If @value is NULL it unregisters
2349 * the variable
2350 *
2351 * Returns 0 in case of success, -1 in case of error
2352 */
2353int
2354xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2355 xmlXPathObjectPtr value) {
2356 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2357}
2358
2359/**
2360 * xmlXPathRegisterVariableNS:
2361 * @ctxt: the XPath context
2362 * @name: the variable name
2363 * @ns_uri: the variable namespace URI
2364 * @value: the variable value or NULL
2365 *
2366 * Register a new variable value. If @value is NULL it unregisters
2367 * the variable
2368 *
2369 * Returns 0 in case of success, -1 in case of error
2370 */
2371int
2372xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2373 const xmlChar *ns_uri,
2374 xmlXPathObjectPtr value) {
2375 if (ctxt == NULL)
2376 return(-1);
2377 if (name == NULL)
2378 return(-1);
2379
2380 if (ctxt->varHash == NULL)
2381 ctxt->varHash = xmlHashCreate(0);
2382 if (ctxt->varHash == NULL)
2383 return(-1);
2384 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2385 (void *) value,
2386 (xmlHashDeallocator)xmlXPathFreeObject));
2387}
2388
2389/**
2390 * xmlXPathRegisterVariableLookup:
2391 * @ctxt: the XPath context
2392 * @f: the lookup function
2393 * @data: the lookup data
2394 *
2395 * register an external mechanism to do variable lookup
2396 */
2397void
2398xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2399 xmlXPathVariableLookupFunc f, void *data) {
2400 if (ctxt == NULL)
2401 return;
2402 ctxt->varLookupFunc = (void *) f;
2403 ctxt->varLookupData = data;
2404}
2405
2406/**
2407 * xmlXPathVariableLookup:
2408 * @ctxt: the XPath context
2409 * @name: the variable name
2410 *
2411 * Search in the Variable array of the context for the given
2412 * variable value.
2413 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002414 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002415 */
2416xmlXPathObjectPtr
2417xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2418 if (ctxt == NULL)
2419 return(NULL);
2420
2421 if (ctxt->varLookupFunc != NULL) {
2422 xmlXPathObjectPtr ret;
2423
2424 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2425 (ctxt->varLookupData, name, NULL);
2426 if (ret != NULL) return(ret);
2427 }
2428 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2429}
2430
2431/**
2432 * xmlXPathVariableLookupNS:
2433 * @ctxt: the XPath context
2434 * @name: the variable name
2435 * @ns_uri: the variable namespace URI
2436 *
2437 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002438 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002439 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002440 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002441 */
2442xmlXPathObjectPtr
2443xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2444 const xmlChar *ns_uri) {
2445 if (ctxt == NULL)
2446 return(NULL);
2447
2448 if (ctxt->varLookupFunc != NULL) {
2449 xmlXPathObjectPtr ret;
2450
2451 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2452 (ctxt->varLookupData, name, ns_uri);
2453 if (ret != NULL) return(ret);
2454 }
2455
2456 if (ctxt->varHash == NULL)
2457 return(NULL);
2458 if (name == NULL)
2459 return(NULL);
2460
Daniel Veillard8c357d52001-07-03 23:43:33 +00002461 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2462 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002463}
2464
2465/**
2466 * xmlXPathRegisteredVariablesCleanup:
2467 * @ctxt: the XPath context
2468 *
2469 * Cleanup the XPath context data associated to registered variables
2470 */
2471void
2472xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2473 if (ctxt == NULL)
2474 return;
2475
Daniel Veillard76d66f42001-05-16 21:05:17 +00002476 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002477 ctxt->varHash = NULL;
2478}
2479
2480/**
2481 * xmlXPathRegisterNs:
2482 * @ctxt: the XPath context
2483 * @prefix: the namespace prefix
2484 * @ns_uri: the namespace name
2485 *
2486 * Register a new namespace. If @ns_uri is NULL it unregisters
2487 * the namespace
2488 *
2489 * Returns 0 in case of success, -1 in case of error
2490 */
2491int
2492xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2493 const xmlChar *ns_uri) {
2494 if (ctxt == NULL)
2495 return(-1);
2496 if (prefix == NULL)
2497 return(-1);
2498
2499 if (ctxt->nsHash == NULL)
2500 ctxt->nsHash = xmlHashCreate(10);
2501 if (ctxt->nsHash == NULL)
2502 return(-1);
2503 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2504 (xmlHashDeallocator)xmlFree));
2505}
2506
2507/**
2508 * xmlXPathNsLookup:
2509 * @ctxt: the XPath context
2510 * @prefix: the namespace prefix value
2511 *
2512 * Search in the namespace declaration array of the context for the given
2513 * namespace name associated to the given prefix
2514 *
2515 * Returns the value or NULL if not found
2516 */
2517const xmlChar *
2518xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2519 if (ctxt == NULL)
2520 return(NULL);
2521 if (prefix == NULL)
2522 return(NULL);
2523
2524#ifdef XML_XML_NAMESPACE
2525 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2526 return(XML_XML_NAMESPACE);
2527#endif
2528
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002529 if (ctxt->namespaces != NULL) {
2530 int i;
2531
2532 for (i = 0;i < ctxt->nsNr;i++) {
2533 if ((ctxt->namespaces[i] != NULL) &&
2534 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2535 return(ctxt->namespaces[i]->href);
2536 }
2537 }
Owen Taylor3473f882001-02-23 17:55:21 +00002538
2539 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2540}
2541
2542/**
2543 * xmlXPathRegisteredVariablesCleanup:
2544 * @ctxt: the XPath context
2545 *
2546 * Cleanup the XPath context data associated to registered variables
2547 */
2548void
2549xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2550 if (ctxt == NULL)
2551 return;
2552
2553 xmlHashFree(ctxt->nsHash, NULL);
2554 ctxt->nsHash = NULL;
2555}
2556
2557/************************************************************************
2558 * *
2559 * Routines to handle Values *
2560 * *
2561 ************************************************************************/
2562
2563/* Allocations are terrible, one need to optimize all this !!! */
2564
2565/**
2566 * xmlXPathNewFloat:
2567 * @val: the double value
2568 *
2569 * Create a new xmlXPathObjectPtr of type double and of value @val
2570 *
2571 * Returns the newly created object.
2572 */
2573xmlXPathObjectPtr
2574xmlXPathNewFloat(double val) {
2575 xmlXPathObjectPtr ret;
2576
2577 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2578 if (ret == NULL) {
2579 xmlGenericError(xmlGenericErrorContext,
2580 "xmlXPathNewFloat: out of memory\n");
2581 return(NULL);
2582 }
2583 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2584 ret->type = XPATH_NUMBER;
2585 ret->floatval = val;
2586 return(ret);
2587}
2588
2589/**
2590 * xmlXPathNewBoolean:
2591 * @val: the boolean value
2592 *
2593 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2594 *
2595 * Returns the newly created object.
2596 */
2597xmlXPathObjectPtr
2598xmlXPathNewBoolean(int val) {
2599 xmlXPathObjectPtr ret;
2600
2601 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2602 if (ret == NULL) {
2603 xmlGenericError(xmlGenericErrorContext,
2604 "xmlXPathNewBoolean: out of memory\n");
2605 return(NULL);
2606 }
2607 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2608 ret->type = XPATH_BOOLEAN;
2609 ret->boolval = (val != 0);
2610 return(ret);
2611}
2612
2613/**
2614 * xmlXPathNewString:
2615 * @val: the xmlChar * value
2616 *
2617 * Create a new xmlXPathObjectPtr of type string and of value @val
2618 *
2619 * Returns the newly created object.
2620 */
2621xmlXPathObjectPtr
2622xmlXPathNewString(const xmlChar *val) {
2623 xmlXPathObjectPtr ret;
2624
2625 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2626 if (ret == NULL) {
2627 xmlGenericError(xmlGenericErrorContext,
2628 "xmlXPathNewString: out of memory\n");
2629 return(NULL);
2630 }
2631 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2632 ret->type = XPATH_STRING;
2633 if (val != NULL)
2634 ret->stringval = xmlStrdup(val);
2635 else
2636 ret->stringval = xmlStrdup((const xmlChar *)"");
2637 return(ret);
2638}
2639
2640/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002641 * xmlXPathWrapString:
2642 * @val: the xmlChar * value
2643 *
2644 * Wraps the @val string into an XPath object.
2645 *
2646 * Returns the newly created object.
2647 */
2648xmlXPathObjectPtr
2649xmlXPathWrapString (xmlChar *val) {
2650 xmlXPathObjectPtr ret;
2651
2652 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2653 if (ret == NULL) {
2654 xmlGenericError(xmlGenericErrorContext,
2655 "xmlXPathWrapString: out of memory\n");
2656 return(NULL);
2657 }
2658 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2659 ret->type = XPATH_STRING;
2660 ret->stringval = val;
2661 return(ret);
2662}
2663
2664/**
Owen Taylor3473f882001-02-23 17:55:21 +00002665 * xmlXPathNewCString:
2666 * @val: the char * value
2667 *
2668 * Create a new xmlXPathObjectPtr of type string and of value @val
2669 *
2670 * Returns the newly created object.
2671 */
2672xmlXPathObjectPtr
2673xmlXPathNewCString(const char *val) {
2674 xmlXPathObjectPtr ret;
2675
2676 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2677 if (ret == NULL) {
2678 xmlGenericError(xmlGenericErrorContext,
2679 "xmlXPathNewCString: out of memory\n");
2680 return(NULL);
2681 }
2682 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2683 ret->type = XPATH_STRING;
2684 ret->stringval = xmlStrdup(BAD_CAST val);
2685 return(ret);
2686}
2687
2688/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002689 * xmlXPathWrapCString:
2690 * @val: the char * value
2691 *
2692 * Wraps a string into an XPath object.
2693 *
2694 * Returns the newly created object.
2695 */
2696xmlXPathObjectPtr
2697xmlXPathWrapCString (char * val) {
2698 return(xmlXPathWrapString((xmlChar *)(val)));
2699}
2700
2701/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002702 * xmlXPathWrapExternal:
2703 * @val: the user data
2704 *
2705 * Wraps the @val data into an XPath object.
2706 *
2707 * Returns the newly created object.
2708 */
2709xmlXPathObjectPtr
2710xmlXPathWrapExternal (void *val) {
2711 xmlXPathObjectPtr ret;
2712
2713 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2714 if (ret == NULL) {
2715 xmlGenericError(xmlGenericErrorContext,
2716 "xmlXPathWrapString: out of memory\n");
2717 return(NULL);
2718 }
2719 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2720 ret->type = XPATH_USERS;
2721 ret->user = val;
2722 return(ret);
2723}
2724
2725/**
Owen Taylor3473f882001-02-23 17:55:21 +00002726 * xmlXPathObjectCopy:
2727 * @val: the original object
2728 *
2729 * allocate a new copy of a given object
2730 *
2731 * Returns the newly created object.
2732 */
2733xmlXPathObjectPtr
2734xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2735 xmlXPathObjectPtr ret;
2736
2737 if (val == NULL)
2738 return(NULL);
2739
2740 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2741 if (ret == NULL) {
2742 xmlGenericError(xmlGenericErrorContext,
2743 "xmlXPathObjectCopy: out of memory\n");
2744 return(NULL);
2745 }
2746 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2747 switch (val->type) {
2748 case XPATH_BOOLEAN:
2749 case XPATH_NUMBER:
2750 case XPATH_POINT:
2751 case XPATH_RANGE:
2752 break;
2753 case XPATH_STRING:
2754 ret->stringval = xmlStrdup(val->stringval);
2755 break;
2756 case XPATH_XSLT_TREE:
2757 if ((val->nodesetval != NULL) &&
2758 (val->nodesetval->nodeTab != NULL))
2759 ret->nodesetval = xmlXPathNodeSetCreate(
2760 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2761 else
2762 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2763 break;
2764 case XPATH_NODESET:
2765 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2766 break;
2767 case XPATH_LOCATIONSET:
2768#ifdef LIBXML_XPTR_ENABLED
2769 {
2770 xmlLocationSetPtr loc = val->user;
2771 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2772 break;
2773 }
2774#endif
2775 case XPATH_UNDEFINED:
2776 case XPATH_USERS:
2777 xmlGenericError(xmlGenericErrorContext,
2778 "xmlXPathObjectCopy: unsupported type %d\n",
2779 val->type);
2780 break;
2781 }
2782 return(ret);
2783}
2784
2785/**
2786 * xmlXPathFreeObject:
2787 * @obj: the object to free
2788 *
2789 * Free up an xmlXPathObjectPtr object.
2790 */
2791void
2792xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2793 if (obj == NULL) return;
2794 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002795 if (obj->boolval) {
2796 obj->type = XPATH_XSLT_TREE;
2797 if (obj->nodesetval != NULL)
2798 xmlXPathFreeValueTree(obj->nodesetval);
2799 } else {
2800 if (obj->nodesetval != NULL)
2801 xmlXPathFreeNodeSet(obj->nodesetval);
2802 }
Owen Taylor3473f882001-02-23 17:55:21 +00002803#ifdef LIBXML_XPTR_ENABLED
2804 } else if (obj->type == XPATH_LOCATIONSET) {
2805 if (obj->user != NULL)
2806 xmlXPtrFreeLocationSet(obj->user);
2807#endif
2808 } else if (obj->type == XPATH_STRING) {
2809 if (obj->stringval != NULL)
2810 xmlFree(obj->stringval);
2811 } else if (obj->type == XPATH_XSLT_TREE) {
2812 if (obj->nodesetval != NULL)
2813 xmlXPathFreeValueTree(obj->nodesetval);
2814 }
2815
Owen Taylor3473f882001-02-23 17:55:21 +00002816 xmlFree(obj);
2817}
2818
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002819
2820/************************************************************************
2821 * *
2822 * Type Casting Routines *
2823 * *
2824 ************************************************************************/
2825
2826/**
2827 * xmlXPathCastBooleanToString:
2828 * @val: a boolean
2829 *
2830 * Converts a boolean to its string value.
2831 *
2832 * Returns a newly allocated string.
2833 */
2834xmlChar *
2835xmlXPathCastBooleanToString (int val) {
2836 xmlChar *ret;
2837 if (val)
2838 ret = xmlStrdup((const xmlChar *) "true");
2839 else
2840 ret = xmlStrdup((const xmlChar *) "false");
2841 return(ret);
2842}
2843
2844/**
2845 * xmlXPathCastNumberToString:
2846 * @val: a number
2847 *
2848 * Converts a number to its string value.
2849 *
2850 * Returns a newly allocated string.
2851 */
2852xmlChar *
2853xmlXPathCastNumberToString (double val) {
2854 xmlChar *ret;
2855 switch (isinf(val)) {
2856 case 1:
2857 ret = xmlStrdup((const xmlChar *) "+Infinity");
2858 break;
2859 case -1:
2860 ret = xmlStrdup((const xmlChar *) "-Infinity");
2861 break;
2862 default:
2863 if (isnan(val)) {
2864 ret = xmlStrdup((const xmlChar *) "NaN");
2865 } else {
2866 /* could be improved */
2867 char buf[100];
2868 xmlXPathFormatNumber(val, buf, 100);
2869 ret = xmlStrdup((const xmlChar *) buf);
2870 }
2871 }
2872 return(ret);
2873}
2874
2875/**
2876 * xmlXPathCastNodeToString:
2877 * @node: a node
2878 *
2879 * Converts a node to its string value.
2880 *
2881 * Returns a newly allocated string.
2882 */
2883xmlChar *
2884xmlXPathCastNodeToString (xmlNodePtr node) {
2885 return(xmlNodeGetContent(node));
2886}
2887
2888/**
2889 * xmlXPathCastNodeSetToString:
2890 * @ns: a node-set
2891 *
2892 * Converts a node-set to its string value.
2893 *
2894 * Returns a newly allocated string.
2895 */
2896xmlChar *
2897xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2898 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2899 return(xmlStrdup((const xmlChar *) ""));
2900
2901 xmlXPathNodeSetSort(ns);
2902 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2903}
2904
2905/**
2906 * xmlXPathCastToString:
2907 * @val: an XPath object
2908 *
2909 * Converts an existing object to its string() equivalent
2910 *
2911 * Returns the string value of the object, NULL in case of error.
2912 * A new string is allocated only if needed (val isn't a
2913 * string object).
2914 */
2915xmlChar *
2916xmlXPathCastToString(xmlXPathObjectPtr val) {
2917 xmlChar *ret = NULL;
2918
2919 if (val == NULL)
2920 return(xmlStrdup((const xmlChar *) ""));
2921 switch (val->type) {
2922 case XPATH_UNDEFINED:
2923#ifdef DEBUG_EXPR
2924 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2925#endif
2926 ret = xmlStrdup((const xmlChar *) "");
2927 break;
2928 case XPATH_XSLT_TREE:
2929 case XPATH_NODESET:
2930 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2931 break;
2932 case XPATH_STRING:
2933 return(val->stringval);
2934 case XPATH_BOOLEAN:
2935 ret = xmlXPathCastBooleanToString(val->boolval);
2936 break;
2937 case XPATH_NUMBER: {
2938 ret = xmlXPathCastNumberToString(val->floatval);
2939 break;
2940 }
2941 case XPATH_USERS:
2942 case XPATH_POINT:
2943 case XPATH_RANGE:
2944 case XPATH_LOCATIONSET:
2945 TODO
2946 ret = xmlStrdup((const xmlChar *) "");
2947 break;
2948 }
2949 return(ret);
2950}
2951
2952/**
2953 * xmlXPathConvertString:
2954 * @val: an XPath object
2955 *
2956 * Converts an existing object to its string() equivalent
2957 *
2958 * Returns the new object, the old one is freed (or the operation
2959 * is done directly on @val)
2960 */
2961xmlXPathObjectPtr
2962xmlXPathConvertString(xmlXPathObjectPtr val) {
2963 xmlChar *res = NULL;
2964
2965 if (val == NULL)
2966 return(xmlXPathNewCString(""));
2967
2968 switch (val->type) {
2969 case XPATH_UNDEFINED:
2970#ifdef DEBUG_EXPR
2971 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2972#endif
2973 break;
2974 case XPATH_XSLT_TREE:
2975 case XPATH_NODESET:
2976 res = xmlXPathCastNodeSetToString(val->nodesetval);
2977 break;
2978 case XPATH_STRING:
2979 return(val);
2980 case XPATH_BOOLEAN:
2981 res = xmlXPathCastBooleanToString(val->boolval);
2982 break;
2983 case XPATH_NUMBER:
2984 res = xmlXPathCastNumberToString(val->floatval);
2985 break;
2986 case XPATH_USERS:
2987 case XPATH_POINT:
2988 case XPATH_RANGE:
2989 case XPATH_LOCATIONSET:
2990 TODO;
2991 break;
2992 }
2993 xmlXPathFreeObject(val);
2994 if (res == NULL)
2995 return(xmlXPathNewCString(""));
2996 return(xmlXPathWrapString(res));
2997}
2998
2999/**
3000 * xmlXPathCastBooleanToNumber:
3001 * @val: a boolean
3002 *
3003 * Converts a boolean to its number value
3004 *
3005 * Returns the number value
3006 */
3007double
3008xmlXPathCastBooleanToNumber(int val) {
3009 if (val)
3010 return(1.0);
3011 return(0.0);
3012}
3013
3014/**
3015 * xmlXPathCastStringToNumber:
3016 * @val: a string
3017 *
3018 * Converts a string to its number value
3019 *
3020 * Returns the number value
3021 */
3022double
3023xmlXPathCastStringToNumber(const xmlChar * val) {
3024 return(xmlXPathStringEvalNumber(val));
3025}
3026
3027/**
3028 * xmlXPathCastNodeToNumber:
3029 * @node: a node
3030 *
3031 * Converts a node to its number value
3032 *
3033 * Returns the number value
3034 */
3035double
3036xmlXPathCastNodeToNumber (xmlNodePtr node) {
3037 xmlChar *strval;
3038 double ret;
3039
3040 if (node == NULL)
3041 return(xmlXPathNAN);
3042 strval = xmlXPathCastNodeToString(node);
3043 if (strval == NULL)
3044 return(xmlXPathNAN);
3045 ret = xmlXPathCastStringToNumber(strval);
3046 xmlFree(strval);
3047
3048 return(ret);
3049}
3050
3051/**
3052 * xmlXPathCastNodeSetToNumber:
3053 * @ns: a node-set
3054 *
3055 * Converts a node-set to its number value
3056 *
3057 * Returns the number value
3058 */
3059double
3060xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3061 xmlChar *str;
3062 double ret;
3063
3064 if (ns == NULL)
3065 return(xmlXPathNAN);
3066 str = xmlXPathCastNodeSetToString(ns);
3067 ret = xmlXPathCastStringToNumber(str);
3068 xmlFree(str);
3069 return(ret);
3070}
3071
3072/**
3073 * xmlXPathCastToNumber:
3074 * @val: an XPath object
3075 *
3076 * Converts an XPath object to its number value
3077 *
3078 * Returns the number value
3079 */
3080double
3081xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3082 double ret = 0.0;
3083
3084 if (val == NULL)
3085 return(xmlXPathNAN);
3086 switch (val->type) {
3087 case XPATH_UNDEFINED:
3088#ifdef DEGUB_EXPR
3089 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3090#endif
3091 ret = xmlXPathNAN;
3092 break;
3093 case XPATH_XSLT_TREE:
3094 case XPATH_NODESET:
3095 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3096 break;
3097 case XPATH_STRING:
3098 ret = xmlXPathCastStringToNumber(val->stringval);
3099 break;
3100 case XPATH_NUMBER:
3101 ret = val->floatval;
3102 break;
3103 case XPATH_BOOLEAN:
3104 ret = xmlXPathCastBooleanToNumber(val->boolval);
3105 break;
3106 case XPATH_USERS:
3107 case XPATH_POINT:
3108 case XPATH_RANGE:
3109 case XPATH_LOCATIONSET:
3110 TODO;
3111 ret = xmlXPathNAN;
3112 break;
3113 }
3114 return(ret);
3115}
3116
3117/**
3118 * xmlXPathConvertNumber:
3119 * @val: an XPath object
3120 *
3121 * Converts an existing object to its number() equivalent
3122 *
3123 * Returns the new object, the old one is freed (or the operation
3124 * is done directly on @val)
3125 */
3126xmlXPathObjectPtr
3127xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3128 xmlXPathObjectPtr ret;
3129
3130 if (val == NULL)
3131 return(xmlXPathNewFloat(0.0));
3132 if (val->type == XPATH_NUMBER)
3133 return(val);
3134 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3135 xmlXPathFreeObject(val);
3136 return(ret);
3137}
3138
3139/**
3140 * xmlXPathCastNumberToBoolean:
3141 * @val: a number
3142 *
3143 * Converts a number to its boolean value
3144 *
3145 * Returns the boolean value
3146 */
3147int
3148xmlXPathCastNumberToBoolean (double val) {
3149 if (isnan(val) || (val == 0.0))
3150 return(0);
3151 return(1);
3152}
3153
3154/**
3155 * xmlXPathCastStringToBoolean:
3156 * @val: a string
3157 *
3158 * Converts a string to its boolean value
3159 *
3160 * Returns the boolean value
3161 */
3162int
3163xmlXPathCastStringToBoolean (const xmlChar *val) {
3164 if ((val == NULL) || (xmlStrlen(val) == 0))
3165 return(0);
3166 return(1);
3167}
3168
3169/**
3170 * xmlXPathCastNodeSetToBoolean:
3171 * @ns: a node-set
3172 *
3173 * Converts a node-set to its boolean value
3174 *
3175 * Returns the boolean value
3176 */
3177int
3178xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3179 if ((ns == NULL) || (ns->nodeNr == 0))
3180 return(0);
3181 return(1);
3182}
3183
3184/**
3185 * xmlXpathCastToBoolean:
3186 * @val: an XPath object
3187 *
3188 * Converts an XPath object to its boolean value
3189 *
3190 * Returns the boolean value
3191 */
3192int
3193xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3194 int ret = 0;
3195
3196 if (val == NULL)
3197 return(0);
3198 switch (val->type) {
3199 case XPATH_UNDEFINED:
3200#ifdef DEBUG_EXPR
3201 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3202#endif
3203 ret = 0;
3204 break;
3205 case XPATH_XSLT_TREE:
3206 case XPATH_NODESET:
3207 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3208 break;
3209 case XPATH_STRING:
3210 ret = xmlXPathCastStringToBoolean(val->stringval);
3211 break;
3212 case XPATH_NUMBER:
3213 ret = xmlXPathCastNumberToBoolean(val->floatval);
3214 break;
3215 case XPATH_BOOLEAN:
3216 ret = val->boolval;
3217 break;
3218 case XPATH_USERS:
3219 case XPATH_POINT:
3220 case XPATH_RANGE:
3221 case XPATH_LOCATIONSET:
3222 TODO;
3223 ret = 0;
3224 break;
3225 }
3226 return(ret);
3227}
3228
3229
3230/**
3231 * xmlXPathConvertBoolean:
3232 * @val: an XPath object
3233 *
3234 * Converts an existing object to its boolean() equivalent
3235 *
3236 * Returns the new object, the old one is freed (or the operation
3237 * is done directly on @val)
3238 */
3239xmlXPathObjectPtr
3240xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3241 xmlXPathObjectPtr ret;
3242
3243 if (val == NULL)
3244 return(xmlXPathNewBoolean(0));
3245 if (val->type == XPATH_BOOLEAN)
3246 return(val);
3247 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3248 xmlXPathFreeObject(val);
3249 return(ret);
3250}
3251
Owen Taylor3473f882001-02-23 17:55:21 +00003252/************************************************************************
3253 * *
3254 * Routines to handle XPath contexts *
3255 * *
3256 ************************************************************************/
3257
3258/**
3259 * xmlXPathNewContext:
3260 * @doc: the XML document
3261 *
3262 * Create a new xmlXPathContext
3263 *
3264 * Returns the xmlXPathContext just allocated.
3265 */
3266xmlXPathContextPtr
3267xmlXPathNewContext(xmlDocPtr doc) {
3268 xmlXPathContextPtr ret;
3269
3270 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3271 if (ret == NULL) {
3272 xmlGenericError(xmlGenericErrorContext,
3273 "xmlXPathNewContext: out of memory\n");
3274 return(NULL);
3275 }
3276 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3277 ret->doc = doc;
3278 ret->node = NULL;
3279
3280 ret->varHash = NULL;
3281
3282 ret->nb_types = 0;
3283 ret->max_types = 0;
3284 ret->types = NULL;
3285
3286 ret->funcHash = xmlHashCreate(0);
3287
3288 ret->nb_axis = 0;
3289 ret->max_axis = 0;
3290 ret->axis = NULL;
3291
3292 ret->nsHash = NULL;
3293 ret->user = NULL;
3294
3295 ret->contextSize = -1;
3296 ret->proximityPosition = -1;
3297
3298 xmlXPathRegisterAllFunctions(ret);
3299
3300 return(ret);
3301}
3302
3303/**
3304 * xmlXPathFreeContext:
3305 * @ctxt: the context to free
3306 *
3307 * Free up an xmlXPathContext
3308 */
3309void
3310xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3311 xmlXPathRegisteredNsCleanup(ctxt);
3312 xmlXPathRegisteredFuncsCleanup(ctxt);
3313 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003314 xmlFree(ctxt);
3315}
3316
3317/************************************************************************
3318 * *
3319 * Routines to handle XPath parser contexts *
3320 * *
3321 ************************************************************************/
3322
3323#define CHECK_CTXT(ctxt) \
3324 if (ctxt == NULL) { \
3325 xmlGenericError(xmlGenericErrorContext, \
3326 "%s:%d Internal error: ctxt == NULL\n", \
3327 __FILE__, __LINE__); \
3328 } \
3329
3330
3331#define CHECK_CONTEXT(ctxt) \
3332 if (ctxt == NULL) { \
3333 xmlGenericError(xmlGenericErrorContext, \
3334 "%s:%d Internal error: no context\n", \
3335 __FILE__, __LINE__); \
3336 } \
3337 else if (ctxt->doc == NULL) { \
3338 xmlGenericError(xmlGenericErrorContext, \
3339 "%s:%d Internal error: no document\n", \
3340 __FILE__, __LINE__); \
3341 } \
3342 else if (ctxt->doc->children == NULL) { \
3343 xmlGenericError(xmlGenericErrorContext, \
3344 "%s:%d Internal error: document without root\n", \
3345 __FILE__, __LINE__); \
3346 } \
3347
3348
3349/**
3350 * xmlXPathNewParserContext:
3351 * @str: the XPath expression
3352 * @ctxt: the XPath context
3353 *
3354 * Create a new xmlXPathParserContext
3355 *
3356 * Returns the xmlXPathParserContext just allocated.
3357 */
3358xmlXPathParserContextPtr
3359xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3360 xmlXPathParserContextPtr ret;
3361
3362 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3363 if (ret == NULL) {
3364 xmlGenericError(xmlGenericErrorContext,
3365 "xmlXPathNewParserContext: out of memory\n");
3366 return(NULL);
3367 }
3368 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3369 ret->cur = ret->base = str;
3370 ret->context = ctxt;
3371
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003372 ret->comp = xmlXPathNewCompExpr();
3373 if (ret->comp == NULL) {
3374 xmlFree(ret->valueTab);
3375 xmlFree(ret);
3376 return(NULL);
3377 }
3378
3379 return(ret);
3380}
3381
3382/**
3383 * xmlXPathCompParserContext:
3384 * @comp: the XPath compiled expression
3385 * @ctxt: the XPath context
3386 *
3387 * Create a new xmlXPathParserContext when processing a compiled expression
3388 *
3389 * Returns the xmlXPathParserContext just allocated.
3390 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003391static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003392xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3393 xmlXPathParserContextPtr ret;
3394
3395 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3396 if (ret == NULL) {
3397 xmlGenericError(xmlGenericErrorContext,
3398 "xmlXPathNewParserContext: out of memory\n");
3399 return(NULL);
3400 }
3401 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3402
Owen Taylor3473f882001-02-23 17:55:21 +00003403 /* Allocate the value stack */
3404 ret->valueTab = (xmlXPathObjectPtr *)
3405 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003406 if (ret->valueTab == NULL) {
3407 xmlFree(ret);
3408 xmlGenericError(xmlGenericErrorContext,
3409 "xmlXPathNewParserContext: out of memory\n");
3410 return(NULL);
3411 }
Owen Taylor3473f882001-02-23 17:55:21 +00003412 ret->valueNr = 0;
3413 ret->valueMax = 10;
3414 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003415
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003416 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003417 ret->comp = comp;
3418
Owen Taylor3473f882001-02-23 17:55:21 +00003419 return(ret);
3420}
3421
3422/**
3423 * xmlXPathFreeParserContext:
3424 * @ctxt: the context to free
3425 *
3426 * Free up an xmlXPathParserContext
3427 */
3428void
3429xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3430 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003431 xmlFree(ctxt->valueTab);
3432 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003433 if (ctxt->comp)
3434 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003435 xmlFree(ctxt);
3436}
3437
3438/************************************************************************
3439 * *
3440 * The implicit core function library *
3441 * *
3442 ************************************************************************/
3443
Owen Taylor3473f882001-02-23 17:55:21 +00003444/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003445 * xmlXPathNodeStringHash:
3446 * @node: a node pointer
3447 *
3448 * Function computing the beginning of the string value of the node,
3449 * used to speed up comparisons
3450 *
3451 * Returns an int usable as a hash
3452 */
3453static unsigned int
3454xmlXPathNodeValHash(xmlNodePtr node) {
3455 int len = 2;
3456 const xmlChar * string = NULL;
3457 xmlNodePtr tmp = NULL;
3458 unsigned int ret = 0;
3459
3460 if (node == NULL)
3461 return(0);
3462
3463
3464 switch (node->type) {
3465 case XML_COMMENT_NODE:
3466 case XML_PI_NODE:
3467 case XML_CDATA_SECTION_NODE:
3468 case XML_TEXT_NODE:
3469 string = node->content;
3470 if (string == NULL)
3471 return(0);
3472 if (string[0] == 0)
3473 return(0);
3474 return(((unsigned int) string[0]) +
3475 (((unsigned int) string[1]) << 8));
3476 case XML_NAMESPACE_DECL:
3477 string = ((xmlNsPtr)node)->href;
3478 if (string == NULL)
3479 return(0);
3480 if (string[0] == 0)
3481 return(0);
3482 return(((unsigned int) string[0]) +
3483 (((unsigned int) string[1]) << 8));
3484 case XML_ATTRIBUTE_NODE:
3485 tmp = ((xmlAttrPtr) node)->children;
3486 break;
3487 case XML_ELEMENT_NODE:
3488 tmp = node->children;
3489 break;
3490 default:
3491 return(0);
3492 }
3493 while (tmp != NULL) {
3494 switch (tmp->type) {
3495 case XML_COMMENT_NODE:
3496 case XML_PI_NODE:
3497 case XML_CDATA_SECTION_NODE:
3498 case XML_TEXT_NODE:
3499 string = tmp->content;
3500 break;
3501 case XML_NAMESPACE_DECL:
3502 string = ((xmlNsPtr)tmp)->href;
3503 break;
3504 default:
3505 break;
3506 }
3507 if ((string != NULL) && (string[0] != 0)) {
3508 if (string[0] == 0)
3509 return(0);
3510 if (len == 1) {
3511 return(ret + (((unsigned int) string[0]) << 8));
3512 }
3513 if (string[1] == 0) {
3514 len = 1;
3515 ret = (unsigned int) string[0];
3516 } else {
3517 return(((unsigned int) string[0]) +
3518 (((unsigned int) string[1]) << 8));
3519 }
3520 }
3521 /*
3522 * Skip to next node
3523 */
3524 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3525 if (tmp->children->type != XML_ENTITY_DECL) {
3526 tmp = tmp->children;
3527 continue;
3528 }
3529 }
3530 if (tmp == node)
3531 break;
3532
3533 if (tmp->next != NULL) {
3534 tmp = tmp->next;
3535 continue;
3536 }
3537
3538 do {
3539 tmp = tmp->parent;
3540 if (tmp == NULL)
3541 break;
3542 if (tmp == node) {
3543 tmp = NULL;
3544 break;
3545 }
3546 if (tmp->next != NULL) {
3547 tmp = tmp->next;
3548 break;
3549 }
3550 } while (tmp != NULL);
3551 }
3552 return(ret);
3553}
3554
3555/**
3556 * xmlXPathStringHash:
3557 * @string: a string
3558 *
3559 * Function computing the beginning of the string value of the node,
3560 * used to speed up comparisons
3561 *
3562 * Returns an int usable as a hash
3563 */
3564static unsigned int
3565xmlXPathStringHash(const xmlChar * string) {
3566 if (string == NULL)
3567 return((unsigned int) 0);
3568 if (string[0] == 0)
3569 return(0);
3570 return(((unsigned int) string[0]) +
3571 (((unsigned int) string[1]) << 8));
3572}
3573
3574/**
Owen Taylor3473f882001-02-23 17:55:21 +00003575 * xmlXPathCompareNodeSetFloat:
3576 * @ctxt: the XPath Parser context
3577 * @inf: less than (1) or greater than (0)
3578 * @strict: is the comparison strict
3579 * @arg: the node set
3580 * @f: the value
3581 *
3582 * Implement the compare operation between a nodeset and a number
3583 * @ns < @val (1, 1, ...
3584 * @ns <= @val (1, 0, ...
3585 * @ns > @val (0, 1, ...
3586 * @ns >= @val (0, 0, ...
3587 *
3588 * If one object to be compared is a node-set and the other is a number,
3589 * then the comparison will be true if and only if there is a node in the
3590 * node-set such that the result of performing the comparison on the number
3591 * to be compared and on the result of converting the string-value of that
3592 * node to a number using the number function is true.
3593 *
3594 * Returns 0 or 1 depending on the results of the test.
3595 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003596static int
Owen Taylor3473f882001-02-23 17:55:21 +00003597xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3598 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3599 int i, ret = 0;
3600 xmlNodeSetPtr ns;
3601 xmlChar *str2;
3602
3603 if ((f == NULL) || (arg == NULL) ||
3604 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3605 xmlXPathFreeObject(arg);
3606 xmlXPathFreeObject(f);
3607 return(0);
3608 }
3609 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003610 if (ns != NULL) {
3611 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003612 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003613 if (str2 != NULL) {
3614 valuePush(ctxt,
3615 xmlXPathNewString(str2));
3616 xmlFree(str2);
3617 xmlXPathNumberFunction(ctxt, 1);
3618 valuePush(ctxt, xmlXPathObjectCopy(f));
3619 ret = xmlXPathCompareValues(ctxt, inf, strict);
3620 if (ret)
3621 break;
3622 }
3623 }
Owen Taylor3473f882001-02-23 17:55:21 +00003624 }
3625 xmlXPathFreeObject(arg);
3626 xmlXPathFreeObject(f);
3627 return(ret);
3628}
3629
3630/**
3631 * xmlXPathCompareNodeSetString:
3632 * @ctxt: the XPath Parser context
3633 * @inf: less than (1) or greater than (0)
3634 * @strict: is the comparison strict
3635 * @arg: the node set
3636 * @s: the value
3637 *
3638 * Implement the compare operation between a nodeset and a string
3639 * @ns < @val (1, 1, ...
3640 * @ns <= @val (1, 0, ...
3641 * @ns > @val (0, 1, ...
3642 * @ns >= @val (0, 0, ...
3643 *
3644 * If one object to be compared is a node-set and the other is a string,
3645 * then the comparison will be true if and only if there is a node in
3646 * the node-set such that the result of performing the comparison on the
3647 * string-value of the node and the other string is true.
3648 *
3649 * Returns 0 or 1 depending on the results of the test.
3650 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003651static int
Owen Taylor3473f882001-02-23 17:55:21 +00003652xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3653 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3654 int i, ret = 0;
3655 xmlNodeSetPtr ns;
3656 xmlChar *str2;
3657
3658 if ((s == NULL) || (arg == NULL) ||
3659 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3660 xmlXPathFreeObject(arg);
3661 xmlXPathFreeObject(s);
3662 return(0);
3663 }
3664 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003665 if (ns != NULL) {
3666 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003667 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003668 if (str2 != NULL) {
3669 valuePush(ctxt,
3670 xmlXPathNewString(str2));
3671 xmlFree(str2);
3672 valuePush(ctxt, xmlXPathObjectCopy(s));
3673 ret = xmlXPathCompareValues(ctxt, inf, strict);
3674 if (ret)
3675 break;
3676 }
3677 }
Owen Taylor3473f882001-02-23 17:55:21 +00003678 }
3679 xmlXPathFreeObject(arg);
3680 xmlXPathFreeObject(s);
3681 return(ret);
3682}
3683
3684/**
3685 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003686 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003687 * @strict: is the comparison strict
3688 * @arg1: the fist node set object
3689 * @arg2: the second node set object
3690 *
3691 * Implement the compare operation on nodesets:
3692 *
3693 * If both objects to be compared are node-sets, then the comparison
3694 * will be true if and only if there is a node in the first node-set
3695 * and a node in the second node-set such that the result of performing
3696 * the comparison on the string-values of the two nodes is true.
3697 * ....
3698 * When neither object to be compared is a node-set and the operator
3699 * is <=, <, >= or >, then the objects are compared by converting both
3700 * objects to numbers and comparing the numbers according to IEEE 754.
3701 * ....
3702 * The number function converts its argument to a number as follows:
3703 * - a string that consists of optional whitespace followed by an
3704 * optional minus sign followed by a Number followed by whitespace
3705 * is converted to the IEEE 754 number that is nearest (according
3706 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3707 * represented by the string; any other string is converted to NaN
3708 *
3709 * Conclusion all nodes need to be converted first to their string value
3710 * and then the comparison must be done when possible
3711 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003712static int
3713xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003714 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3715 int i, j, init = 0;
3716 double val1;
3717 double *values2;
3718 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003719 xmlNodeSetPtr ns1;
3720 xmlNodeSetPtr ns2;
3721
3722 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003723 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3724 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003725 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003726 }
Owen Taylor3473f882001-02-23 17:55:21 +00003727 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003728 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3729 xmlXPathFreeObject(arg1);
3730 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003731 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003732 }
Owen Taylor3473f882001-02-23 17:55:21 +00003733
3734 ns1 = arg1->nodesetval;
3735 ns2 = arg2->nodesetval;
3736
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003737 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003738 xmlXPathFreeObject(arg1);
3739 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003740 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003741 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003742 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003743 xmlXPathFreeObject(arg1);
3744 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003745 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003746 }
Owen Taylor3473f882001-02-23 17:55:21 +00003747
3748 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3749 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003750 xmlXPathFreeObject(arg1);
3751 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003752 return(0);
3753 }
3754 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003755 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003756 if (isnan(val1))
3757 continue;
3758 for (j = 0;j < ns2->nodeNr;j++) {
3759 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003760 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003761 }
3762 if (isnan(values2[j]))
3763 continue;
3764 if (inf && strict)
3765 ret = (val1 < values2[j]);
3766 else if (inf && !strict)
3767 ret = (val1 <= values2[j]);
3768 else if (!inf && strict)
3769 ret = (val1 > values2[j]);
3770 else if (!inf && !strict)
3771 ret = (val1 >= values2[j]);
3772 if (ret)
3773 break;
3774 }
3775 if (ret)
3776 break;
3777 init = 1;
3778 }
3779 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003780 xmlXPathFreeObject(arg1);
3781 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003782 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003783}
3784
3785/**
3786 * xmlXPathCompareNodeSetValue:
3787 * @ctxt: the XPath Parser context
3788 * @inf: less than (1) or greater than (0)
3789 * @strict: is the comparison strict
3790 * @arg: the node set
3791 * @val: the value
3792 *
3793 * Implement the compare operation between a nodeset and a value
3794 * @ns < @val (1, 1, ...
3795 * @ns <= @val (1, 0, ...
3796 * @ns > @val (0, 1, ...
3797 * @ns >= @val (0, 0, ...
3798 *
3799 * If one object to be compared is a node-set and the other is a boolean,
3800 * then the comparison will be true if and only if the result of performing
3801 * the comparison on the boolean and on the result of converting
3802 * the node-set to a boolean using the boolean function is true.
3803 *
3804 * Returns 0 or 1 depending on the results of the test.
3805 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003806static int
Owen Taylor3473f882001-02-23 17:55:21 +00003807xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3808 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3809 if ((val == NULL) || (arg == NULL) ||
3810 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3811 return(0);
3812
3813 switch(val->type) {
3814 case XPATH_NUMBER:
3815 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3816 case XPATH_NODESET:
3817 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003818 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003819 case XPATH_STRING:
3820 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3821 case XPATH_BOOLEAN:
3822 valuePush(ctxt, arg);
3823 xmlXPathBooleanFunction(ctxt, 1);
3824 valuePush(ctxt, val);
3825 return(xmlXPathCompareValues(ctxt, inf, strict));
3826 default:
3827 TODO
3828 return(0);
3829 }
3830 return(0);
3831}
3832
3833/**
3834 * xmlXPathEqualNodeSetString
3835 * @arg: the nodeset object argument
3836 * @str: the string to compare to.
3837 *
3838 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3839 * If one object to be compared is a node-set and the other is a string,
3840 * then the comparison will be true if and only if there is a node in
3841 * the node-set such that the result of performing the comparison on the
3842 * string-value of the node and the other string is true.
3843 *
3844 * Returns 0 or 1 depending on the results of the test.
3845 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003846static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003847xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3848{
Owen Taylor3473f882001-02-23 17:55:21 +00003849 int i;
3850 xmlNodeSetPtr ns;
3851 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003852 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003853
3854 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003855 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3856 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003857 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003858 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003859 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003860 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003861 if (ns->nodeNr <= 0) {
3862 if (hash == 0)
3863 return(1);
3864 return(0);
3865 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003866 for (i = 0; i < ns->nodeNr; i++) {
3867 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3868 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3869 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3870 xmlFree(str2);
3871 return (1);
3872 }
3873 if (str2 != NULL)
3874 xmlFree(str2);
3875 }
Owen Taylor3473f882001-02-23 17:55:21 +00003876 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003877 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003878}
3879
3880/**
3881 * xmlXPathEqualNodeSetFloat
3882 * @arg: the nodeset object argument
3883 * @f: the float to compare to
3884 *
3885 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3886 * If one object to be compared is a node-set and the other is a number,
3887 * then the comparison will be true if and only if there is a node in
3888 * the node-set such that the result of performing the comparison on the
3889 * number to be compared and on the result of converting the string-value
3890 * of that node to a number using the number function is true.
3891 *
3892 * Returns 0 or 1 depending on the results of the test.
3893 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003894static int
Owen Taylor3473f882001-02-23 17:55:21 +00003895xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3896 char buf[100] = "";
3897
3898 if ((arg == NULL) ||
3899 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3900 return(0);
3901
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003902 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003903 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3904}
3905
3906
3907/**
3908 * xmlXPathEqualNodeSets
3909 * @arg1: first nodeset object argument
3910 * @arg2: second nodeset object argument
3911 *
3912 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3913 * If both objects to be compared are node-sets, then the comparison
3914 * will be true if and only if there is a node in the first node-set and
3915 * a node in the second node-set such that the result of performing the
3916 * comparison on the string-values of the two nodes is true.
3917 *
3918 * (needless to say, this is a costly operation)
3919 *
3920 * Returns 0 or 1 depending on the results of the test.
3921 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003922static int
Owen Taylor3473f882001-02-23 17:55:21 +00003923xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3924 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003925 unsigned int *hashs1;
3926 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003927 xmlChar **values1;
3928 xmlChar **values2;
3929 int ret = 0;
3930 xmlNodeSetPtr ns1;
3931 xmlNodeSetPtr ns2;
3932
3933 if ((arg1 == NULL) ||
3934 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3935 return(0);
3936 if ((arg2 == NULL) ||
3937 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3938 return(0);
3939
3940 ns1 = arg1->nodesetval;
3941 ns2 = arg2->nodesetval;
3942
Daniel Veillard911f49a2001-04-07 15:39:35 +00003943 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003944 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003945 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003946 return(0);
3947
3948 /*
3949 * check if there is a node pertaining to both sets
3950 */
3951 for (i = 0;i < ns1->nodeNr;i++)
3952 for (j = 0;j < ns2->nodeNr;j++)
3953 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3954 return(1);
3955
3956 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3957 if (values1 == NULL)
3958 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003959 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3960 if (hashs1 == NULL) {
3961 xmlFree(values1);
3962 return(0);
3963 }
Owen Taylor3473f882001-02-23 17:55:21 +00003964 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3965 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3966 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003967 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003968 xmlFree(values1);
3969 return(0);
3970 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003971 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3972 if (hashs2 == NULL) {
3973 xmlFree(hashs1);
3974 xmlFree(values1);
3975 xmlFree(values2);
3976 return(0);
3977 }
Owen Taylor3473f882001-02-23 17:55:21 +00003978 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3979 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003980 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003981 for (j = 0;j < ns2->nodeNr;j++) {
3982 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003983 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
3984 if (hashs1[i] == hashs2[j]) {
3985 if (values1[i] == NULL)
3986 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3987 if (values2[j] == NULL)
3988 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3989 ret = xmlStrEqual(values1[i], values2[j]);
3990 if (ret)
3991 break;
3992 }
Owen Taylor3473f882001-02-23 17:55:21 +00003993 }
3994 if (ret)
3995 break;
3996 }
3997 for (i = 0;i < ns1->nodeNr;i++)
3998 if (values1[i] != NULL)
3999 xmlFree(values1[i]);
4000 for (j = 0;j < ns2->nodeNr;j++)
4001 if (values2[j] != NULL)
4002 xmlFree(values2[j]);
4003 xmlFree(values1);
4004 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004005 xmlFree(hashs1);
4006 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004007 return(ret);
4008}
4009
4010/**
4011 * xmlXPathEqualValues:
4012 * @ctxt: the XPath Parser context
4013 *
4014 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4015 *
4016 * Returns 0 or 1 depending on the results of the test.
4017 */
4018int
4019xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4020 xmlXPathObjectPtr arg1, arg2;
4021 int ret = 0;
4022
4023 arg1 = valuePop(ctxt);
4024 if (arg1 == NULL)
4025 XP_ERROR0(XPATH_INVALID_OPERAND);
4026
4027 arg2 = valuePop(ctxt);
4028 if (arg2 == NULL) {
4029 xmlXPathFreeObject(arg1);
4030 XP_ERROR0(XPATH_INVALID_OPERAND);
4031 }
4032
4033 if (arg1 == arg2) {
4034#ifdef DEBUG_EXPR
4035 xmlGenericError(xmlGenericErrorContext,
4036 "Equal: by pointer\n");
4037#endif
4038 return(1);
4039 }
4040
4041 switch (arg1->type) {
4042 case XPATH_UNDEFINED:
4043#ifdef DEBUG_EXPR
4044 xmlGenericError(xmlGenericErrorContext,
4045 "Equal: undefined\n");
4046#endif
4047 break;
4048 case XPATH_XSLT_TREE:
4049 case XPATH_NODESET:
4050 switch (arg2->type) {
4051 case XPATH_UNDEFINED:
4052#ifdef DEBUG_EXPR
4053 xmlGenericError(xmlGenericErrorContext,
4054 "Equal: undefined\n");
4055#endif
4056 break;
4057 case XPATH_XSLT_TREE:
4058 case XPATH_NODESET:
4059 ret = xmlXPathEqualNodeSets(arg1, arg2);
4060 break;
4061 case XPATH_BOOLEAN:
4062 if ((arg1->nodesetval == NULL) ||
4063 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4064 else
4065 ret = 1;
4066 ret = (ret == arg2->boolval);
4067 break;
4068 case XPATH_NUMBER:
4069 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4070 break;
4071 case XPATH_STRING:
4072 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4073 break;
4074 case XPATH_USERS:
4075 case XPATH_POINT:
4076 case XPATH_RANGE:
4077 case XPATH_LOCATIONSET:
4078 TODO
4079 break;
4080 }
4081 break;
4082 case XPATH_BOOLEAN:
4083 switch (arg2->type) {
4084 case XPATH_UNDEFINED:
4085#ifdef DEBUG_EXPR
4086 xmlGenericError(xmlGenericErrorContext,
4087 "Equal: undefined\n");
4088#endif
4089 break;
4090 case XPATH_NODESET:
4091 case XPATH_XSLT_TREE:
4092 if ((arg2->nodesetval == NULL) ||
4093 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4094 else
4095 ret = 1;
4096 break;
4097 case XPATH_BOOLEAN:
4098#ifdef DEBUG_EXPR
4099 xmlGenericError(xmlGenericErrorContext,
4100 "Equal: %d boolean %d \n",
4101 arg1->boolval, arg2->boolval);
4102#endif
4103 ret = (arg1->boolval == arg2->boolval);
4104 break;
4105 case XPATH_NUMBER:
4106 if (arg2->floatval) ret = 1;
4107 else ret = 0;
4108 ret = (arg1->boolval == ret);
4109 break;
4110 case XPATH_STRING:
4111 if ((arg2->stringval == NULL) ||
4112 (arg2->stringval[0] == 0)) ret = 0;
4113 else
4114 ret = 1;
4115 ret = (arg1->boolval == ret);
4116 break;
4117 case XPATH_USERS:
4118 case XPATH_POINT:
4119 case XPATH_RANGE:
4120 case XPATH_LOCATIONSET:
4121 TODO
4122 break;
4123 }
4124 break;
4125 case XPATH_NUMBER:
4126 switch (arg2->type) {
4127 case XPATH_UNDEFINED:
4128#ifdef DEBUG_EXPR
4129 xmlGenericError(xmlGenericErrorContext,
4130 "Equal: undefined\n");
4131#endif
4132 break;
4133 case XPATH_NODESET:
4134 case XPATH_XSLT_TREE:
4135 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4136 break;
4137 case XPATH_BOOLEAN:
4138 if (arg1->floatval) ret = 1;
4139 else ret = 0;
4140 ret = (arg2->boolval == ret);
4141 break;
4142 case XPATH_STRING:
4143 valuePush(ctxt, arg2);
4144 xmlXPathNumberFunction(ctxt, 1);
4145 arg2 = valuePop(ctxt);
4146 /* no break on purpose */
4147 case XPATH_NUMBER:
4148 ret = (arg1->floatval == arg2->floatval);
4149 break;
4150 case XPATH_USERS:
4151 case XPATH_POINT:
4152 case XPATH_RANGE:
4153 case XPATH_LOCATIONSET:
4154 TODO
4155 break;
4156 }
4157 break;
4158 case XPATH_STRING:
4159 switch (arg2->type) {
4160 case XPATH_UNDEFINED:
4161#ifdef DEBUG_EXPR
4162 xmlGenericError(xmlGenericErrorContext,
4163 "Equal: undefined\n");
4164#endif
4165 break;
4166 case XPATH_NODESET:
4167 case XPATH_XSLT_TREE:
4168 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4169 break;
4170 case XPATH_BOOLEAN:
4171 if ((arg1->stringval == NULL) ||
4172 (arg1->stringval[0] == 0)) ret = 0;
4173 else
4174 ret = 1;
4175 ret = (arg2->boolval == ret);
4176 break;
4177 case XPATH_STRING:
4178 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4179 break;
4180 case XPATH_NUMBER:
4181 valuePush(ctxt, arg1);
4182 xmlXPathNumberFunction(ctxt, 1);
4183 arg1 = valuePop(ctxt);
4184 ret = (arg1->floatval == arg2->floatval);
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_USERS:
4195 case XPATH_POINT:
4196 case XPATH_RANGE:
4197 case XPATH_LOCATIONSET:
4198 TODO
4199 break;
4200 }
4201 xmlXPathFreeObject(arg1);
4202 xmlXPathFreeObject(arg2);
4203 return(ret);
4204}
4205
4206
4207/**
4208 * xmlXPathCompareValues:
4209 * @ctxt: the XPath Parser context
4210 * @inf: less than (1) or greater than (0)
4211 * @strict: is the comparison strict
4212 *
4213 * Implement the compare operation on XPath objects:
4214 * @arg1 < @arg2 (1, 1, ...
4215 * @arg1 <= @arg2 (1, 0, ...
4216 * @arg1 > @arg2 (0, 1, ...
4217 * @arg1 >= @arg2 (0, 0, ...
4218 *
4219 * When neither object to be compared is a node-set and the operator is
4220 * <=, <, >=, >, then the objects are compared by converted both objects
4221 * to numbers and comparing the numbers according to IEEE 754. The <
4222 * comparison will be true if and only if the first number is less than the
4223 * second number. The <= comparison will be true if and only if the first
4224 * number is less than or equal to the second number. The > comparison
4225 * will be true if and only if the first number is greater than the second
4226 * number. The >= comparison will be true if and only if the first number
4227 * is greater than or equal to the second number.
4228 *
4229 * Returns 1 if the comparaison succeeded, 0 if it failed
4230 */
4231int
4232xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4233 int ret = 0;
4234 xmlXPathObjectPtr arg1, arg2;
4235
4236 arg2 = valuePop(ctxt);
4237 if (arg2 == NULL) {
4238 XP_ERROR0(XPATH_INVALID_OPERAND);
4239 }
4240
4241 arg1 = valuePop(ctxt);
4242 if (arg1 == NULL) {
4243 xmlXPathFreeObject(arg2);
4244 XP_ERROR0(XPATH_INVALID_OPERAND);
4245 }
4246
4247 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4248 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004249 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004250 } else {
4251 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004252 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4253 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004254 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004255 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4256 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004257 }
4258 }
4259 return(ret);
4260 }
4261
4262 if (arg1->type != XPATH_NUMBER) {
4263 valuePush(ctxt, arg1);
4264 xmlXPathNumberFunction(ctxt, 1);
4265 arg1 = valuePop(ctxt);
4266 }
4267 if (arg1->type != XPATH_NUMBER) {
4268 xmlXPathFreeObject(arg1);
4269 xmlXPathFreeObject(arg2);
4270 XP_ERROR0(XPATH_INVALID_OPERAND);
4271 }
4272 if (arg2->type != XPATH_NUMBER) {
4273 valuePush(ctxt, arg2);
4274 xmlXPathNumberFunction(ctxt, 1);
4275 arg2 = valuePop(ctxt);
4276 }
4277 if (arg2->type != XPATH_NUMBER) {
4278 xmlXPathFreeObject(arg1);
4279 xmlXPathFreeObject(arg2);
4280 XP_ERROR0(XPATH_INVALID_OPERAND);
4281 }
4282 /*
4283 * Add tests for infinity and nan
4284 * => feedback on 3.4 for Inf and NaN
4285 */
4286 if (inf && strict)
4287 ret = (arg1->floatval < arg2->floatval);
4288 else if (inf && !strict)
4289 ret = (arg1->floatval <= arg2->floatval);
4290 else if (!inf && strict)
4291 ret = (arg1->floatval > arg2->floatval);
4292 else if (!inf && !strict)
4293 ret = (arg1->floatval >= arg2->floatval);
4294 xmlXPathFreeObject(arg1);
4295 xmlXPathFreeObject(arg2);
4296 return(ret);
4297}
4298
4299/**
4300 * xmlXPathValueFlipSign:
4301 * @ctxt: the XPath Parser context
4302 *
4303 * Implement the unary - operation on an XPath object
4304 * The numeric operators convert their operands to numbers as if
4305 * by calling the number function.
4306 */
4307void
4308xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004309 CAST_TO_NUMBER;
4310 CHECK_TYPE(XPATH_NUMBER);
4311 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004312}
4313
4314/**
4315 * xmlXPathAddValues:
4316 * @ctxt: the XPath Parser context
4317 *
4318 * Implement the add operation on XPath objects:
4319 * The numeric operators convert their operands to numbers as if
4320 * by calling the number function.
4321 */
4322void
4323xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4324 xmlXPathObjectPtr arg;
4325 double val;
4326
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004327 arg = valuePop(ctxt);
4328 if (arg == NULL)
4329 XP_ERROR(XPATH_INVALID_OPERAND);
4330 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004331 xmlXPathFreeObject(arg);
4332
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004333 CAST_TO_NUMBER;
4334 CHECK_TYPE(XPATH_NUMBER);
4335 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004336}
4337
4338/**
4339 * xmlXPathSubValues:
4340 * @ctxt: the XPath Parser context
4341 *
4342 * Implement the substraction operation on XPath objects:
4343 * The numeric operators convert their operands to numbers as if
4344 * by calling the number function.
4345 */
4346void
4347xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4348 xmlXPathObjectPtr arg;
4349 double val;
4350
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004351 arg = valuePop(ctxt);
4352 if (arg == NULL)
4353 XP_ERROR(XPATH_INVALID_OPERAND);
4354 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004355 xmlXPathFreeObject(arg);
4356
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004357 CAST_TO_NUMBER;
4358 CHECK_TYPE(XPATH_NUMBER);
4359 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004360}
4361
4362/**
4363 * xmlXPathMultValues:
4364 * @ctxt: the XPath Parser context
4365 *
4366 * Implement the multiply operation on XPath objects:
4367 * The numeric operators convert their operands to numbers as if
4368 * by calling the number function.
4369 */
4370void
4371xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4372 xmlXPathObjectPtr arg;
4373 double val;
4374
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004375 arg = valuePop(ctxt);
4376 if (arg == NULL)
4377 XP_ERROR(XPATH_INVALID_OPERAND);
4378 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004379 xmlXPathFreeObject(arg);
4380
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004381 CAST_TO_NUMBER;
4382 CHECK_TYPE(XPATH_NUMBER);
4383 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004384}
4385
4386/**
4387 * xmlXPathDivValues:
4388 * @ctxt: the XPath Parser context
4389 *
4390 * Implement the div operation on XPath objects @arg1 / @arg2:
4391 * The numeric operators convert their operands to numbers as if
4392 * by calling the number function.
4393 */
4394void
4395xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4396 xmlXPathObjectPtr arg;
4397 double val;
4398
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004399 arg = valuePop(ctxt);
4400 if (arg == NULL)
4401 XP_ERROR(XPATH_INVALID_OPERAND);
4402 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004403 xmlXPathFreeObject(arg);
4404
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004405 CAST_TO_NUMBER;
4406 CHECK_TYPE(XPATH_NUMBER);
4407 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004408}
4409
4410/**
4411 * xmlXPathModValues:
4412 * @ctxt: the XPath Parser context
4413 *
4414 * Implement the mod operation on XPath objects: @arg1 / @arg2
4415 * The numeric operators convert their operands to numbers as if
4416 * by calling the number function.
4417 */
4418void
4419xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4420 xmlXPathObjectPtr arg;
4421 int arg1, arg2;
4422
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004423 arg = valuePop(ctxt);
4424 if (arg == NULL)
4425 XP_ERROR(XPATH_INVALID_OPERAND);
4426 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004427 xmlXPathFreeObject(arg);
4428
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004429 CAST_TO_NUMBER;
4430 CHECK_TYPE(XPATH_NUMBER);
4431 arg1 = (int) ctxt->value->floatval;
4432 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004433}
4434
4435/************************************************************************
4436 * *
4437 * The traversal functions *
4438 * *
4439 ************************************************************************/
4440
Owen Taylor3473f882001-02-23 17:55:21 +00004441/*
4442 * A traversal function enumerates nodes along an axis.
4443 * Initially it must be called with NULL, and it indicates
4444 * termination on the axis by returning NULL.
4445 */
4446typedef xmlNodePtr (*xmlXPathTraversalFunction)
4447 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4448
4449/**
4450 * xmlXPathNextSelf:
4451 * @ctxt: the XPath Parser context
4452 * @cur: the current node in the traversal
4453 *
4454 * Traversal function for the "self" direction
4455 * The self axis contains just the context node itself
4456 *
4457 * Returns the next element following that axis
4458 */
4459xmlNodePtr
4460xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4461 if (cur == NULL)
4462 return(ctxt->context->node);
4463 return(NULL);
4464}
4465
4466/**
4467 * xmlXPathNextChild:
4468 * @ctxt: the XPath Parser context
4469 * @cur: the current node in the traversal
4470 *
4471 * Traversal function for the "child" direction
4472 * The child axis contains the children of the context node in document order.
4473 *
4474 * Returns the next element following that axis
4475 */
4476xmlNodePtr
4477xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4478 if (cur == NULL) {
4479 if (ctxt->context->node == NULL) return(NULL);
4480 switch (ctxt->context->node->type) {
4481 case XML_ELEMENT_NODE:
4482 case XML_TEXT_NODE:
4483 case XML_CDATA_SECTION_NODE:
4484 case XML_ENTITY_REF_NODE:
4485 case XML_ENTITY_NODE:
4486 case XML_PI_NODE:
4487 case XML_COMMENT_NODE:
4488 case XML_NOTATION_NODE:
4489 case XML_DTD_NODE:
4490 return(ctxt->context->node->children);
4491 case XML_DOCUMENT_NODE:
4492 case XML_DOCUMENT_TYPE_NODE:
4493 case XML_DOCUMENT_FRAG_NODE:
4494 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004495#ifdef LIBXML_DOCB_ENABLED
4496 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004497#endif
4498 return(((xmlDocPtr) ctxt->context->node)->children);
4499 case XML_ELEMENT_DECL:
4500 case XML_ATTRIBUTE_DECL:
4501 case XML_ENTITY_DECL:
4502 case XML_ATTRIBUTE_NODE:
4503 case XML_NAMESPACE_DECL:
4504 case XML_XINCLUDE_START:
4505 case XML_XINCLUDE_END:
4506 return(NULL);
4507 }
4508 return(NULL);
4509 }
4510 if ((cur->type == XML_DOCUMENT_NODE) ||
4511 (cur->type == XML_HTML_DOCUMENT_NODE))
4512 return(NULL);
4513 return(cur->next);
4514}
4515
4516/**
4517 * xmlXPathNextDescendant:
4518 * @ctxt: the XPath Parser context
4519 * @cur: the current node in the traversal
4520 *
4521 * Traversal function for the "descendant" direction
4522 * the descendant axis contains the descendants of the context node in document
4523 * order; a descendant is a child or a child of a child and so on.
4524 *
4525 * Returns the next element following that axis
4526 */
4527xmlNodePtr
4528xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4529 if (cur == NULL) {
4530 if (ctxt->context->node == NULL)
4531 return(NULL);
4532 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4533 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4534 return(NULL);
4535
4536 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4537 return(ctxt->context->doc->children);
4538 return(ctxt->context->node->children);
4539 }
4540
4541 if (cur->children != NULL)
4542 {
4543 if (cur->children->type != XML_ENTITY_DECL)
4544 return(cur->children);
4545 }
4546 if (cur->next != NULL) return(cur->next);
4547
4548 do {
4549 cur = cur->parent;
4550 if (cur == NULL) return(NULL);
4551 if (cur == ctxt->context->node) return(NULL);
4552 if (cur->next != NULL) {
4553 cur = cur->next;
4554 return(cur);
4555 }
4556 } while (cur != NULL);
4557 return(cur);
4558}
4559
4560/**
4561 * xmlXPathNextDescendantOrSelf:
4562 * @ctxt: the XPath Parser context
4563 * @cur: the current node in the traversal
4564 *
4565 * Traversal function for the "descendant-or-self" direction
4566 * the descendant-or-self axis contains the context node and the descendants
4567 * of the context node in document order; thus the context node is the first
4568 * node on the axis, and the first child of the context node is the second node
4569 * on the axis
4570 *
4571 * Returns the next element following that axis
4572 */
4573xmlNodePtr
4574xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4575 if (cur == NULL) {
4576 if (ctxt->context->node == NULL)
4577 return(NULL);
4578 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4579 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4580 return(NULL);
4581 return(ctxt->context->node);
4582 }
4583
4584 return(xmlXPathNextDescendant(ctxt, cur));
4585}
4586
4587/**
4588 * xmlXPathNextParent:
4589 * @ctxt: the XPath Parser context
4590 * @cur: the current node in the traversal
4591 *
4592 * Traversal function for the "parent" direction
4593 * The parent axis contains the parent of the context node, if there is one.
4594 *
4595 * Returns the next element following that axis
4596 */
4597xmlNodePtr
4598xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4599 /*
4600 * the parent of an attribute or namespace node is the element
4601 * to which the attribute or namespace node is attached
4602 * Namespace handling !!!
4603 */
4604 if (cur == NULL) {
4605 if (ctxt->context->node == NULL) return(NULL);
4606 switch (ctxt->context->node->type) {
4607 case XML_ELEMENT_NODE:
4608 case XML_TEXT_NODE:
4609 case XML_CDATA_SECTION_NODE:
4610 case XML_ENTITY_REF_NODE:
4611 case XML_ENTITY_NODE:
4612 case XML_PI_NODE:
4613 case XML_COMMENT_NODE:
4614 case XML_NOTATION_NODE:
4615 case XML_DTD_NODE:
4616 case XML_ELEMENT_DECL:
4617 case XML_ATTRIBUTE_DECL:
4618 case XML_XINCLUDE_START:
4619 case XML_XINCLUDE_END:
4620 case XML_ENTITY_DECL:
4621 if (ctxt->context->node->parent == NULL)
4622 return((xmlNodePtr) ctxt->context->doc);
4623 return(ctxt->context->node->parent);
4624 case XML_ATTRIBUTE_NODE: {
4625 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4626
4627 return(att->parent);
4628 }
4629 case XML_DOCUMENT_NODE:
4630 case XML_DOCUMENT_TYPE_NODE:
4631 case XML_DOCUMENT_FRAG_NODE:
4632 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004633#ifdef LIBXML_DOCB_ENABLED
4634 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004635#endif
4636 return(NULL);
4637 case XML_NAMESPACE_DECL:
4638 /*
4639 * TODO !!! may require extending struct _xmlNs with
4640 * parent field
4641 * C.f. Infoset case...
4642 */
4643 return(NULL);
4644 }
4645 }
4646 return(NULL);
4647}
4648
4649/**
4650 * xmlXPathNextAncestor:
4651 * @ctxt: the XPath Parser context
4652 * @cur: the current node in the traversal
4653 *
4654 * Traversal function for the "ancestor" direction
4655 * the ancestor axis contains the ancestors of the context node; the ancestors
4656 * of the context node consist of the parent of context node and the parent's
4657 * parent and so on; the nodes are ordered in reverse document order; thus the
4658 * parent is the first node on the axis, and the parent's parent is the second
4659 * node on the axis
4660 *
4661 * Returns the next element following that axis
4662 */
4663xmlNodePtr
4664xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4665 /*
4666 * the parent of an attribute or namespace node is the element
4667 * to which the attribute or namespace node is attached
4668 * !!!!!!!!!!!!!
4669 */
4670 if (cur == NULL) {
4671 if (ctxt->context->node == NULL) return(NULL);
4672 switch (ctxt->context->node->type) {
4673 case XML_ELEMENT_NODE:
4674 case XML_TEXT_NODE:
4675 case XML_CDATA_SECTION_NODE:
4676 case XML_ENTITY_REF_NODE:
4677 case XML_ENTITY_NODE:
4678 case XML_PI_NODE:
4679 case XML_COMMENT_NODE:
4680 case XML_DTD_NODE:
4681 case XML_ELEMENT_DECL:
4682 case XML_ATTRIBUTE_DECL:
4683 case XML_ENTITY_DECL:
4684 case XML_NOTATION_NODE:
4685 case XML_XINCLUDE_START:
4686 case XML_XINCLUDE_END:
4687 if (ctxt->context->node->parent == NULL)
4688 return((xmlNodePtr) ctxt->context->doc);
4689 return(ctxt->context->node->parent);
4690 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004691 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004692
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004693 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004694 }
4695 case XML_DOCUMENT_NODE:
4696 case XML_DOCUMENT_TYPE_NODE:
4697 case XML_DOCUMENT_FRAG_NODE:
4698 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004699#ifdef LIBXML_DOCB_ENABLED
4700 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004701#endif
4702 return(NULL);
4703 case XML_NAMESPACE_DECL:
4704 /*
4705 * TODO !!! may require extending struct _xmlNs with
4706 * parent field
4707 * C.f. Infoset case...
4708 */
4709 return(NULL);
4710 }
4711 return(NULL);
4712 }
4713 if (cur == ctxt->context->doc->children)
4714 return((xmlNodePtr) ctxt->context->doc);
4715 if (cur == (xmlNodePtr) ctxt->context->doc)
4716 return(NULL);
4717 switch (cur->type) {
4718 case XML_ELEMENT_NODE:
4719 case XML_TEXT_NODE:
4720 case XML_CDATA_SECTION_NODE:
4721 case XML_ENTITY_REF_NODE:
4722 case XML_ENTITY_NODE:
4723 case XML_PI_NODE:
4724 case XML_COMMENT_NODE:
4725 case XML_NOTATION_NODE:
4726 case XML_DTD_NODE:
4727 case XML_ELEMENT_DECL:
4728 case XML_ATTRIBUTE_DECL:
4729 case XML_ENTITY_DECL:
4730 case XML_XINCLUDE_START:
4731 case XML_XINCLUDE_END:
4732 return(cur->parent);
4733 case XML_ATTRIBUTE_NODE: {
4734 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4735
4736 return(att->parent);
4737 }
4738 case XML_DOCUMENT_NODE:
4739 case XML_DOCUMENT_TYPE_NODE:
4740 case XML_DOCUMENT_FRAG_NODE:
4741 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004742#ifdef LIBXML_DOCB_ENABLED
4743 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004744#endif
4745 return(NULL);
4746 case XML_NAMESPACE_DECL:
4747 /*
4748 * TODO !!! may require extending struct _xmlNs with
4749 * parent field
4750 * C.f. Infoset case...
4751 */
4752 return(NULL);
4753 }
4754 return(NULL);
4755}
4756
4757/**
4758 * xmlXPathNextAncestorOrSelf:
4759 * @ctxt: the XPath Parser context
4760 * @cur: the current node in the traversal
4761 *
4762 * Traversal function for the "ancestor-or-self" direction
4763 * he ancestor-or-self axis contains the context node and ancestors of
4764 * the context node in reverse document order; thus the context node is
4765 * the first node on the axis, and the context node's parent the second;
4766 * parent here is defined the same as with the parent axis.
4767 *
4768 * Returns the next element following that axis
4769 */
4770xmlNodePtr
4771xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4772 if (cur == NULL)
4773 return(ctxt->context->node);
4774 return(xmlXPathNextAncestor(ctxt, cur));
4775}
4776
4777/**
4778 * xmlXPathNextFollowingSibling:
4779 * @ctxt: the XPath Parser context
4780 * @cur: the current node in the traversal
4781 *
4782 * Traversal function for the "following-sibling" direction
4783 * The following-sibling axis contains the following siblings of the context
4784 * node in document order.
4785 *
4786 * Returns the next element following that axis
4787 */
4788xmlNodePtr
4789xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4790 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4791 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4792 return(NULL);
4793 if (cur == (xmlNodePtr) ctxt->context->doc)
4794 return(NULL);
4795 if (cur == NULL)
4796 return(ctxt->context->node->next);
4797 return(cur->next);
4798}
4799
4800/**
4801 * xmlXPathNextPrecedingSibling:
4802 * @ctxt: the XPath Parser context
4803 * @cur: the current node in the traversal
4804 *
4805 * Traversal function for the "preceding-sibling" direction
4806 * The preceding-sibling axis contains the preceding siblings of the context
4807 * node in reverse document order; the first preceding sibling is first on the
4808 * axis; the sibling preceding that node is the second on the axis and so on.
4809 *
4810 * Returns the next element following that axis
4811 */
4812xmlNodePtr
4813xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4814 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4815 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4816 return(NULL);
4817 if (cur == (xmlNodePtr) ctxt->context->doc)
4818 return(NULL);
4819 if (cur == NULL)
4820 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004821 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4822 cur = cur->prev;
4823 if (cur == NULL)
4824 return(ctxt->context->node->prev);
4825 }
Owen Taylor3473f882001-02-23 17:55:21 +00004826 return(cur->prev);
4827}
4828
4829/**
4830 * xmlXPathNextFollowing:
4831 * @ctxt: the XPath Parser context
4832 * @cur: the current node in the traversal
4833 *
4834 * Traversal function for the "following" direction
4835 * The following axis contains all nodes in the same document as the context
4836 * node that are after the context node in document order, excluding any
4837 * descendants and excluding attribute nodes and namespace nodes; the nodes
4838 * are ordered in document order
4839 *
4840 * Returns the next element following that axis
4841 */
4842xmlNodePtr
4843xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4844 if (cur != NULL && cur->children != NULL)
4845 return cur->children ;
4846 if (cur == NULL) cur = ctxt->context->node;
4847 if (cur == NULL) return(NULL) ; /* ERROR */
4848 if (cur->next != NULL) return(cur->next) ;
4849 do {
4850 cur = cur->parent;
4851 if (cur == NULL) return(NULL);
4852 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4853 if (cur->next != NULL) return(cur->next);
4854 } while (cur != NULL);
4855 return(cur);
4856}
4857
4858/*
4859 * xmlXPathIsAncestor:
4860 * @ancestor: the ancestor node
4861 * @node: the current node
4862 *
4863 * Check that @ancestor is a @node's ancestor
4864 *
4865 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4866 */
4867static int
4868xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4869 if ((ancestor == NULL) || (node == NULL)) return(0);
4870 /* nodes need to be in the same document */
4871 if (ancestor->doc != node->doc) return(0);
4872 /* avoid searching if ancestor or node is the root node */
4873 if (ancestor == (xmlNodePtr) node->doc) return(1);
4874 if (node == (xmlNodePtr) ancestor->doc) return(0);
4875 while (node->parent != NULL) {
4876 if (node->parent == ancestor)
4877 return(1);
4878 node = node->parent;
4879 }
4880 return(0);
4881}
4882
4883/**
4884 * xmlXPathNextPreceding:
4885 * @ctxt: the XPath Parser context
4886 * @cur: the current node in the traversal
4887 *
4888 * Traversal function for the "preceding" direction
4889 * the preceding axis contains all nodes in the same document as the context
4890 * node that are before the context node in document order, excluding any
4891 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4892 * ordered in reverse document order
4893 *
4894 * Returns the next element following that axis
4895 */
4896xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004897xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4898{
Owen Taylor3473f882001-02-23 17:55:21 +00004899 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004900 cur = ctxt->context->node;
4901 if (cur == NULL)
4902 return (NULL);
4903 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4904 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004905 do {
4906 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004907 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4908 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004909 }
4910
4911 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004912 if (cur == NULL)
4913 return (NULL);
4914 if (cur == ctxt->context->doc->children)
4915 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004916 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004917 return (cur);
4918}
4919
4920/**
4921 * xmlXPathNextPrecedingInternal:
4922 * @ctxt: the XPath Parser context
4923 * @cur: the current node in the traversal
4924 *
4925 * Traversal function for the "preceding" direction
4926 * the preceding axis contains all nodes in the same document as the context
4927 * node that are before the context node in document order, excluding any
4928 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4929 * ordered in reverse document order
4930 * This is a faster implementation but internal only since it requires a
4931 * state kept in the parser context: ctxt->ancestor.
4932 *
4933 * Returns the next element following that axis
4934 */
4935static xmlNodePtr
4936xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4937 xmlNodePtr cur)
4938{
4939 if (cur == NULL) {
4940 cur = ctxt->context->node;
4941 if (cur == NULL)
4942 return (NULL);
4943 ctxt->ancestor = cur->parent;
4944 }
4945 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4946 cur = cur->prev;
4947 while (cur->prev == NULL) {
4948 cur = cur->parent;
4949 if (cur == NULL)
4950 return (NULL);
4951 if (cur == ctxt->context->doc->children)
4952 return (NULL);
4953 if (cur != ctxt->ancestor)
4954 return (cur);
4955 ctxt->ancestor = cur->parent;
4956 }
4957 cur = cur->prev;
4958 while (cur->last != NULL)
4959 cur = cur->last;
4960 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004961}
4962
4963/**
4964 * xmlXPathNextNamespace:
4965 * @ctxt: the XPath Parser context
4966 * @cur: the current attribute in the traversal
4967 *
4968 * Traversal function for the "namespace" direction
4969 * the namespace axis contains the namespace nodes of the context node;
4970 * the order of nodes on this axis is implementation-defined; the axis will
4971 * be empty unless the context node is an element
4972 *
4973 * Returns the next element following that axis
4974 */
4975xmlNodePtr
4976xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4977 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
4978 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
4979 if (ctxt->context->namespaces != NULL)
4980 xmlFree(ctxt->context->namespaces);
4981 ctxt->context->namespaces =
4982 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
4983 if (ctxt->context->namespaces == NULL) return(NULL);
4984 ctxt->context->nsNr = 0;
4985 }
4986 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
4987}
4988
4989/**
4990 * xmlXPathNextAttribute:
4991 * @ctxt: the XPath Parser context
4992 * @cur: the current attribute in the traversal
4993 *
4994 * Traversal function for the "attribute" direction
4995 * TODO: support DTD inherited default attributes
4996 *
4997 * Returns the next element following that axis
4998 */
4999xmlNodePtr
5000xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005001 if (ctxt->context->node == NULL)
5002 return(NULL);
5003 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5004 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005005 if (cur == NULL) {
5006 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5007 return(NULL);
5008 return((xmlNodePtr)ctxt->context->node->properties);
5009 }
5010 return((xmlNodePtr)cur->next);
5011}
5012
5013/************************************************************************
5014 * *
5015 * NodeTest Functions *
5016 * *
5017 ************************************************************************/
5018
Owen Taylor3473f882001-02-23 17:55:21 +00005019#define IS_FUNCTION 200
5020
Owen Taylor3473f882001-02-23 17:55:21 +00005021
5022/************************************************************************
5023 * *
5024 * Implicit tree core function library *
5025 * *
5026 ************************************************************************/
5027
5028/**
5029 * xmlXPathRoot:
5030 * @ctxt: the XPath Parser context
5031 *
5032 * Initialize the context to the root of the document
5033 */
5034void
5035xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5036 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5037 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5038}
5039
5040/************************************************************************
5041 * *
5042 * The explicit core function library *
5043 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5044 * *
5045 ************************************************************************/
5046
5047
5048/**
5049 * xmlXPathLastFunction:
5050 * @ctxt: the XPath Parser context
5051 * @nargs: the number of arguments
5052 *
5053 * Implement the last() XPath function
5054 * number last()
5055 * The last function returns the number of nodes in the context node list.
5056 */
5057void
5058xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5059 CHECK_ARITY(0);
5060 if (ctxt->context->contextSize >= 0) {
5061 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5062#ifdef DEBUG_EXPR
5063 xmlGenericError(xmlGenericErrorContext,
5064 "last() : %d\n", ctxt->context->contextSize);
5065#endif
5066 } else {
5067 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5068 }
5069}
5070
5071/**
5072 * xmlXPathPositionFunction:
5073 * @ctxt: the XPath Parser context
5074 * @nargs: the number of arguments
5075 *
5076 * Implement the position() XPath function
5077 * number position()
5078 * The position function returns the position of the context node in the
5079 * context node list. The first position is 1, and so the last positionr
5080 * will be equal to last().
5081 */
5082void
5083xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5084 CHECK_ARITY(0);
5085 if (ctxt->context->proximityPosition >= 0) {
5086 valuePush(ctxt,
5087 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5088#ifdef DEBUG_EXPR
5089 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5090 ctxt->context->proximityPosition);
5091#endif
5092 } else {
5093 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5094 }
5095}
5096
5097/**
5098 * xmlXPathCountFunction:
5099 * @ctxt: the XPath Parser context
5100 * @nargs: the number of arguments
5101 *
5102 * Implement the count() XPath function
5103 * number count(node-set)
5104 */
5105void
5106xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5107 xmlXPathObjectPtr cur;
5108
5109 CHECK_ARITY(1);
5110 if ((ctxt->value == NULL) ||
5111 ((ctxt->value->type != XPATH_NODESET) &&
5112 (ctxt->value->type != XPATH_XSLT_TREE)))
5113 XP_ERROR(XPATH_INVALID_TYPE);
5114 cur = valuePop(ctxt);
5115
Daniel Veillard911f49a2001-04-07 15:39:35 +00005116 if ((cur == NULL) || (cur->nodesetval == NULL))
5117 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5118 else
5119 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00005120 xmlXPathFreeObject(cur);
5121}
5122
5123/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005124 * xmlXPathGetElementsByIds:
5125 * @doc: the document
5126 * @ids: a whitespace separated list of IDs
5127 *
5128 * Selects elements by their unique ID.
5129 *
5130 * Returns a node-set of selected elements.
5131 */
5132static xmlNodeSetPtr
5133xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5134 xmlNodeSetPtr ret;
5135 const xmlChar *cur = ids;
5136 xmlChar *ID;
5137 xmlAttrPtr attr;
5138 xmlNodePtr elem = NULL;
5139
5140 ret = xmlXPathNodeSetCreate(NULL);
5141
5142 while (IS_BLANK(*cur)) cur++;
5143 while (*cur != 0) {
5144 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5145 (*cur == '.') || (*cur == '-') ||
5146 (*cur == '_') || (*cur == ':') ||
5147 (IS_COMBINING(*cur)) ||
5148 (IS_EXTENDER(*cur)))
5149 cur++;
5150
5151 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5152
5153 ID = xmlStrndup(ids, cur - ids);
5154 attr = xmlGetID(doc, ID);
5155 if (attr != NULL) {
5156 elem = attr->parent;
5157 xmlXPathNodeSetAdd(ret, elem);
5158 }
5159 if (ID != NULL)
5160 xmlFree(ID);
5161
5162 while (IS_BLANK(*cur)) cur++;
5163 ids = cur;
5164 }
5165 return(ret);
5166}
5167
5168/**
Owen Taylor3473f882001-02-23 17:55:21 +00005169 * xmlXPathIdFunction:
5170 * @ctxt: the XPath Parser context
5171 * @nargs: the number of arguments
5172 *
5173 * Implement the id() XPath function
5174 * node-set id(object)
5175 * The id function selects elements by their unique ID
5176 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5177 * then the result is the union of the result of applying id to the
5178 * string value of each of the nodes in the argument node-set. When the
5179 * argument to id is of any other type, the argument is converted to a
5180 * string as if by a call to the string function; the string is split
5181 * into a whitespace-separated list of tokens (whitespace is any sequence
5182 * of characters matching the production S); the result is a node-set
5183 * containing the elements in the same document as the context node that
5184 * have a unique ID equal to any of the tokens in the list.
5185 */
5186void
5187xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005188 xmlChar *tokens;
5189 xmlNodeSetPtr ret;
5190 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005191
5192 CHECK_ARITY(1);
5193 obj = valuePop(ctxt);
5194 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5195 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005196 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005197 int i;
5198
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005199 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005200
Daniel Veillard911f49a2001-04-07 15:39:35 +00005201 if (obj->nodesetval != NULL) {
5202 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005203 tokens =
5204 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5205 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5206 ret = xmlXPathNodeSetMerge(ret, ns);
5207 xmlXPathFreeNodeSet(ns);
5208 if (tokens != NULL)
5209 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005210 }
Owen Taylor3473f882001-02-23 17:55:21 +00005211 }
5212
5213 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005214 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005215 return;
5216 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005217 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005218
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005219 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5220 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005221
Owen Taylor3473f882001-02-23 17:55:21 +00005222 xmlXPathFreeObject(obj);
5223 return;
5224}
5225
5226/**
5227 * xmlXPathLocalNameFunction:
5228 * @ctxt: the XPath Parser context
5229 * @nargs: the number of arguments
5230 *
5231 * Implement the local-name() XPath function
5232 * string local-name(node-set?)
5233 * The local-name function returns a string containing the local part
5234 * of the name of the node in the argument node-set that is first in
5235 * document order. If the node-set is empty or the first node has no
5236 * name, an empty string is returned. If the argument is omitted it
5237 * defaults to the context node.
5238 */
5239void
5240xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5241 xmlXPathObjectPtr cur;
5242
5243 if (nargs == 0) {
5244 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5245 nargs = 1;
5246 }
5247
5248 CHECK_ARITY(1);
5249 if ((ctxt->value == NULL) ||
5250 ((ctxt->value->type != XPATH_NODESET) &&
5251 (ctxt->value->type != XPATH_XSLT_TREE)))
5252 XP_ERROR(XPATH_INVALID_TYPE);
5253 cur = valuePop(ctxt);
5254
Daniel Veillard911f49a2001-04-07 15:39:35 +00005255 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005256 valuePush(ctxt, xmlXPathNewCString(""));
5257 } else {
5258 int i = 0; /* Should be first in document order !!!!! */
5259 switch (cur->nodesetval->nodeTab[i]->type) {
5260 case XML_ELEMENT_NODE:
5261 case XML_ATTRIBUTE_NODE:
5262 case XML_PI_NODE:
5263 valuePush(ctxt,
5264 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5265 break;
5266 case XML_NAMESPACE_DECL:
5267 valuePush(ctxt, xmlXPathNewString(
5268 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5269 break;
5270 default:
5271 valuePush(ctxt, xmlXPathNewCString(""));
5272 }
5273 }
5274 xmlXPathFreeObject(cur);
5275}
5276
5277/**
5278 * xmlXPathNamespaceURIFunction:
5279 * @ctxt: the XPath Parser context
5280 * @nargs: the number of arguments
5281 *
5282 * Implement the namespace-uri() XPath function
5283 * string namespace-uri(node-set?)
5284 * The namespace-uri function returns a string containing the
5285 * namespace URI of the expanded name of the node in the argument
5286 * node-set that is first in document order. If the node-set is empty,
5287 * the first node has no name, or the expanded name has no namespace
5288 * URI, an empty string is returned. If the argument is omitted it
5289 * defaults to the context node.
5290 */
5291void
5292xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5293 xmlXPathObjectPtr cur;
5294
5295 if (nargs == 0) {
5296 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5297 nargs = 1;
5298 }
5299 CHECK_ARITY(1);
5300 if ((ctxt->value == NULL) ||
5301 ((ctxt->value->type != XPATH_NODESET) &&
5302 (ctxt->value->type != XPATH_XSLT_TREE)))
5303 XP_ERROR(XPATH_INVALID_TYPE);
5304 cur = valuePop(ctxt);
5305
Daniel Veillard911f49a2001-04-07 15:39:35 +00005306 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005307 valuePush(ctxt, xmlXPathNewCString(""));
5308 } else {
5309 int i = 0; /* Should be first in document order !!!!! */
5310 switch (cur->nodesetval->nodeTab[i]->type) {
5311 case XML_ELEMENT_NODE:
5312 case XML_ATTRIBUTE_NODE:
5313 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5314 valuePush(ctxt, xmlXPathNewCString(""));
5315 else
5316 valuePush(ctxt, xmlXPathNewString(
5317 cur->nodesetval->nodeTab[i]->ns->href));
5318 break;
5319 default:
5320 valuePush(ctxt, xmlXPathNewCString(""));
5321 }
5322 }
5323 xmlXPathFreeObject(cur);
5324}
5325
5326/**
5327 * xmlXPathNameFunction:
5328 * @ctxt: the XPath Parser context
5329 * @nargs: the number of arguments
5330 *
5331 * Implement the name() XPath function
5332 * string name(node-set?)
5333 * The name function returns a string containing a QName representing
5334 * the name of the node in the argument node-set that is first in documenti
5335 * order. The QName must represent the name with respect to the namespace
5336 * declarations in effect on the node whose name is being represented.
5337 * Typically, this will be the form in which the name occurred in the XML
5338 * source. This need not be the case if there are namespace declarations
5339 * in effect on the node that associate multiple prefixes with the same
5340 * namespace. However, an implementation may include information about
5341 * the original prefix in its representation of nodes; in this case, an
5342 * implementation can ensure that the returned string is always the same
5343 * as the QName used in the XML source. If the argument it omitted it
5344 * defaults to the context node.
5345 * Libxml keep the original prefix so the "real qualified name" used is
5346 * returned.
5347 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005348static void
Daniel Veillard04383752001-07-08 14:27:15 +00005349xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5350{
Owen Taylor3473f882001-02-23 17:55:21 +00005351 xmlXPathObjectPtr cur;
5352
5353 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005354 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5355 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005356 }
5357
5358 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005359 if ((ctxt->value == NULL) ||
5360 ((ctxt->value->type != XPATH_NODESET) &&
5361 (ctxt->value->type != XPATH_XSLT_TREE)))
5362 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005363 cur = valuePop(ctxt);
5364
Daniel Veillard911f49a2001-04-07 15:39:35 +00005365 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005366 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005367 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005368 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005369
Daniel Veillard04383752001-07-08 14:27:15 +00005370 switch (cur->nodesetval->nodeTab[i]->type) {
5371 case XML_ELEMENT_NODE:
5372 case XML_ATTRIBUTE_NODE:
5373 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5374 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5375 valuePush(ctxt,
5376 xmlXPathNewString(cur->nodesetval->
5377 nodeTab[i]->name));
5378
5379 else {
5380 char name[2000];
5381
5382 snprintf(name, sizeof(name), "%s:%s",
5383 (char *) cur->nodesetval->nodeTab[i]->ns->
5384 prefix,
5385 (char *) cur->nodesetval->nodeTab[i]->name);
5386 name[sizeof(name) - 1] = 0;
5387 valuePush(ctxt, xmlXPathNewCString(name));
5388 }
5389 break;
5390 default:
5391 valuePush(ctxt,
5392 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5393 xmlXPathLocalNameFunction(ctxt, 1);
5394 }
Owen Taylor3473f882001-02-23 17:55:21 +00005395 }
5396 xmlXPathFreeObject(cur);
5397}
5398
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005399
5400/**
Owen Taylor3473f882001-02-23 17:55:21 +00005401 * xmlXPathStringFunction:
5402 * @ctxt: the XPath Parser context
5403 * @nargs: the number of arguments
5404 *
5405 * Implement the string() XPath function
5406 * string string(object?)
5407 * he string function converts an object to a string as follows:
5408 * - A node-set is converted to a string by returning the value of
5409 * the node in the node-set that is first in document order.
5410 * If the node-set is empty, an empty string is returned.
5411 * - A number is converted to a string as follows
5412 * + NaN is converted to the string NaN
5413 * + positive zero is converted to the string 0
5414 * + negative zero is converted to the string 0
5415 * + positive infinity is converted to the string Infinity
5416 * + negative infinity is converted to the string -Infinity
5417 * + if the number is an integer, the number is represented in
5418 * decimal form as a Number with no decimal point and no leading
5419 * zeros, preceded by a minus sign (-) if the number is negative
5420 * + otherwise, the number is represented in decimal form as a
5421 * Number including a decimal point with at least one digit
5422 * before the decimal point and at least one digit after the
5423 * decimal point, preceded by a minus sign (-) if the number
5424 * is negative; there must be no leading zeros before the decimal
5425 * point apart possibly from the one required digit immediatelyi
5426 * before the decimal point; beyond the one required digit
5427 * after the decimal point there must be as many, but only as
5428 * many, more digits as are needed to uniquely distinguish the
5429 * number from all other IEEE 754 numeric values.
5430 * - The boolean false value is converted to the string false.
5431 * The boolean true value is converted to the string true.
5432 *
5433 * If the argument is omitted, it defaults to a node-set with the
5434 * context node as its only member.
5435 */
5436void
5437xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5438 xmlXPathObjectPtr cur;
5439
5440 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005441 valuePush(ctxt,
5442 xmlXPathWrapString(
5443 xmlXPathCastNodeToString(ctxt->context->node)));
5444 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005445 }
5446
5447 CHECK_ARITY(1);
5448 cur = valuePop(ctxt);
5449 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005450 cur = xmlXPathConvertString(cur);
5451 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005452}
5453
5454/**
5455 * xmlXPathStringLengthFunction:
5456 * @ctxt: the XPath Parser context
5457 * @nargs: the number of arguments
5458 *
5459 * Implement the string-length() XPath function
5460 * number string-length(string?)
5461 * The string-length returns the number of characters in the string
5462 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5463 * the context node converted to a string, in other words the value
5464 * of the context node.
5465 */
5466void
5467xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5468 xmlXPathObjectPtr cur;
5469
5470 if (nargs == 0) {
5471 if (ctxt->context->node == NULL) {
5472 valuePush(ctxt, xmlXPathNewFloat(0));
5473 } else {
5474 xmlChar *content;
5475
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005476 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005477 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005478 xmlFree(content);
5479 }
5480 return;
5481 }
5482 CHECK_ARITY(1);
5483 CAST_TO_STRING;
5484 CHECK_TYPE(XPATH_STRING);
5485 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005486 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005487 xmlXPathFreeObject(cur);
5488}
5489
5490/**
5491 * xmlXPathConcatFunction:
5492 * @ctxt: the XPath Parser context
5493 * @nargs: the number of arguments
5494 *
5495 * Implement the concat() XPath function
5496 * string concat(string, string, string*)
5497 * The concat function returns the concatenation of its arguments.
5498 */
5499void
5500xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5501 xmlXPathObjectPtr cur, newobj;
5502 xmlChar *tmp;
5503
5504 if (nargs < 2) {
5505 CHECK_ARITY(2);
5506 }
5507
5508 CAST_TO_STRING;
5509 cur = valuePop(ctxt);
5510 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5511 xmlXPathFreeObject(cur);
5512 return;
5513 }
5514 nargs--;
5515
5516 while (nargs > 0) {
5517 CAST_TO_STRING;
5518 newobj = valuePop(ctxt);
5519 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5520 xmlXPathFreeObject(newobj);
5521 xmlXPathFreeObject(cur);
5522 XP_ERROR(XPATH_INVALID_TYPE);
5523 }
5524 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5525 newobj->stringval = cur->stringval;
5526 cur->stringval = tmp;
5527
5528 xmlXPathFreeObject(newobj);
5529 nargs--;
5530 }
5531 valuePush(ctxt, cur);
5532}
5533
5534/**
5535 * xmlXPathContainsFunction:
5536 * @ctxt: the XPath Parser context
5537 * @nargs: the number of arguments
5538 *
5539 * Implement the contains() XPath function
5540 * boolean contains(string, string)
5541 * The contains function returns true if the first argument string
5542 * contains the second argument string, and otherwise returns false.
5543 */
5544void
5545xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5546 xmlXPathObjectPtr hay, needle;
5547
5548 CHECK_ARITY(2);
5549 CAST_TO_STRING;
5550 CHECK_TYPE(XPATH_STRING);
5551 needle = valuePop(ctxt);
5552 CAST_TO_STRING;
5553 hay = valuePop(ctxt);
5554 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5555 xmlXPathFreeObject(hay);
5556 xmlXPathFreeObject(needle);
5557 XP_ERROR(XPATH_INVALID_TYPE);
5558 }
5559 if (xmlStrstr(hay->stringval, needle->stringval))
5560 valuePush(ctxt, xmlXPathNewBoolean(1));
5561 else
5562 valuePush(ctxt, xmlXPathNewBoolean(0));
5563 xmlXPathFreeObject(hay);
5564 xmlXPathFreeObject(needle);
5565}
5566
5567/**
5568 * xmlXPathStartsWithFunction:
5569 * @ctxt: the XPath Parser context
5570 * @nargs: the number of arguments
5571 *
5572 * Implement the starts-with() XPath function
5573 * boolean starts-with(string, string)
5574 * The starts-with function returns true if the first argument string
5575 * starts with the second argument string, and otherwise returns false.
5576 */
5577void
5578xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5579 xmlXPathObjectPtr hay, needle;
5580 int n;
5581
5582 CHECK_ARITY(2);
5583 CAST_TO_STRING;
5584 CHECK_TYPE(XPATH_STRING);
5585 needle = valuePop(ctxt);
5586 CAST_TO_STRING;
5587 hay = valuePop(ctxt);
5588 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5589 xmlXPathFreeObject(hay);
5590 xmlXPathFreeObject(needle);
5591 XP_ERROR(XPATH_INVALID_TYPE);
5592 }
5593 n = xmlStrlen(needle->stringval);
5594 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5595 valuePush(ctxt, xmlXPathNewBoolean(0));
5596 else
5597 valuePush(ctxt, xmlXPathNewBoolean(1));
5598 xmlXPathFreeObject(hay);
5599 xmlXPathFreeObject(needle);
5600}
5601
5602/**
5603 * xmlXPathSubstringFunction:
5604 * @ctxt: the XPath Parser context
5605 * @nargs: the number of arguments
5606 *
5607 * Implement the substring() XPath function
5608 * string substring(string, number, number?)
5609 * The substring function returns the substring of the first argument
5610 * starting at the position specified in the second argument with
5611 * length specified in the third argument. For example,
5612 * substring("12345",2,3) returns "234". If the third argument is not
5613 * specified, it returns the substring starting at the position specified
5614 * in the second argument and continuing to the end of the string. For
5615 * example, substring("12345",2) returns "2345". More precisely, each
5616 * character in the string (see [3.6 Strings]) is considered to have a
5617 * numeric position: the position of the first character is 1, the position
5618 * of the second character is 2 and so on. The returned substring contains
5619 * those characters for which the position of the character is greater than
5620 * or equal to the second argument and, if the third argument is specified,
5621 * less than the sum of the second and third arguments; the comparisons
5622 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5623 * - substring("12345", 1.5, 2.6) returns "234"
5624 * - substring("12345", 0, 3) returns "12"
5625 * - substring("12345", 0 div 0, 3) returns ""
5626 * - substring("12345", 1, 0 div 0) returns ""
5627 * - substring("12345", -42, 1 div 0) returns "12345"
5628 * - substring("12345", -1 div 0, 1 div 0) returns ""
5629 */
5630void
5631xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5632 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005633 double le=0, in;
5634 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005635 xmlChar *ret;
5636
Owen Taylor3473f882001-02-23 17:55:21 +00005637 if (nargs < 2) {
5638 CHECK_ARITY(2);
5639 }
5640 if (nargs > 3) {
5641 CHECK_ARITY(3);
5642 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005643 /*
5644 * take care of possible last (position) argument
5645 */
Owen Taylor3473f882001-02-23 17:55:21 +00005646 if (nargs == 3) {
5647 CAST_TO_NUMBER;
5648 CHECK_TYPE(XPATH_NUMBER);
5649 len = valuePop(ctxt);
5650 le = len->floatval;
5651 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005652 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005653
Owen Taylor3473f882001-02-23 17:55:21 +00005654 CAST_TO_NUMBER;
5655 CHECK_TYPE(XPATH_NUMBER);
5656 start = valuePop(ctxt);
5657 in = start->floatval;
5658 xmlXPathFreeObject(start);
5659 CAST_TO_STRING;
5660 CHECK_TYPE(XPATH_STRING);
5661 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005662 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005663
Daniel Veillard97ac1312001-05-30 19:14:17 +00005664 /*
5665 * If last pos not present, calculate last position
5666 */
5667 if (nargs != 3)
5668 le = m;
5669
5670 /*
5671 * To meet our requirements, initial index calculations
5672 * must be done before we convert to integer format
5673 *
5674 * First we normalize indices
5675 */
5676 in -= 1.0;
5677 le += in;
5678 if (in < 0.0)
5679 in = 0.0;
5680 if (le > (double)m)
5681 le = (double)m;
5682
5683 /*
5684 * Now we go to integer form, rounding up
5685 */
Owen Taylor3473f882001-02-23 17:55:21 +00005686 i = (int) in;
5687 if (((double)i) != in) i++;
5688
Owen Taylor3473f882001-02-23 17:55:21 +00005689 l = (int) le;
5690 if (((double)l) != le) l++;
5691
Daniel Veillard97ac1312001-05-30 19:14:17 +00005692 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005693
5694 /* number of chars to copy */
5695 l -= i;
5696
Daniel Veillard97ac1312001-05-30 19:14:17 +00005697 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005698 if (ret == NULL)
5699 valuePush(ctxt, xmlXPathNewCString(""));
5700 else {
5701 valuePush(ctxt, xmlXPathNewString(ret));
5702 xmlFree(ret);
5703 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005704
Owen Taylor3473f882001-02-23 17:55:21 +00005705 xmlXPathFreeObject(str);
5706}
5707
5708/**
5709 * xmlXPathSubstringBeforeFunction:
5710 * @ctxt: the XPath Parser context
5711 * @nargs: the number of arguments
5712 *
5713 * Implement the substring-before() XPath function
5714 * string substring-before(string, string)
5715 * The substring-before function returns the substring of the first
5716 * argument string that precedes the first occurrence of the second
5717 * argument string in the first argument string, or the empty string
5718 * if the first argument string does not contain the second argument
5719 * string. For example, substring-before("1999/04/01","/") returns 1999.
5720 */
5721void
5722xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5723 xmlXPathObjectPtr str;
5724 xmlXPathObjectPtr find;
5725 xmlBufferPtr target;
5726 const xmlChar *point;
5727 int offset;
5728
5729 CHECK_ARITY(2);
5730 CAST_TO_STRING;
5731 find = valuePop(ctxt);
5732 CAST_TO_STRING;
5733 str = valuePop(ctxt);
5734
5735 target = xmlBufferCreate();
5736 if (target) {
5737 point = xmlStrstr(str->stringval, find->stringval);
5738 if (point) {
5739 offset = (int)(point - str->stringval);
5740 xmlBufferAdd(target, str->stringval, offset);
5741 }
5742 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5743 xmlBufferFree(target);
5744 }
5745
5746 xmlXPathFreeObject(str);
5747 xmlXPathFreeObject(find);
5748}
5749
5750/**
5751 * xmlXPathSubstringAfterFunction:
5752 * @ctxt: the XPath Parser context
5753 * @nargs: the number of arguments
5754 *
5755 * Implement the substring-after() XPath function
5756 * string substring-after(string, string)
5757 * The substring-after function returns the substring of the first
5758 * argument string that follows the first occurrence of the second
5759 * argument string in the first argument string, or the empty stringi
5760 * if the first argument string does not contain the second argument
5761 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5762 * and substring-after("1999/04/01","19") returns 99/04/01.
5763 */
5764void
5765xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5766 xmlXPathObjectPtr str;
5767 xmlXPathObjectPtr find;
5768 xmlBufferPtr target;
5769 const xmlChar *point;
5770 int offset;
5771
5772 CHECK_ARITY(2);
5773 CAST_TO_STRING;
5774 find = valuePop(ctxt);
5775 CAST_TO_STRING;
5776 str = valuePop(ctxt);
5777
5778 target = xmlBufferCreate();
5779 if (target) {
5780 point = xmlStrstr(str->stringval, find->stringval);
5781 if (point) {
5782 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5783 xmlBufferAdd(target, &str->stringval[offset],
5784 xmlStrlen(str->stringval) - offset);
5785 }
5786 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5787 xmlBufferFree(target);
5788 }
5789
5790 xmlXPathFreeObject(str);
5791 xmlXPathFreeObject(find);
5792}
5793
5794/**
5795 * xmlXPathNormalizeFunction:
5796 * @ctxt: the XPath Parser context
5797 * @nargs: the number of arguments
5798 *
5799 * Implement the normalize-space() XPath function
5800 * string normalize-space(string?)
5801 * The normalize-space function returns the argument string with white
5802 * space normalized by stripping leading and trailing whitespace
5803 * and replacing sequences of whitespace characters by a single
5804 * space. Whitespace characters are the same allowed by the S production
5805 * in XML. If the argument is omitted, it defaults to the context
5806 * node converted to a string, in other words the value of the context node.
5807 */
5808void
5809xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5810 xmlXPathObjectPtr obj = NULL;
5811 xmlChar *source = NULL;
5812 xmlBufferPtr target;
5813 xmlChar blank;
5814
5815 if (nargs == 0) {
5816 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005817 valuePush(ctxt,
5818 xmlXPathWrapString(
5819 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005820 nargs = 1;
5821 }
5822
5823 CHECK_ARITY(1);
5824 CAST_TO_STRING;
5825 CHECK_TYPE(XPATH_STRING);
5826 obj = valuePop(ctxt);
5827 source = obj->stringval;
5828
5829 target = xmlBufferCreate();
5830 if (target && source) {
5831
5832 /* Skip leading whitespaces */
5833 while (IS_BLANK(*source))
5834 source++;
5835
5836 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5837 blank = 0;
5838 while (*source) {
5839 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005840 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005841 } else {
5842 if (blank) {
5843 xmlBufferAdd(target, &blank, 1);
5844 blank = 0;
5845 }
5846 xmlBufferAdd(target, source, 1);
5847 }
5848 source++;
5849 }
5850
5851 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5852 xmlBufferFree(target);
5853 }
5854 xmlXPathFreeObject(obj);
5855}
5856
5857/**
5858 * xmlXPathTranslateFunction:
5859 * @ctxt: the XPath Parser context
5860 * @nargs: the number of arguments
5861 *
5862 * Implement the translate() XPath function
5863 * string translate(string, string, string)
5864 * The translate function returns the first argument string with
5865 * occurrences of characters in the second argument string replaced
5866 * by the character at the corresponding position in the third argument
5867 * string. For example, translate("bar","abc","ABC") returns the string
5868 * BAr. If there is a character in the second argument string with no
5869 * character at a corresponding position in the third argument string
5870 * (because the second argument string is longer than the third argument
5871 * string), then occurrences of that character in the first argument
5872 * string are removed. For example, translate("--aaa--","abc-","ABC")
5873 * returns "AAA". If a character occurs more than once in second
5874 * argument string, then the first occurrence determines the replacement
5875 * character. If the third argument string is longer than the second
5876 * argument string, then excess characters are ignored.
5877 */
5878void
5879xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005880 xmlXPathObjectPtr str;
5881 xmlXPathObjectPtr from;
5882 xmlXPathObjectPtr to;
5883 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005884 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005885 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005886 xmlChar *point;
5887 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005888
Daniel Veillarde043ee12001-04-16 14:08:07 +00005889 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005890
Daniel Veillarde043ee12001-04-16 14:08:07 +00005891 CAST_TO_STRING;
5892 to = valuePop(ctxt);
5893 CAST_TO_STRING;
5894 from = valuePop(ctxt);
5895 CAST_TO_STRING;
5896 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005897
Daniel Veillarde043ee12001-04-16 14:08:07 +00005898 target = xmlBufferCreate();
5899 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005900 max = xmlUTF8Strlen(to->stringval);
5901 for (cptr = str->stringval; (ch=*cptr); ) {
5902 offset = xmlUTF8Strloc(from->stringval, cptr);
5903 if (offset >= 0) {
5904 if (offset < max) {
5905 point = xmlUTF8Strpos(to->stringval, offset);
5906 if (point)
5907 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5908 }
5909 } else
5910 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5911
5912 /* Step to next character in input */
5913 cptr++;
5914 if ( ch & 0x80 ) {
5915 /* if not simple ascii, verify proper format */
5916 if ( (ch & 0xc0) != 0xc0 ) {
5917 xmlGenericError(xmlGenericErrorContext,
5918 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5919 break;
5920 }
5921 /* then skip over remaining bytes for this char */
5922 while ( (ch <<= 1) & 0x80 )
5923 if ( (*cptr++ & 0xc0) != 0x80 ) {
5924 xmlGenericError(xmlGenericErrorContext,
5925 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5926 break;
5927 }
5928 if (ch & 0x80) /* must have had error encountered */
5929 break;
5930 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005931 }
Owen Taylor3473f882001-02-23 17:55:21 +00005932 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005933 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5934 xmlBufferFree(target);
5935 xmlXPathFreeObject(str);
5936 xmlXPathFreeObject(from);
5937 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005938}
5939
5940/**
5941 * xmlXPathBooleanFunction:
5942 * @ctxt: the XPath Parser context
5943 * @nargs: the number of arguments
5944 *
5945 * Implement the boolean() XPath function
5946 * boolean boolean(object)
5947 * he boolean function converts its argument to a boolean as follows:
5948 * - a number is true if and only if it is neither positive or
5949 * negative zero nor NaN
5950 * - a node-set is true if and only if it is non-empty
5951 * - a string is true if and only if its length is non-zero
5952 */
5953void
5954xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5955 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005956
5957 CHECK_ARITY(1);
5958 cur = valuePop(ctxt);
5959 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005960 cur = xmlXPathConvertBoolean(cur);
5961 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005962}
5963
5964/**
5965 * xmlXPathNotFunction:
5966 * @ctxt: the XPath Parser context
5967 * @nargs: the number of arguments
5968 *
5969 * Implement the not() XPath function
5970 * boolean not(boolean)
5971 * The not function returns true if its argument is false,
5972 * and false otherwise.
5973 */
5974void
5975xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5976 CHECK_ARITY(1);
5977 CAST_TO_BOOLEAN;
5978 CHECK_TYPE(XPATH_BOOLEAN);
5979 ctxt->value->boolval = ! ctxt->value->boolval;
5980}
5981
5982/**
5983 * xmlXPathTrueFunction:
5984 * @ctxt: the XPath Parser context
5985 * @nargs: the number of arguments
5986 *
5987 * Implement the true() XPath function
5988 * boolean true()
5989 */
5990void
5991xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5992 CHECK_ARITY(0);
5993 valuePush(ctxt, xmlXPathNewBoolean(1));
5994}
5995
5996/**
5997 * xmlXPathFalseFunction:
5998 * @ctxt: the XPath Parser context
5999 * @nargs: the number of arguments
6000 *
6001 * Implement the false() XPath function
6002 * boolean false()
6003 */
6004void
6005xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6006 CHECK_ARITY(0);
6007 valuePush(ctxt, xmlXPathNewBoolean(0));
6008}
6009
6010/**
6011 * xmlXPathLangFunction:
6012 * @ctxt: the XPath Parser context
6013 * @nargs: the number of arguments
6014 *
6015 * Implement the lang() XPath function
6016 * boolean lang(string)
6017 * The lang function returns true or false depending on whether the
6018 * language of the context node as specified by xml:lang attributes
6019 * is the same as or is a sublanguage of the language specified by
6020 * the argument string. The language of the context node is determined
6021 * by the value of the xml:lang attribute on the context node, or, if
6022 * the context node has no xml:lang attribute, by the value of the
6023 * xml:lang attribute on the nearest ancestor of the context node that
6024 * has an xml:lang attribute. If there is no such attribute, then lang
6025 * returns false. If there is such an attribute, then lang returns
6026 * true if the attribute value is equal to the argument ignoring case,
6027 * or if there is some suffix starting with - such that the attribute
6028 * value is equal to the argument ignoring that suffix of the attribute
6029 * value and ignoring case.
6030 */
6031void
6032xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6033 xmlXPathObjectPtr val;
6034 const xmlChar *theLang;
6035 const xmlChar *lang;
6036 int ret = 0;
6037 int i;
6038
6039 CHECK_ARITY(1);
6040 CAST_TO_STRING;
6041 CHECK_TYPE(XPATH_STRING);
6042 val = valuePop(ctxt);
6043 lang = val->stringval;
6044 theLang = xmlNodeGetLang(ctxt->context->node);
6045 if ((theLang != NULL) && (lang != NULL)) {
6046 for (i = 0;lang[i] != 0;i++)
6047 if (toupper(lang[i]) != toupper(theLang[i]))
6048 goto not_equal;
6049 ret = 1;
6050 }
6051not_equal:
6052 xmlXPathFreeObject(val);
6053 valuePush(ctxt, xmlXPathNewBoolean(ret));
6054}
6055
6056/**
6057 * xmlXPathNumberFunction:
6058 * @ctxt: the XPath Parser context
6059 * @nargs: the number of arguments
6060 *
6061 * Implement the number() XPath function
6062 * number number(object?)
6063 */
6064void
6065xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6066 xmlXPathObjectPtr cur;
6067 double res;
6068
6069 if (nargs == 0) {
6070 if (ctxt->context->node == NULL) {
6071 valuePush(ctxt, xmlXPathNewFloat(0.0));
6072 } else {
6073 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6074
6075 res = xmlXPathStringEvalNumber(content);
6076 valuePush(ctxt, xmlXPathNewFloat(res));
6077 xmlFree(content);
6078 }
6079 return;
6080 }
6081
6082 CHECK_ARITY(1);
6083 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006084 cur = xmlXPathConvertNumber(cur);
6085 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006086}
6087
6088/**
6089 * xmlXPathSumFunction:
6090 * @ctxt: the XPath Parser context
6091 * @nargs: the number of arguments
6092 *
6093 * Implement the sum() XPath function
6094 * number sum(node-set)
6095 * The sum function returns the sum of the values of the nodes in
6096 * the argument node-set.
6097 */
6098void
6099xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6100 xmlXPathObjectPtr cur;
6101 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006102 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006103
6104 CHECK_ARITY(1);
6105 if ((ctxt->value == NULL) ||
6106 ((ctxt->value->type != XPATH_NODESET) &&
6107 (ctxt->value->type != XPATH_XSLT_TREE)))
6108 XP_ERROR(XPATH_INVALID_TYPE);
6109 cur = valuePop(ctxt);
6110
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006111 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006112 valuePush(ctxt, xmlXPathNewFloat(0.0));
6113 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006114 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6115 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006116 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006117 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006118 }
6119 xmlXPathFreeObject(cur);
6120}
6121
6122/**
6123 * xmlXPathFloorFunction:
6124 * @ctxt: the XPath Parser context
6125 * @nargs: the number of arguments
6126 *
6127 * Implement the floor() XPath function
6128 * number floor(number)
6129 * The floor function returns the largest (closest to positive infinity)
6130 * number that is not greater than the argument and that is an integer.
6131 */
6132void
6133xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6134 CHECK_ARITY(1);
6135 CAST_TO_NUMBER;
6136 CHECK_TYPE(XPATH_NUMBER);
6137#if 0
6138 ctxt->value->floatval = floor(ctxt->value->floatval);
6139#else
6140 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6141 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6142#endif
6143}
6144
6145/**
6146 * xmlXPathCeilingFunction:
6147 * @ctxt: the XPath Parser context
6148 * @nargs: the number of arguments
6149 *
6150 * Implement the ceiling() XPath function
6151 * number ceiling(number)
6152 * The ceiling function returns the smallest (closest to negative infinity)
6153 * number that is not less than the argument and that is an integer.
6154 */
6155void
6156xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6157 double f;
6158
6159 CHECK_ARITY(1);
6160 CAST_TO_NUMBER;
6161 CHECK_TYPE(XPATH_NUMBER);
6162
6163#if 0
6164 ctxt->value->floatval = ceil(ctxt->value->floatval);
6165#else
6166 f = (double)((int) ctxt->value->floatval);
6167 if (f != ctxt->value->floatval)
6168 ctxt->value->floatval = f + 1;
6169#endif
6170}
6171
6172/**
6173 * xmlXPathRoundFunction:
6174 * @ctxt: the XPath Parser context
6175 * @nargs: the number of arguments
6176 *
6177 * Implement the round() XPath function
6178 * number round(number)
6179 * The round function returns the number that is closest to the
6180 * argument and that is an integer. If there are two such numbers,
6181 * then the one that is even is returned.
6182 */
6183void
6184xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6185 double f;
6186
6187 CHECK_ARITY(1);
6188 CAST_TO_NUMBER;
6189 CHECK_TYPE(XPATH_NUMBER);
6190
6191 if ((ctxt->value->floatval == xmlXPathNAN) ||
6192 (ctxt->value->floatval == xmlXPathPINF) ||
6193 (ctxt->value->floatval == xmlXPathNINF) ||
6194 (ctxt->value->floatval == 0.0))
6195 return;
6196
6197#if 0
6198 f = floor(ctxt->value->floatval);
6199#else
6200 f = (double)((int) ctxt->value->floatval);
6201#endif
6202 if (ctxt->value->floatval < f + 0.5)
6203 ctxt->value->floatval = f;
6204 else
6205 ctxt->value->floatval = f + 1;
6206}
6207
6208/************************************************************************
6209 * *
6210 * The Parser *
6211 * *
6212 ************************************************************************/
6213
6214/*
6215 * a couple of forward declarations since we use a recursive call based
6216 * implementation.
6217 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006218static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006219static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006220static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006221#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006222static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6223#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006224#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006225static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006226#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006227static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6228 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006229
6230/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006231 * xmlXPathCurrentChar:
6232 * @ctxt: the XPath parser context
6233 * @cur: pointer to the beginning of the char
6234 * @len: pointer to the length of the char read
6235 *
6236 * The current char value, if using UTF-8 this may actaully span multiple
6237 * bytes in the input buffer.
6238 *
6239 * Returns the current char value and its lenght
6240 */
6241
6242static int
6243xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6244 unsigned char c;
6245 unsigned int val;
6246 const xmlChar *cur;
6247
6248 if (ctxt == NULL)
6249 return(0);
6250 cur = ctxt->cur;
6251
6252 /*
6253 * We are supposed to handle UTF8, check it's valid
6254 * From rfc2044: encoding of the Unicode values on UTF-8:
6255 *
6256 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6257 * 0000 0000-0000 007F 0xxxxxxx
6258 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6259 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6260 *
6261 * Check for the 0x110000 limit too
6262 */
6263 c = *cur;
6264 if (c & 0x80) {
6265 if ((cur[1] & 0xc0) != 0x80)
6266 goto encoding_error;
6267 if ((c & 0xe0) == 0xe0) {
6268
6269 if ((cur[2] & 0xc0) != 0x80)
6270 goto encoding_error;
6271 if ((c & 0xf0) == 0xf0) {
6272 if (((c & 0xf8) != 0xf0) ||
6273 ((cur[3] & 0xc0) != 0x80))
6274 goto encoding_error;
6275 /* 4-byte code */
6276 *len = 4;
6277 val = (cur[0] & 0x7) << 18;
6278 val |= (cur[1] & 0x3f) << 12;
6279 val |= (cur[2] & 0x3f) << 6;
6280 val |= cur[3] & 0x3f;
6281 } else {
6282 /* 3-byte code */
6283 *len = 3;
6284 val = (cur[0] & 0xf) << 12;
6285 val |= (cur[1] & 0x3f) << 6;
6286 val |= cur[2] & 0x3f;
6287 }
6288 } else {
6289 /* 2-byte code */
6290 *len = 2;
6291 val = (cur[0] & 0x1f) << 6;
6292 val |= cur[1] & 0x3f;
6293 }
6294 if (!IS_CHAR(val)) {
6295 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6296 }
6297 return(val);
6298 } else {
6299 /* 1-byte code */
6300 *len = 1;
6301 return((int) *cur);
6302 }
6303encoding_error:
6304 /*
6305 * If we detect an UTF8 error that probably mean that the
6306 * input encoding didn't get properly advertized in the
6307 * declaration header. Report the error and switch the encoding
6308 * to ISO-Latin-1 (if you don't like this policy, just declare the
6309 * encoding !)
6310 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006311 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006312 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006313}
6314
6315/**
Owen Taylor3473f882001-02-23 17:55:21 +00006316 * xmlXPathParseNCName:
6317 * @ctxt: the XPath Parser context
6318 *
6319 * parse an XML namespace non qualified name.
6320 *
6321 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6322 *
6323 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6324 * CombiningChar | Extender
6325 *
6326 * Returns the namespace name or NULL
6327 */
6328
6329xmlChar *
6330xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006331 const xmlChar *in;
6332 xmlChar *ret;
6333 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006334
Daniel Veillard2156a562001-04-28 12:24:34 +00006335 /*
6336 * Accelerator for simple ASCII names
6337 */
6338 in = ctxt->cur;
6339 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6340 ((*in >= 0x41) && (*in <= 0x5A)) ||
6341 (*in == '_')) {
6342 in++;
6343 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6344 ((*in >= 0x41) && (*in <= 0x5A)) ||
6345 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006346 (*in == '_') || (*in == '.') ||
6347 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006348 in++;
6349 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6350 (*in == '[') || (*in == ']') || (*in == ':') ||
6351 (*in == '@') || (*in == '*')) {
6352 count = in - ctxt->cur;
6353 if (count == 0)
6354 return(NULL);
6355 ret = xmlStrndup(ctxt->cur, count);
6356 ctxt->cur = in;
6357 return(ret);
6358 }
6359 }
6360 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006361}
6362
Daniel Veillard2156a562001-04-28 12:24:34 +00006363
Owen Taylor3473f882001-02-23 17:55:21 +00006364/**
6365 * xmlXPathParseQName:
6366 * @ctxt: the XPath Parser context
6367 * @prefix: a xmlChar **
6368 *
6369 * parse an XML qualified name
6370 *
6371 * [NS 5] QName ::= (Prefix ':')? LocalPart
6372 *
6373 * [NS 6] Prefix ::= NCName
6374 *
6375 * [NS 7] LocalPart ::= NCName
6376 *
6377 * Returns the function returns the local part, and prefix is updated
6378 * to get the Prefix if any.
6379 */
6380
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006381static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006382xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6383 xmlChar *ret = NULL;
6384
6385 *prefix = NULL;
6386 ret = xmlXPathParseNCName(ctxt);
6387 if (CUR == ':') {
6388 *prefix = ret;
6389 NEXT;
6390 ret = xmlXPathParseNCName(ctxt);
6391 }
6392 return(ret);
6393}
6394
6395/**
6396 * xmlXPathParseName:
6397 * @ctxt: the XPath Parser context
6398 *
6399 * parse an XML name
6400 *
6401 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6402 * CombiningChar | Extender
6403 *
6404 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6405 *
6406 * Returns the namespace name or NULL
6407 */
6408
6409xmlChar *
6410xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006411 const xmlChar *in;
6412 xmlChar *ret;
6413 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006414
Daniel Veillard61d80a22001-04-27 17:13:01 +00006415 /*
6416 * Accelerator for simple ASCII names
6417 */
6418 in = ctxt->cur;
6419 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6420 ((*in >= 0x41) && (*in <= 0x5A)) ||
6421 (*in == '_') || (*in == ':')) {
6422 in++;
6423 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6424 ((*in >= 0x41) && (*in <= 0x5A)) ||
6425 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006426 (*in == '_') || (*in == '-') ||
6427 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006428 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006429 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006430 count = in - ctxt->cur;
6431 ret = xmlStrndup(ctxt->cur, count);
6432 ctxt->cur = in;
6433 return(ret);
6434 }
6435 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006436 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006437}
6438
Daniel Veillard61d80a22001-04-27 17:13:01 +00006439static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006440xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006441 xmlChar buf[XML_MAX_NAMELEN + 5];
6442 int len = 0, l;
6443 int c;
6444
6445 /*
6446 * Handler for more complex cases
6447 */
6448 c = CUR_CHAR(l);
6449 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006450 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6451 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006452 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006453 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006454 return(NULL);
6455 }
6456
6457 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6458 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6459 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006460 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006461 (IS_COMBINING(c)) ||
6462 (IS_EXTENDER(c)))) {
6463 COPY_BUF(l,buf,len,c);
6464 NEXTL(l);
6465 c = CUR_CHAR(l);
6466 if (len >= XML_MAX_NAMELEN) {
6467 /*
6468 * Okay someone managed to make a huge name, so he's ready to pay
6469 * for the processing speed.
6470 */
6471 xmlChar *buffer;
6472 int max = len * 2;
6473
6474 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6475 if (buffer == NULL) {
6476 XP_ERROR0(XPATH_MEMORY_ERROR);
6477 }
6478 memcpy(buffer, buf, len);
6479 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6480 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006481 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006482 (IS_COMBINING(c)) ||
6483 (IS_EXTENDER(c))) {
6484 if (len + 10 > max) {
6485 max *= 2;
6486 buffer = (xmlChar *) xmlRealloc(buffer,
6487 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006488 if (buffer == NULL) {
6489 XP_ERROR0(XPATH_MEMORY_ERROR);
6490 }
6491 }
6492 COPY_BUF(l,buffer,len,c);
6493 NEXTL(l);
6494 c = CUR_CHAR(l);
6495 }
6496 buffer[len] = 0;
6497 return(buffer);
6498 }
6499 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006500 if (len == 0)
6501 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006502 return(xmlStrndup(buf, len));
6503}
Owen Taylor3473f882001-02-23 17:55:21 +00006504/**
6505 * xmlXPathStringEvalNumber:
6506 * @str: A string to scan
6507 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006508 * [30a] Float ::= Number ('e' Digits?)?
6509 *
Owen Taylor3473f882001-02-23 17:55:21 +00006510 * [30] Number ::= Digits ('.' Digits?)?
6511 * | '.' Digits
6512 * [31] Digits ::= [0-9]+
6513 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006514 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006515 * In complement of the Number expression, this function also handles
6516 * negative values : '-' Number.
6517 *
6518 * Returns the double value.
6519 */
6520double
6521xmlXPathStringEvalNumber(const xmlChar *str) {
6522 const xmlChar *cur = str;
6523 double ret = 0.0;
6524 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006525 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006526 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006527 int exponent = 0;
6528 int is_exponent_negative = 0;
6529
Owen Taylor3473f882001-02-23 17:55:21 +00006530 while (IS_BLANK(*cur)) cur++;
6531 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6532 return(xmlXPathNAN);
6533 }
6534 if (*cur == '-') {
6535 isneg = 1;
6536 cur++;
6537 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006538 /*
6539 * tmp is a workaroudn against a gcc compiler bug
6540 */
Owen Taylor3473f882001-02-23 17:55:21 +00006541 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006542 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006543 ok = 1;
6544 cur++;
6545 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006546 ret = (double) tmp;
6547
Owen Taylor3473f882001-02-23 17:55:21 +00006548 if (*cur == '.') {
6549 cur++;
6550 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6551 return(xmlXPathNAN);
6552 }
6553 while ((*cur >= '0') && (*cur <= '9')) {
6554 mult /= 10;
6555 ret = ret + (*cur - '0') * mult;
6556 cur++;
6557 }
6558 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006559 if ((*cur == 'e') || (*cur == 'E')) {
6560 cur++;
6561 if (*cur == '-') {
6562 is_exponent_negative = 1;
6563 cur++;
6564 }
6565 while ((*cur >= '0') && (*cur <= '9')) {
6566 exponent = exponent * 10 + (*cur - '0');
6567 cur++;
6568 }
6569 }
Owen Taylor3473f882001-02-23 17:55:21 +00006570 while (IS_BLANK(*cur)) cur++;
6571 if (*cur != 0) return(xmlXPathNAN);
6572 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006573 if (is_exponent_negative) exponent = -exponent;
6574 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006575 return(ret);
6576}
6577
6578/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006579 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006580 * @ctxt: the XPath Parser context
6581 *
6582 * [30] Number ::= Digits ('.' Digits?)?
6583 * | '.' Digits
6584 * [31] Digits ::= [0-9]+
6585 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006586 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006587 *
6588 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006589static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006590xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6591{
Owen Taylor3473f882001-02-23 17:55:21 +00006592 double ret = 0.0;
6593 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006594 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006595 int exponent = 0;
6596 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006597
6598 CHECK_ERROR;
6599 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6600 XP_ERROR(XPATH_NUMBER_ERROR);
6601 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006602 /*
6603 * Try to work around a gcc optimizer bug
6604 */
Owen Taylor3473f882001-02-23 17:55:21 +00006605 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006606 tmp = tmp * 10 + (CUR - '0');
6607 ok = 1;
6608 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006609 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006610 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006611 if (CUR == '.') {
6612 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006613 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6614 XP_ERROR(XPATH_NUMBER_ERROR);
6615 }
6616 while ((CUR >= '0') && (CUR <= '9')) {
6617 mult /= 10;
6618 ret = ret + (CUR - '0') * mult;
6619 NEXT;
6620 }
Owen Taylor3473f882001-02-23 17:55:21 +00006621 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006622 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006623 NEXT;
6624 if (CUR == '-') {
6625 is_exponent_negative = 1;
6626 NEXT;
6627 }
6628 while ((CUR >= '0') && (CUR <= '9')) {
6629 exponent = exponent * 10 + (CUR - '0');
6630 NEXT;
6631 }
6632 if (is_exponent_negative)
6633 exponent = -exponent;
6634 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006635 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006636 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006637 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006638}
6639
6640/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006641 * xmlXPathParseLiteral:
6642 * @ctxt: the XPath Parser context
6643 *
6644 * Parse a Literal
6645 *
6646 * [29] Literal ::= '"' [^"]* '"'
6647 * | "'" [^']* "'"
6648 *
6649 * Returns the value found or NULL in case of error
6650 */
6651static xmlChar *
6652xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6653 const xmlChar *q;
6654 xmlChar *ret = NULL;
6655
6656 if (CUR == '"') {
6657 NEXT;
6658 q = CUR_PTR;
6659 while ((IS_CHAR(CUR)) && (CUR != '"'))
6660 NEXT;
6661 if (!IS_CHAR(CUR)) {
6662 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6663 } else {
6664 ret = xmlStrndup(q, CUR_PTR - q);
6665 NEXT;
6666 }
6667 } else if (CUR == '\'') {
6668 NEXT;
6669 q = CUR_PTR;
6670 while ((IS_CHAR(CUR)) && (CUR != '\''))
6671 NEXT;
6672 if (!IS_CHAR(CUR)) {
6673 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6674 } else {
6675 ret = xmlStrndup(q, CUR_PTR - q);
6676 NEXT;
6677 }
6678 } else {
6679 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6680 }
6681 return(ret);
6682}
6683
6684/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006685 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006686 * @ctxt: the XPath Parser context
6687 *
6688 * Parse a Literal and push it on the stack.
6689 *
6690 * [29] Literal ::= '"' [^"]* '"'
6691 * | "'" [^']* "'"
6692 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006693 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006694 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006695static void
6696xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006697 const xmlChar *q;
6698 xmlChar *ret = NULL;
6699
6700 if (CUR == '"') {
6701 NEXT;
6702 q = CUR_PTR;
6703 while ((IS_CHAR(CUR)) && (CUR != '"'))
6704 NEXT;
6705 if (!IS_CHAR(CUR)) {
6706 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6707 } else {
6708 ret = xmlStrndup(q, CUR_PTR - q);
6709 NEXT;
6710 }
6711 } else if (CUR == '\'') {
6712 NEXT;
6713 q = CUR_PTR;
6714 while ((IS_CHAR(CUR)) && (CUR != '\''))
6715 NEXT;
6716 if (!IS_CHAR(CUR)) {
6717 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6718 } else {
6719 ret = xmlStrndup(q, CUR_PTR - q);
6720 NEXT;
6721 }
6722 } else {
6723 XP_ERROR(XPATH_START_LITERAL_ERROR);
6724 }
6725 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006726 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6727 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006728 xmlFree(ret);
6729}
6730
6731/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006732 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006733 * @ctxt: the XPath Parser context
6734 *
6735 * Parse a VariableReference, evaluate it and push it on the stack.
6736 *
6737 * The variable bindings consist of a mapping from variable names
6738 * to variable values. The value of a variable is an object, which
6739 * of any of the types that are possible for the value of an expression,
6740 * and may also be of additional types not specified here.
6741 *
6742 * Early evaluation is possible since:
6743 * The variable bindings [...] used to evaluate a subexpression are
6744 * always the same as those used to evaluate the containing expression.
6745 *
6746 * [36] VariableReference ::= '$' QName
6747 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006748static void
6749xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006750 xmlChar *name;
6751 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006752
6753 SKIP_BLANKS;
6754 if (CUR != '$') {
6755 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6756 }
6757 NEXT;
6758 name = xmlXPathParseQName(ctxt, &prefix);
6759 if (name == NULL) {
6760 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6761 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006762 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006763 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6764 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006765 SKIP_BLANKS;
6766}
6767
6768/**
6769 * xmlXPathIsNodeType:
6770 * @ctxt: the XPath Parser context
6771 * @name: a name string
6772 *
6773 * Is the name given a NodeType one.
6774 *
6775 * [38] NodeType ::= 'comment'
6776 * | 'text'
6777 * | 'processing-instruction'
6778 * | 'node'
6779 *
6780 * Returns 1 if true 0 otherwise
6781 */
6782int
6783xmlXPathIsNodeType(const xmlChar *name) {
6784 if (name == NULL)
6785 return(0);
6786
6787 if (xmlStrEqual(name, BAD_CAST "comment"))
6788 return(1);
6789 if (xmlStrEqual(name, BAD_CAST "text"))
6790 return(1);
6791 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6792 return(1);
6793 if (xmlStrEqual(name, BAD_CAST "node"))
6794 return(1);
6795 return(0);
6796}
6797
6798/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006799 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006800 * @ctxt: the XPath Parser context
6801 *
6802 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6803 * [17] Argument ::= Expr
6804 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006805 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006806 * pushed on the stack
6807 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006808static void
6809xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006810 xmlChar *name;
6811 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006812 int nbargs = 0;
6813
6814 name = xmlXPathParseQName(ctxt, &prefix);
6815 if (name == NULL) {
6816 XP_ERROR(XPATH_EXPR_ERROR);
6817 }
6818 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006819#ifdef DEBUG_EXPR
6820 if (prefix == NULL)
6821 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6822 name);
6823 else
6824 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6825 prefix, name);
6826#endif
6827
Owen Taylor3473f882001-02-23 17:55:21 +00006828 if (CUR != '(') {
6829 XP_ERROR(XPATH_EXPR_ERROR);
6830 }
6831 NEXT;
6832 SKIP_BLANKS;
6833
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006834 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006835 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006836 int op1 = ctxt->comp->last;
6837 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006838 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006839 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006840 nbargs++;
6841 if (CUR == ')') break;
6842 if (CUR != ',') {
6843 XP_ERROR(XPATH_EXPR_ERROR);
6844 }
6845 NEXT;
6846 SKIP_BLANKS;
6847 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006848 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6849 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006850 NEXT;
6851 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006852}
6853
6854/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006855 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006856 * @ctxt: the XPath Parser context
6857 *
6858 * [15] PrimaryExpr ::= VariableReference
6859 * | '(' Expr ')'
6860 * | Literal
6861 * | Number
6862 * | FunctionCall
6863 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006864 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006865 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006866static void
6867xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006868 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006869 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006870 else if (CUR == '(') {
6871 NEXT;
6872 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006873 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006874 if (CUR != ')') {
6875 XP_ERROR(XPATH_EXPR_ERROR);
6876 }
6877 NEXT;
6878 SKIP_BLANKS;
6879 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006880 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006881 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006882 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006883 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006884 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006885 }
6886 SKIP_BLANKS;
6887}
6888
6889/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006890 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006891 * @ctxt: the XPath Parser context
6892 *
6893 * [20] FilterExpr ::= PrimaryExpr
6894 * | FilterExpr Predicate
6895 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006896 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006897 * Square brackets are used to filter expressions in the same way that
6898 * they are used in location paths. It is an error if the expression to
6899 * be filtered does not evaluate to a node-set. The context node list
6900 * used for evaluating the expression in square brackets is the node-set
6901 * to be filtered listed in document order.
6902 */
6903
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006904static void
6905xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6906 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006907 CHECK_ERROR;
6908 SKIP_BLANKS;
6909
6910 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006911 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006912 SKIP_BLANKS;
6913 }
6914
6915
6916}
6917
6918/**
6919 * xmlXPathScanName:
6920 * @ctxt: the XPath Parser context
6921 *
6922 * Trickery: parse an XML name but without consuming the input flow
6923 * Needed to avoid insanity in the parser state.
6924 *
6925 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6926 * CombiningChar | Extender
6927 *
6928 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6929 *
6930 * [6] Names ::= Name (S Name)*
6931 *
6932 * Returns the Name parsed or NULL
6933 */
6934
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006935static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006936xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6937 xmlChar buf[XML_MAX_NAMELEN];
6938 int len = 0;
6939
6940 SKIP_BLANKS;
6941 if (!IS_LETTER(CUR) && (CUR != '_') &&
6942 (CUR != ':')) {
6943 return(NULL);
6944 }
6945
6946 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6947 (NXT(len) == '.') || (NXT(len) == '-') ||
6948 (NXT(len) == '_') || (NXT(len) == ':') ||
6949 (IS_COMBINING(NXT(len))) ||
6950 (IS_EXTENDER(NXT(len)))) {
6951 buf[len] = NXT(len);
6952 len++;
6953 if (len >= XML_MAX_NAMELEN) {
6954 xmlGenericError(xmlGenericErrorContext,
6955 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6956 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6957 (NXT(len) == '.') || (NXT(len) == '-') ||
6958 (NXT(len) == '_') || (NXT(len) == ':') ||
6959 (IS_COMBINING(NXT(len))) ||
6960 (IS_EXTENDER(NXT(len))))
6961 len++;
6962 break;
6963 }
6964 }
6965 return(xmlStrndup(buf, len));
6966}
6967
6968/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006969 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006970 * @ctxt: the XPath Parser context
6971 *
6972 * [19] PathExpr ::= LocationPath
6973 * | FilterExpr
6974 * | FilterExpr '/' RelativeLocationPath
6975 * | FilterExpr '//' RelativeLocationPath
6976 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006977 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006978 * The / operator and // operators combine an arbitrary expression
6979 * and a relative location path. It is an error if the expression
6980 * does not evaluate to a node-set.
6981 * The / operator does composition in the same way as when / is
6982 * used in a location path. As in location paths, // is short for
6983 * /descendant-or-self::node()/.
6984 */
6985
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006986static void
6987xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006988 int lc = 1; /* Should we branch to LocationPath ? */
6989 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6990
6991 SKIP_BLANKS;
6992 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6993 (CUR == '\'') || (CUR == '"')) {
6994 lc = 0;
6995 } else if (CUR == '*') {
6996 /* relative or absolute location path */
6997 lc = 1;
6998 } else if (CUR == '/') {
6999 /* relative or absolute location path */
7000 lc = 1;
7001 } else if (CUR == '@') {
7002 /* relative abbreviated attribute location path */
7003 lc = 1;
7004 } else if (CUR == '.') {
7005 /* relative abbreviated attribute location path */
7006 lc = 1;
7007 } else {
7008 /*
7009 * Problem is finding if we have a name here whether it's:
7010 * - a nodetype
7011 * - a function call in which case it's followed by '('
7012 * - an axis in which case it's followed by ':'
7013 * - a element name
7014 * We do an a priori analysis here rather than having to
7015 * maintain parsed token content through the recursive function
7016 * calls. This looks uglier but makes the code quite easier to
7017 * read/write/debug.
7018 */
7019 SKIP_BLANKS;
7020 name = xmlXPathScanName(ctxt);
7021 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7022#ifdef DEBUG_STEP
7023 xmlGenericError(xmlGenericErrorContext,
7024 "PathExpr: Axis\n");
7025#endif
7026 lc = 1;
7027 xmlFree(name);
7028 } else if (name != NULL) {
7029 int len =xmlStrlen(name);
7030 int blank = 0;
7031
7032
7033 while (NXT(len) != 0) {
7034 if (NXT(len) == '/') {
7035 /* element name */
7036#ifdef DEBUG_STEP
7037 xmlGenericError(xmlGenericErrorContext,
7038 "PathExpr: AbbrRelLocation\n");
7039#endif
7040 lc = 1;
7041 break;
7042 } else if (IS_BLANK(NXT(len))) {
7043 /* skip to next */
7044 blank = 1;
7045 } else if (NXT(len) == ':') {
7046#ifdef DEBUG_STEP
7047 xmlGenericError(xmlGenericErrorContext,
7048 "PathExpr: AbbrRelLocation\n");
7049#endif
7050 lc = 1;
7051 break;
7052 } else if ((NXT(len) == '(')) {
7053 /* Note Type or Function */
7054 if (xmlXPathIsNodeType(name)) {
7055#ifdef DEBUG_STEP
7056 xmlGenericError(xmlGenericErrorContext,
7057 "PathExpr: Type search\n");
7058#endif
7059 lc = 1;
7060 } else {
7061#ifdef DEBUG_STEP
7062 xmlGenericError(xmlGenericErrorContext,
7063 "PathExpr: function call\n");
7064#endif
7065 lc = 0;
7066 }
7067 break;
7068 } else if ((NXT(len) == '[')) {
7069 /* element name */
7070#ifdef DEBUG_STEP
7071 xmlGenericError(xmlGenericErrorContext,
7072 "PathExpr: AbbrRelLocation\n");
7073#endif
7074 lc = 1;
7075 break;
7076 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7077 (NXT(len) == '=')) {
7078 lc = 1;
7079 break;
7080 } else {
7081 lc = 1;
7082 break;
7083 }
7084 len++;
7085 }
7086 if (NXT(len) == 0) {
7087#ifdef DEBUG_STEP
7088 xmlGenericError(xmlGenericErrorContext,
7089 "PathExpr: AbbrRelLocation\n");
7090#endif
7091 /* element name */
7092 lc = 1;
7093 }
7094 xmlFree(name);
7095 } else {
7096 /* make sure all cases are covered explicitely */
7097 XP_ERROR(XPATH_EXPR_ERROR);
7098 }
7099 }
7100
7101 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007102 if (CUR == '/') {
7103 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7104 } else {
7105 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007106 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007107 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007108 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007109 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007110 CHECK_ERROR;
7111 if ((CUR == '/') && (NXT(1) == '/')) {
7112 SKIP(2);
7113 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007114
7115 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7116 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7117 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7118
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007119 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007120 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007121 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007122 }
7123 }
7124 SKIP_BLANKS;
7125}
7126
7127/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007128 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007129 * @ctxt: the XPath Parser context
7130 *
7131 * [18] UnionExpr ::= PathExpr
7132 * | UnionExpr '|' PathExpr
7133 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007134 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007135 */
7136
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007137static void
7138xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7139 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007140 CHECK_ERROR;
7141 SKIP_BLANKS;
7142 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007143 int op1 = ctxt->comp->last;
7144 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007145
7146 NEXT;
7147 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007148 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007149
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007150 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7151
Owen Taylor3473f882001-02-23 17:55:21 +00007152 SKIP_BLANKS;
7153 }
Owen Taylor3473f882001-02-23 17:55:21 +00007154}
7155
7156/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007157 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007158 * @ctxt: the XPath Parser context
7159 *
7160 * [27] UnaryExpr ::= UnionExpr
7161 * | '-' UnaryExpr
7162 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007163 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007164 */
7165
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007166static void
7167xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007168 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007169 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007170
7171 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007172 while (CUR == '-') {
7173 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007174 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007175 NEXT;
7176 SKIP_BLANKS;
7177 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007178
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007179 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007180 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007181 if (found) {
7182 if (minus)
7183 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7184 else
7185 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007186 }
7187}
7188
7189/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007190 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007191 * @ctxt: the XPath Parser context
7192 *
7193 * [26] MultiplicativeExpr ::= UnaryExpr
7194 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7195 * | MultiplicativeExpr 'div' UnaryExpr
7196 * | MultiplicativeExpr 'mod' UnaryExpr
7197 * [34] MultiplyOperator ::= '*'
7198 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007199 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007200 */
7201
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007202static void
7203xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7204 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007205 CHECK_ERROR;
7206 SKIP_BLANKS;
7207 while ((CUR == '*') ||
7208 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7209 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7210 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007211 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007212
7213 if (CUR == '*') {
7214 op = 0;
7215 NEXT;
7216 } else if (CUR == 'd') {
7217 op = 1;
7218 SKIP(3);
7219 } else if (CUR == 'm') {
7220 op = 2;
7221 SKIP(3);
7222 }
7223 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007224 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007225 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007226 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007227 SKIP_BLANKS;
7228 }
7229}
7230
7231/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007232 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007233 * @ctxt: the XPath Parser context
7234 *
7235 * [25] AdditiveExpr ::= MultiplicativeExpr
7236 * | AdditiveExpr '+' MultiplicativeExpr
7237 * | AdditiveExpr '-' MultiplicativeExpr
7238 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007239 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007240 */
7241
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007242static void
7243xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007244
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007245 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007246 CHECK_ERROR;
7247 SKIP_BLANKS;
7248 while ((CUR == '+') || (CUR == '-')) {
7249 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007250 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007251
7252 if (CUR == '+') plus = 1;
7253 else plus = 0;
7254 NEXT;
7255 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007256 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007257 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007258 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007259 SKIP_BLANKS;
7260 }
7261}
7262
7263/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007264 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007265 * @ctxt: the XPath Parser context
7266 *
7267 * [24] RelationalExpr ::= AdditiveExpr
7268 * | RelationalExpr '<' AdditiveExpr
7269 * | RelationalExpr '>' AdditiveExpr
7270 * | RelationalExpr '<=' AdditiveExpr
7271 * | RelationalExpr '>=' AdditiveExpr
7272 *
7273 * A <= B > C is allowed ? Answer from James, yes with
7274 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7275 * which is basically what got implemented.
7276 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007277 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007278 * on the stack
7279 */
7280
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007281static void
7282xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7283 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007284 CHECK_ERROR;
7285 SKIP_BLANKS;
7286 while ((CUR == '<') ||
7287 (CUR == '>') ||
7288 ((CUR == '<') && (NXT(1) == '=')) ||
7289 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007290 int inf, strict;
7291 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007292
7293 if (CUR == '<') inf = 1;
7294 else inf = 0;
7295 if (NXT(1) == '=') strict = 0;
7296 else strict = 1;
7297 NEXT;
7298 if (!strict) NEXT;
7299 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007300 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007301 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007302 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007303 SKIP_BLANKS;
7304 }
7305}
7306
7307/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007308 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007309 * @ctxt: the XPath Parser context
7310 *
7311 * [23] EqualityExpr ::= RelationalExpr
7312 * | EqualityExpr '=' RelationalExpr
7313 * | EqualityExpr '!=' RelationalExpr
7314 *
7315 * A != B != C is allowed ? Answer from James, yes with
7316 * (RelationalExpr = RelationalExpr) = RelationalExpr
7317 * (RelationalExpr != RelationalExpr) != RelationalExpr
7318 * which is basically what got implemented.
7319 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007320 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007321 *
7322 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007323static void
7324xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7325 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007326 CHECK_ERROR;
7327 SKIP_BLANKS;
7328 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007329 int eq;
7330 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007331
7332 if (CUR == '=') eq = 1;
7333 else eq = 0;
7334 NEXT;
7335 if (!eq) NEXT;
7336 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007337 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007338 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007339 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007340 SKIP_BLANKS;
7341 }
7342}
7343
7344/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007345 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007346 * @ctxt: the XPath Parser context
7347 *
7348 * [22] AndExpr ::= EqualityExpr
7349 * | AndExpr 'and' EqualityExpr
7350 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007351 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007352 *
7353 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007354static void
7355xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7356 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007357 CHECK_ERROR;
7358 SKIP_BLANKS;
7359 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007360 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007361 SKIP(3);
7362 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007363 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007364 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007365 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007366 SKIP_BLANKS;
7367 }
7368}
7369
7370/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007371 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007372 * @ctxt: the XPath Parser context
7373 *
7374 * [14] Expr ::= OrExpr
7375 * [21] OrExpr ::= AndExpr
7376 * | OrExpr 'or' AndExpr
7377 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007378 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007379 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007380static void
7381xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7382 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007383 CHECK_ERROR;
7384 SKIP_BLANKS;
7385 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007386 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007387 SKIP(2);
7388 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007389 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007390 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007391 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7392 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007393 SKIP_BLANKS;
7394 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007395 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7396 /* more ops could be optimized too */
7397 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7398 }
Owen Taylor3473f882001-02-23 17:55:21 +00007399}
7400
7401/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007402 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007403 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007404 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007405 *
7406 * [8] Predicate ::= '[' PredicateExpr ']'
7407 * [9] PredicateExpr ::= Expr
7408 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007409 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007410 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007411static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007412xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007413 int op1 = ctxt->comp->last;
7414
7415 SKIP_BLANKS;
7416 if (CUR != '[') {
7417 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7418 }
7419 NEXT;
7420 SKIP_BLANKS;
7421
7422 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007423 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007424 CHECK_ERROR;
7425
7426 if (CUR != ']') {
7427 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7428 }
7429
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007430 if (filter)
7431 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7432 else
7433 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007434
7435 NEXT;
7436 SKIP_BLANKS;
7437}
7438
7439/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007440 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007441 * @ctxt: the XPath Parser context
7442 * @test: pointer to a xmlXPathTestVal
7443 * @type: pointer to a xmlXPathTypeVal
7444 * @prefix: placeholder for a possible name prefix
7445 *
7446 * [7] NodeTest ::= NameTest
7447 * | NodeType '(' ')'
7448 * | 'processing-instruction' '(' Literal ')'
7449 *
7450 * [37] NameTest ::= '*'
7451 * | NCName ':' '*'
7452 * | QName
7453 * [38] NodeType ::= 'comment'
7454 * | 'text'
7455 * | 'processing-instruction'
7456 * | 'node'
7457 *
7458 * Returns the name found and update @test, @type and @prefix appropriately
7459 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007460static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007461xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7462 xmlXPathTypeVal *type, const xmlChar **prefix,
7463 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007464 int blanks;
7465
7466 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7467 STRANGE;
7468 return(NULL);
7469 }
7470 *type = 0;
7471 *test = 0;
7472 *prefix = NULL;
7473 SKIP_BLANKS;
7474
7475 if ((name == NULL) && (CUR == '*')) {
7476 /*
7477 * All elements
7478 */
7479 NEXT;
7480 *test = NODE_TEST_ALL;
7481 return(NULL);
7482 }
7483
7484 if (name == NULL)
7485 name = xmlXPathParseNCName(ctxt);
7486 if (name == NULL) {
7487 XP_ERROR0(XPATH_EXPR_ERROR);
7488 }
7489
7490 blanks = IS_BLANK(CUR);
7491 SKIP_BLANKS;
7492 if (CUR == '(') {
7493 NEXT;
7494 /*
7495 * NodeType or PI search
7496 */
7497 if (xmlStrEqual(name, BAD_CAST "comment"))
7498 *type = NODE_TYPE_COMMENT;
7499 else if (xmlStrEqual(name, BAD_CAST "node"))
7500 *type = NODE_TYPE_NODE;
7501 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7502 *type = NODE_TYPE_PI;
7503 else if (xmlStrEqual(name, BAD_CAST "text"))
7504 *type = NODE_TYPE_TEXT;
7505 else {
7506 if (name != NULL)
7507 xmlFree(name);
7508 XP_ERROR0(XPATH_EXPR_ERROR);
7509 }
7510
7511 *test = NODE_TEST_TYPE;
7512
7513 SKIP_BLANKS;
7514 if (*type == NODE_TYPE_PI) {
7515 /*
7516 * Specific case: search a PI by name.
7517 */
Owen Taylor3473f882001-02-23 17:55:21 +00007518 if (name != NULL)
7519 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007520 name = NULL;
7521 if (CUR != ')') {
7522 name = xmlXPathParseLiteral(ctxt);
7523 CHECK_ERROR 0;
7524 SKIP_BLANKS;
7525 }
Owen Taylor3473f882001-02-23 17:55:21 +00007526 }
7527 if (CUR != ')') {
7528 if (name != NULL)
7529 xmlFree(name);
7530 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7531 }
7532 NEXT;
7533 return(name);
7534 }
7535 *test = NODE_TEST_NAME;
7536 if ((!blanks) && (CUR == ':')) {
7537 NEXT;
7538
7539 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007540 * Since currently the parser context don't have a
7541 * namespace list associated:
7542 * The namespace name for this prefix can be computed
7543 * only at evaluation time. The compilation is done
7544 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007545 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007546#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007547 *prefix = xmlXPathNsLookup(ctxt->context, name);
7548 if (name != NULL)
7549 xmlFree(name);
7550 if (*prefix == NULL) {
7551 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7552 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007553#else
7554 *prefix = name;
7555#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007556
7557 if (CUR == '*') {
7558 /*
7559 * All elements
7560 */
7561 NEXT;
7562 *test = NODE_TEST_ALL;
7563 return(NULL);
7564 }
7565
7566 name = xmlXPathParseNCName(ctxt);
7567 if (name == NULL) {
7568 XP_ERROR0(XPATH_EXPR_ERROR);
7569 }
7570 }
7571 return(name);
7572}
7573
7574/**
7575 * xmlXPathIsAxisName:
7576 * @name: a preparsed name token
7577 *
7578 * [6] AxisName ::= 'ancestor'
7579 * | 'ancestor-or-self'
7580 * | 'attribute'
7581 * | 'child'
7582 * | 'descendant'
7583 * | 'descendant-or-self'
7584 * | 'following'
7585 * | 'following-sibling'
7586 * | 'namespace'
7587 * | 'parent'
7588 * | 'preceding'
7589 * | 'preceding-sibling'
7590 * | 'self'
7591 *
7592 * Returns the axis or 0
7593 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007594static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007595xmlXPathIsAxisName(const xmlChar *name) {
7596 xmlXPathAxisVal ret = 0;
7597 switch (name[0]) {
7598 case 'a':
7599 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7600 ret = AXIS_ANCESTOR;
7601 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7602 ret = AXIS_ANCESTOR_OR_SELF;
7603 if (xmlStrEqual(name, BAD_CAST "attribute"))
7604 ret = AXIS_ATTRIBUTE;
7605 break;
7606 case 'c':
7607 if (xmlStrEqual(name, BAD_CAST "child"))
7608 ret = AXIS_CHILD;
7609 break;
7610 case 'd':
7611 if (xmlStrEqual(name, BAD_CAST "descendant"))
7612 ret = AXIS_DESCENDANT;
7613 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7614 ret = AXIS_DESCENDANT_OR_SELF;
7615 break;
7616 case 'f':
7617 if (xmlStrEqual(name, BAD_CAST "following"))
7618 ret = AXIS_FOLLOWING;
7619 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7620 ret = AXIS_FOLLOWING_SIBLING;
7621 break;
7622 case 'n':
7623 if (xmlStrEqual(name, BAD_CAST "namespace"))
7624 ret = AXIS_NAMESPACE;
7625 break;
7626 case 'p':
7627 if (xmlStrEqual(name, BAD_CAST "parent"))
7628 ret = AXIS_PARENT;
7629 if (xmlStrEqual(name, BAD_CAST "preceding"))
7630 ret = AXIS_PRECEDING;
7631 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7632 ret = AXIS_PRECEDING_SIBLING;
7633 break;
7634 case 's':
7635 if (xmlStrEqual(name, BAD_CAST "self"))
7636 ret = AXIS_SELF;
7637 break;
7638 }
7639 return(ret);
7640}
7641
7642/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007643 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007644 * @ctxt: the XPath Parser context
7645 *
7646 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7647 * | AbbreviatedStep
7648 *
7649 * [12] AbbreviatedStep ::= '.' | '..'
7650 *
7651 * [5] AxisSpecifier ::= AxisName '::'
7652 * | AbbreviatedAxisSpecifier
7653 *
7654 * [13] AbbreviatedAxisSpecifier ::= '@'?
7655 *
7656 * Modified for XPtr range support as:
7657 *
7658 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7659 * | AbbreviatedStep
7660 * | 'range-to' '(' Expr ')' Predicate*
7661 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007662 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007663 * A location step of . is short for self::node(). This is
7664 * particularly useful in conjunction with //. For example, the
7665 * location path .//para is short for
7666 * self::node()/descendant-or-self::node()/child::para
7667 * and so will select all para descendant elements of the context
7668 * node.
7669 * Similarly, a location step of .. is short for parent::node().
7670 * For example, ../title is short for parent::node()/child::title
7671 * and so will select the title children of the parent of the context
7672 * node.
7673 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007674static void
7675xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007676#ifdef LIBXML_XPTR_ENABLED
7677 int rangeto = 0;
7678 int op2 = -1;
7679#endif
7680
Owen Taylor3473f882001-02-23 17:55:21 +00007681 SKIP_BLANKS;
7682 if ((CUR == '.') && (NXT(1) == '.')) {
7683 SKIP(2);
7684 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007685 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7686 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007687 } else if (CUR == '.') {
7688 NEXT;
7689 SKIP_BLANKS;
7690 } else {
7691 xmlChar *name = NULL;
7692 const xmlChar *prefix = NULL;
7693 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007694 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007695 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007696 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007697
7698 /*
7699 * The modification needed for XPointer change to the production
7700 */
7701#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007702 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007703 name = xmlXPathParseNCName(ctxt);
7704 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007705 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007706 xmlFree(name);
7707 SKIP_BLANKS;
7708 if (CUR != '(') {
7709 XP_ERROR(XPATH_EXPR_ERROR);
7710 }
7711 NEXT;
7712 SKIP_BLANKS;
7713
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007714 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007715 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007716 CHECK_ERROR;
7717
7718 SKIP_BLANKS;
7719 if (CUR != ')') {
7720 XP_ERROR(XPATH_EXPR_ERROR);
7721 }
7722 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007723 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007724 goto eval_predicates;
7725 }
7726 }
7727#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007728 if (CUR == '*') {
7729 axis = AXIS_CHILD;
7730 } else {
7731 if (name == NULL)
7732 name = xmlXPathParseNCName(ctxt);
7733 if (name != NULL) {
7734 axis = xmlXPathIsAxisName(name);
7735 if (axis != 0) {
7736 SKIP_BLANKS;
7737 if ((CUR == ':') && (NXT(1) == ':')) {
7738 SKIP(2);
7739 xmlFree(name);
7740 name = NULL;
7741 } else {
7742 /* an element name can conflict with an axis one :-\ */
7743 axis = AXIS_CHILD;
7744 }
Owen Taylor3473f882001-02-23 17:55:21 +00007745 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007746 axis = AXIS_CHILD;
7747 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007748 } else if (CUR == '@') {
7749 NEXT;
7750 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007751 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007752 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007753 }
Owen Taylor3473f882001-02-23 17:55:21 +00007754 }
7755
7756 CHECK_ERROR;
7757
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007758 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007759 if (test == 0)
7760 return;
7761
7762#ifdef DEBUG_STEP
7763 xmlGenericError(xmlGenericErrorContext,
7764 "Basis : computing new set\n");
7765#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007766
Owen Taylor3473f882001-02-23 17:55:21 +00007767#ifdef DEBUG_STEP
7768 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007769 if (ctxt->value == NULL)
7770 xmlGenericError(xmlGenericErrorContext, "no value\n");
7771 else if (ctxt->value->nodesetval == NULL)
7772 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7773 else
7774 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007775#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007776
7777eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007778 op1 = ctxt->comp->last;
7779 ctxt->comp->last = -1;
7780
Owen Taylor3473f882001-02-23 17:55:21 +00007781 SKIP_BLANKS;
7782 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007783 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007784 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007785
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007786#ifdef LIBXML_XPTR_ENABLED
7787 if (rangeto) {
7788 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7789 } else
7790#endif
7791 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7792 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007793
Owen Taylor3473f882001-02-23 17:55:21 +00007794 }
7795#ifdef DEBUG_STEP
7796 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007797 if (ctxt->value == NULL)
7798 xmlGenericError(xmlGenericErrorContext, "no value\n");
7799 else if (ctxt->value->nodesetval == NULL)
7800 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7801 else
7802 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7803 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007804#endif
7805}
7806
7807/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007808 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007809 * @ctxt: the XPath Parser context
7810 *
7811 * [3] RelativeLocationPath ::= Step
7812 * | RelativeLocationPath '/' Step
7813 * | AbbreviatedRelativeLocationPath
7814 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7815 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007816 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007817 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007818static void
Owen Taylor3473f882001-02-23 17:55:21 +00007819#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007820xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007821#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007822xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007823#endif
7824(xmlXPathParserContextPtr ctxt) {
7825 SKIP_BLANKS;
7826 if ((CUR == '/') && (NXT(1) == '/')) {
7827 SKIP(2);
7828 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007829 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7830 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007831 } else if (CUR == '/') {
7832 NEXT;
7833 SKIP_BLANKS;
7834 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007835 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007836 SKIP_BLANKS;
7837 while (CUR == '/') {
7838 if ((CUR == '/') && (NXT(1) == '/')) {
7839 SKIP(2);
7840 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007841 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007842 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007843 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007844 } else if (CUR == '/') {
7845 NEXT;
7846 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007847 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007848 }
7849 SKIP_BLANKS;
7850 }
7851}
7852
7853/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007854 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007855 * @ctxt: the XPath Parser context
7856 *
7857 * [1] LocationPath ::= RelativeLocationPath
7858 * | AbsoluteLocationPath
7859 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7860 * | AbbreviatedAbsoluteLocationPath
7861 * [10] AbbreviatedAbsoluteLocationPath ::=
7862 * '//' RelativeLocationPath
7863 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007864 * Compile a location path
7865 *
Owen Taylor3473f882001-02-23 17:55:21 +00007866 * // is short for /descendant-or-self::node()/. For example,
7867 * //para is short for /descendant-or-self::node()/child::para and
7868 * so will select any para element in the document (even a para element
7869 * that is a document element will be selected by //para since the
7870 * document element node is a child of the root node); div//para is
7871 * short for div/descendant-or-self::node()/child::para and so will
7872 * select all para descendants of div children.
7873 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007874static void
7875xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007876 SKIP_BLANKS;
7877 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007878 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007879 } else {
7880 while (CUR == '/') {
7881 if ((CUR == '/') && (NXT(1) == '/')) {
7882 SKIP(2);
7883 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007884 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7885 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007886 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007887 } else if (CUR == '/') {
7888 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007889 SKIP_BLANKS;
7890 if ((CUR != 0 ) &&
7891 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7892 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007893 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007894 }
7895 }
7896 }
7897}
7898
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007899/************************************************************************
7900 * *
7901 * XPath precompiled expression evaluation *
7902 * *
7903 ************************************************************************/
7904
Daniel Veillardf06307e2001-07-03 10:35:50 +00007905static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007906xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7907
7908/**
7909 * xmlXPathNodeCollectAndTest:
7910 * @ctxt: the XPath Parser context
7911 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007912 * @first: pointer to the first element in document order
7913 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007914 *
7915 * This is the function implementing a step: based on the current list
7916 * of nodes, it builds up a new list, looking at all nodes under that
7917 * axis and selecting them it also do the predicate filtering
7918 *
7919 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007920 *
7921 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007922 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007923static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007924xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007925 xmlXPathStepOpPtr op,
7926 xmlNodePtr * first, xmlNodePtr * last)
7927{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007928 xmlXPathAxisVal axis = op->value;
7929 xmlXPathTestVal test = op->value2;
7930 xmlXPathTypeVal type = op->value3;
7931 const xmlChar *prefix = op->value4;
7932 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007933 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007934
7935#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007936 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007937#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007938 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007939 xmlNodeSetPtr ret, list;
7940 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007941 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007942 xmlNodePtr cur = NULL;
7943 xmlXPathObjectPtr obj;
7944 xmlNodeSetPtr nodelist;
7945 xmlNodePtr tmp;
7946
Daniel Veillardf06307e2001-07-03 10:35:50 +00007947 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007948 obj = valuePop(ctxt);
7949 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007950 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007951 URI = xmlXPathNsLookup(ctxt->context, prefix);
7952 if (URI == NULL)
7953 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00007954 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007955#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007956 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007957#endif
7958 switch (axis) {
7959 case AXIS_ANCESTOR:
7960#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007961 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007962#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007963 first = NULL;
7964 next = xmlXPathNextAncestor;
7965 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007966 case AXIS_ANCESTOR_OR_SELF:
7967#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007968 xmlGenericError(xmlGenericErrorContext,
7969 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007970#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007971 first = NULL;
7972 next = xmlXPathNextAncestorOrSelf;
7973 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007974 case AXIS_ATTRIBUTE:
7975#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007976 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007977#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007978 first = NULL;
7979 last = NULL;
7980 next = xmlXPathNextAttribute;
7981 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007982 case AXIS_CHILD:
7983#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007984 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007985#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007986 last = NULL;
7987 next = xmlXPathNextChild;
7988 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007989 case AXIS_DESCENDANT:
7990#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007991 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007992#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007993 last = NULL;
7994 next = xmlXPathNextDescendant;
7995 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007996 case AXIS_DESCENDANT_OR_SELF:
7997#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007998 xmlGenericError(xmlGenericErrorContext,
7999 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008000#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008001 last = NULL;
8002 next = xmlXPathNextDescendantOrSelf;
8003 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008004 case AXIS_FOLLOWING:
8005#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008006 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008007#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008008 last = NULL;
8009 next = xmlXPathNextFollowing;
8010 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008011 case AXIS_FOLLOWING_SIBLING:
8012#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008013 xmlGenericError(xmlGenericErrorContext,
8014 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008015#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008016 last = NULL;
8017 next = xmlXPathNextFollowingSibling;
8018 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008019 case AXIS_NAMESPACE:
8020#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008021 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008022#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008023 first = NULL;
8024 last = NULL;
8025 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8026 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008027 case AXIS_PARENT:
8028#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008029 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008030#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008031 first = NULL;
8032 next = xmlXPathNextParent;
8033 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008034 case AXIS_PRECEDING:
8035#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008036 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008037#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008038 first = NULL;
8039 next = xmlXPathNextPrecedingInternal;
8040 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008041 case AXIS_PRECEDING_SIBLING:
8042#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008043 xmlGenericError(xmlGenericErrorContext,
8044 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008045#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008046 first = NULL;
8047 next = xmlXPathNextPrecedingSibling;
8048 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008049 case AXIS_SELF:
8050#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008051 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008052#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008053 first = NULL;
8054 last = NULL;
8055 next = xmlXPathNextSelf;
8056 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008057 }
8058 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008059 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008060
8061 nodelist = obj->nodesetval;
8062 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008063 xmlXPathFreeObject(obj);
8064 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8065 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008066 }
8067 addNode = xmlXPathNodeSetAddUnique;
8068 ret = NULL;
8069#ifdef DEBUG_STEP
8070 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008071 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008072 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008073 case NODE_TEST_NONE:
8074 xmlGenericError(xmlGenericErrorContext,
8075 " searching for none !!!\n");
8076 break;
8077 case NODE_TEST_TYPE:
8078 xmlGenericError(xmlGenericErrorContext,
8079 " searching for type %d\n", type);
8080 break;
8081 case NODE_TEST_PI:
8082 xmlGenericError(xmlGenericErrorContext,
8083 " searching for PI !!!\n");
8084 break;
8085 case NODE_TEST_ALL:
8086 xmlGenericError(xmlGenericErrorContext,
8087 " searching for *\n");
8088 break;
8089 case NODE_TEST_NS:
8090 xmlGenericError(xmlGenericErrorContext,
8091 " searching for namespace %s\n",
8092 prefix);
8093 break;
8094 case NODE_TEST_NAME:
8095 xmlGenericError(xmlGenericErrorContext,
8096 " searching for name %s\n", name);
8097 if (prefix != NULL)
8098 xmlGenericError(xmlGenericErrorContext,
8099 " with namespace %s\n", prefix);
8100 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008101 }
8102 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8103#endif
8104 /*
8105 * 2.3 Node Tests
8106 * - For the attribute axis, the principal node type is attribute.
8107 * - For the namespace axis, the principal node type is namespace.
8108 * - For other axes, the principal node type is element.
8109 *
8110 * A node test * is true for any node of the
8111 * principal node type. For example, child::* willi
8112 * select all element children of the context node
8113 */
8114 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008115 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008116 ctxt->context->node = nodelist->nodeTab[i];
8117
Daniel Veillardf06307e2001-07-03 10:35:50 +00008118 cur = NULL;
8119 list = xmlXPathNodeSetCreate(NULL);
8120 do {
8121 cur = next(ctxt, cur);
8122 if (cur == NULL)
8123 break;
8124 if ((first != NULL) && (*first == cur))
8125 break;
8126 if (((t % 256) == 0) &&
8127 (first != NULL) && (*first != NULL) &&
8128 (xmlXPathCmpNodes(*first, cur) >= 0))
8129 break;
8130 if ((last != NULL) && (*last == cur))
8131 break;
8132 if (((t % 256) == 0) &&
8133 (last != NULL) && (*last != NULL) &&
8134 (xmlXPathCmpNodes(cur, *last) >= 0))
8135 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008136 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008137#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008138 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8139#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008140 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008141 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008142 ctxt->context->node = tmp;
8143 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008144 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008145 if ((cur->type == type) ||
8146 ((type == NODE_TYPE_NODE) &&
8147 ((cur->type == XML_DOCUMENT_NODE) ||
8148 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8149 (cur->type == XML_ELEMENT_NODE) ||
8150 (cur->type == XML_PI_NODE) ||
8151 (cur->type == XML_COMMENT_NODE) ||
8152 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008153 (cur->type == XML_TEXT_NODE))) ||
8154 ((type == NODE_TYPE_TEXT) &&
8155 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008156#ifdef DEBUG_STEP
8157 n++;
8158#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008159 addNode(list, cur);
8160 }
8161 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008162 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008163 if (cur->type == XML_PI_NODE) {
8164 if ((name != NULL) &&
8165 (!xmlStrEqual(name, cur->name)))
8166 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008167#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008168 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008169#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008170 addNode(list, cur);
8171 }
8172 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008173 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008174 if (axis == AXIS_ATTRIBUTE) {
8175 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008176#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008177 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008178#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008179 addNode(list, cur);
8180 }
8181 } else if (axis == AXIS_NAMESPACE) {
8182 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008183#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008184 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008185#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008186 addNode(list, cur);
8187 }
8188 } else {
8189 if (cur->type == XML_ELEMENT_NODE) {
8190 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008191#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008192 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008193#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008194 addNode(list, cur);
8195 } else if ((cur->ns != NULL) &&
8196 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008197#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008198 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008199#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008200 addNode(list, cur);
8201 }
8202 }
8203 }
8204 break;
8205 case NODE_TEST_NS:{
8206 TODO;
8207 break;
8208 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008209 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008210 switch (cur->type) {
8211 case XML_ELEMENT_NODE:
8212 if (xmlStrEqual(name, cur->name)) {
8213 if (prefix == NULL) {
8214 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008215#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008216 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008217#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008218 addNode(list, cur);
8219 }
8220 } else {
8221 if ((cur->ns != NULL) &&
8222 (xmlStrEqual(URI,
8223 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008224#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008225 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008226#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008227 addNode(list, cur);
8228 }
8229 }
8230 }
8231 break;
8232 case XML_ATTRIBUTE_NODE:{
8233 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008234
Daniel Veillardf06307e2001-07-03 10:35:50 +00008235 if (xmlStrEqual(name, attr->name)) {
8236 if (prefix == NULL) {
8237 if ((attr->ns == NULL) ||
8238 (attr->ns->prefix == NULL)) {
8239#ifdef DEBUG_STEP
8240 n++;
8241#endif
8242 addNode(list,
8243 (xmlNodePtr) attr);
8244 }
8245 } else {
8246 if ((attr->ns != NULL) &&
8247 (xmlStrEqual(URI,
8248 attr->ns->
8249 href))) {
8250#ifdef DEBUG_STEP
8251 n++;
8252#endif
8253 addNode(list,
8254 (xmlNodePtr) attr);
8255 }
8256 }
8257 }
8258 break;
8259 }
8260 case XML_NAMESPACE_DECL:
8261 if (cur->type == XML_NAMESPACE_DECL) {
8262 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008263
Daniel Veillardf06307e2001-07-03 10:35:50 +00008264 if ((ns->prefix != NULL) && (name != NULL)
8265 && (xmlStrEqual(ns->prefix, name))) {
8266#ifdef DEBUG_STEP
8267 n++;
8268#endif
8269 addNode(list, cur);
8270 }
8271 }
8272 break;
8273 default:
8274 break;
8275 }
8276 break;
8277 break;
8278 }
8279 } while (cur != NULL);
8280
8281 /*
8282 * If there is some predicate filtering do it now
8283 */
8284 if (op->ch2 != -1) {
8285 xmlXPathObjectPtr obj2;
8286
8287 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8288 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8289 CHECK_TYPE0(XPATH_NODESET);
8290 obj2 = valuePop(ctxt);
8291 list = obj2->nodesetval;
8292 obj2->nodesetval = NULL;
8293 xmlXPathFreeObject(obj2);
8294 }
8295 if (ret == NULL) {
8296 ret = list;
8297 } else {
8298 ret = xmlXPathNodeSetMerge(ret, list);
8299 xmlXPathFreeNodeSet(list);
8300 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008301 }
8302 ctxt->context->node = tmp;
8303#ifdef DEBUG_STEP
8304 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008305 "\nExamined %d nodes, found %d nodes at that step\n",
8306 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008307#endif
8308 xmlXPathFreeObject(obj);
8309 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008310 return(t);
8311}
8312
8313/**
8314 * xmlXPathNodeCollectAndTestNth:
8315 * @ctxt: the XPath Parser context
8316 * @op: the XPath precompiled step operation
8317 * @indx: the index to collect
8318 * @first: pointer to the first element in document order
8319 * @last: pointer to the last element in document order
8320 *
8321 * This is the function implementing a step: based on the current list
8322 * of nodes, it builds up a new list, looking at all nodes under that
8323 * axis and selecting them it also do the predicate filtering
8324 *
8325 * Pushes the new NodeSet resulting from the search.
8326 * Returns the number of node traversed
8327 */
8328static int
8329xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8330 xmlXPathStepOpPtr op, int indx,
8331 xmlNodePtr * first, xmlNodePtr * last)
8332{
8333 xmlXPathAxisVal axis = op->value;
8334 xmlXPathTestVal test = op->value2;
8335 xmlXPathTypeVal type = op->value3;
8336 const xmlChar *prefix = op->value4;
8337 const xmlChar *name = op->value5;
8338 const xmlChar *URI = NULL;
8339 int n = 0, t = 0;
8340
8341 int i;
8342 xmlNodeSetPtr list;
8343 xmlXPathTraversalFunction next = NULL;
8344 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8345 xmlNodePtr cur = NULL;
8346 xmlXPathObjectPtr obj;
8347 xmlNodeSetPtr nodelist;
8348 xmlNodePtr tmp;
8349
8350 CHECK_TYPE0(XPATH_NODESET);
8351 obj = valuePop(ctxt);
8352 addNode = xmlXPathNodeSetAdd;
8353 if (prefix != NULL) {
8354 URI = xmlXPathNsLookup(ctxt->context, prefix);
8355 if (URI == NULL)
8356 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8357 }
8358#ifdef DEBUG_STEP_NTH
8359 xmlGenericError(xmlGenericErrorContext, "new step : ");
8360 if (first != NULL) {
8361 if (*first != NULL)
8362 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8363 (*first)->name);
8364 else
8365 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8366 }
8367 if (last != NULL) {
8368 if (*last != NULL)
8369 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8370 (*last)->name);
8371 else
8372 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8373 }
8374#endif
8375 switch (axis) {
8376 case AXIS_ANCESTOR:
8377#ifdef DEBUG_STEP_NTH
8378 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8379#endif
8380 first = NULL;
8381 next = xmlXPathNextAncestor;
8382 break;
8383 case AXIS_ANCESTOR_OR_SELF:
8384#ifdef DEBUG_STEP_NTH
8385 xmlGenericError(xmlGenericErrorContext,
8386 "axis 'ancestors-or-self' ");
8387#endif
8388 first = NULL;
8389 next = xmlXPathNextAncestorOrSelf;
8390 break;
8391 case AXIS_ATTRIBUTE:
8392#ifdef DEBUG_STEP_NTH
8393 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8394#endif
8395 first = NULL;
8396 last = NULL;
8397 next = xmlXPathNextAttribute;
8398 break;
8399 case AXIS_CHILD:
8400#ifdef DEBUG_STEP_NTH
8401 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8402#endif
8403 last = NULL;
8404 next = xmlXPathNextChild;
8405 break;
8406 case AXIS_DESCENDANT:
8407#ifdef DEBUG_STEP_NTH
8408 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8409#endif
8410 last = NULL;
8411 next = xmlXPathNextDescendant;
8412 break;
8413 case AXIS_DESCENDANT_OR_SELF:
8414#ifdef DEBUG_STEP_NTH
8415 xmlGenericError(xmlGenericErrorContext,
8416 "axis 'descendant-or-self' ");
8417#endif
8418 last = NULL;
8419 next = xmlXPathNextDescendantOrSelf;
8420 break;
8421 case AXIS_FOLLOWING:
8422#ifdef DEBUG_STEP_NTH
8423 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8424#endif
8425 last = NULL;
8426 next = xmlXPathNextFollowing;
8427 break;
8428 case AXIS_FOLLOWING_SIBLING:
8429#ifdef DEBUG_STEP_NTH
8430 xmlGenericError(xmlGenericErrorContext,
8431 "axis 'following-siblings' ");
8432#endif
8433 last = NULL;
8434 next = xmlXPathNextFollowingSibling;
8435 break;
8436 case AXIS_NAMESPACE:
8437#ifdef DEBUG_STEP_NTH
8438 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8439#endif
8440 last = NULL;
8441 first = NULL;
8442 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8443 break;
8444 case AXIS_PARENT:
8445#ifdef DEBUG_STEP_NTH
8446 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8447#endif
8448 first = NULL;
8449 next = xmlXPathNextParent;
8450 break;
8451 case AXIS_PRECEDING:
8452#ifdef DEBUG_STEP_NTH
8453 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8454#endif
8455 first = NULL;
8456 next = xmlXPathNextPrecedingInternal;
8457 break;
8458 case AXIS_PRECEDING_SIBLING:
8459#ifdef DEBUG_STEP_NTH
8460 xmlGenericError(xmlGenericErrorContext,
8461 "axis 'preceding-sibling' ");
8462#endif
8463 first = NULL;
8464 next = xmlXPathNextPrecedingSibling;
8465 break;
8466 case AXIS_SELF:
8467#ifdef DEBUG_STEP_NTH
8468 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8469#endif
8470 first = NULL;
8471 last = NULL;
8472 next = xmlXPathNextSelf;
8473 break;
8474 }
8475 if (next == NULL)
8476 return(0);
8477
8478 nodelist = obj->nodesetval;
8479 if (nodelist == NULL) {
8480 xmlXPathFreeObject(obj);
8481 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8482 return(0);
8483 }
8484 addNode = xmlXPathNodeSetAddUnique;
8485#ifdef DEBUG_STEP_NTH
8486 xmlGenericError(xmlGenericErrorContext,
8487 " context contains %d nodes\n", nodelist->nodeNr);
8488 switch (test) {
8489 case NODE_TEST_NONE:
8490 xmlGenericError(xmlGenericErrorContext,
8491 " searching for none !!!\n");
8492 break;
8493 case NODE_TEST_TYPE:
8494 xmlGenericError(xmlGenericErrorContext,
8495 " searching for type %d\n", type);
8496 break;
8497 case NODE_TEST_PI:
8498 xmlGenericError(xmlGenericErrorContext,
8499 " searching for PI !!!\n");
8500 break;
8501 case NODE_TEST_ALL:
8502 xmlGenericError(xmlGenericErrorContext,
8503 " searching for *\n");
8504 break;
8505 case NODE_TEST_NS:
8506 xmlGenericError(xmlGenericErrorContext,
8507 " searching for namespace %s\n",
8508 prefix);
8509 break;
8510 case NODE_TEST_NAME:
8511 xmlGenericError(xmlGenericErrorContext,
8512 " searching for name %s\n", name);
8513 if (prefix != NULL)
8514 xmlGenericError(xmlGenericErrorContext,
8515 " with namespace %s\n", prefix);
8516 break;
8517 }
8518 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8519#endif
8520 /*
8521 * 2.3 Node Tests
8522 * - For the attribute axis, the principal node type is attribute.
8523 * - For the namespace axis, the principal node type is namespace.
8524 * - For other axes, the principal node type is element.
8525 *
8526 * A node test * is true for any node of the
8527 * principal node type. For example, child::* willi
8528 * select all element children of the context node
8529 */
8530 tmp = ctxt->context->node;
8531 list = xmlXPathNodeSetCreate(NULL);
8532 for (i = 0; i < nodelist->nodeNr; i++) {
8533 ctxt->context->node = nodelist->nodeTab[i];
8534
8535 cur = NULL;
8536 n = 0;
8537 do {
8538 cur = next(ctxt, cur);
8539 if (cur == NULL)
8540 break;
8541 if ((first != NULL) && (*first == cur))
8542 break;
8543 if (((t % 256) == 0) &&
8544 (first != NULL) && (*first != NULL) &&
8545 (xmlXPathCmpNodes(*first, cur) >= 0))
8546 break;
8547 if ((last != NULL) && (*last == cur))
8548 break;
8549 if (((t % 256) == 0) &&
8550 (last != NULL) && (*last != NULL) &&
8551 (xmlXPathCmpNodes(cur, *last) >= 0))
8552 break;
8553 t++;
8554 switch (test) {
8555 case NODE_TEST_NONE:
8556 ctxt->context->node = tmp;
8557 STRANGE return(0);
8558 case NODE_TEST_TYPE:
8559 if ((cur->type == type) ||
8560 ((type == NODE_TYPE_NODE) &&
8561 ((cur->type == XML_DOCUMENT_NODE) ||
8562 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8563 (cur->type == XML_ELEMENT_NODE) ||
8564 (cur->type == XML_PI_NODE) ||
8565 (cur->type == XML_COMMENT_NODE) ||
8566 (cur->type == XML_CDATA_SECTION_NODE) ||
8567 (cur->type == XML_TEXT_NODE)))) {
8568 n++;
8569 if (n == indx)
8570 addNode(list, cur);
8571 }
8572 break;
8573 case NODE_TEST_PI:
8574 if (cur->type == XML_PI_NODE) {
8575 if ((name != NULL) &&
8576 (!xmlStrEqual(name, cur->name)))
8577 break;
8578 n++;
8579 if (n == indx)
8580 addNode(list, cur);
8581 }
8582 break;
8583 case NODE_TEST_ALL:
8584 if (axis == AXIS_ATTRIBUTE) {
8585 if (cur->type == XML_ATTRIBUTE_NODE) {
8586 n++;
8587 if (n == indx)
8588 addNode(list, cur);
8589 }
8590 } else if (axis == AXIS_NAMESPACE) {
8591 if (cur->type == XML_NAMESPACE_DECL) {
8592 n++;
8593 if (n == indx)
8594 addNode(list, cur);
8595 }
8596 } else {
8597 if (cur->type == XML_ELEMENT_NODE) {
8598 if (prefix == NULL) {
8599 n++;
8600 if (n == indx)
8601 addNode(list, cur);
8602 } else if ((cur->ns != NULL) &&
8603 (xmlStrEqual(URI, cur->ns->href))) {
8604 n++;
8605 if (n == indx)
8606 addNode(list, cur);
8607 }
8608 }
8609 }
8610 break;
8611 case NODE_TEST_NS:{
8612 TODO;
8613 break;
8614 }
8615 case NODE_TEST_NAME:
8616 switch (cur->type) {
8617 case XML_ELEMENT_NODE:
8618 if (xmlStrEqual(name, cur->name)) {
8619 if (prefix == NULL) {
8620 if (cur->ns == NULL) {
8621 n++;
8622 if (n == indx)
8623 addNode(list, cur);
8624 }
8625 } else {
8626 if ((cur->ns != NULL) &&
8627 (xmlStrEqual(URI,
8628 cur->ns->href))) {
8629 n++;
8630 if (n == indx)
8631 addNode(list, cur);
8632 }
8633 }
8634 }
8635 break;
8636 case XML_ATTRIBUTE_NODE:{
8637 xmlAttrPtr attr = (xmlAttrPtr) cur;
8638
8639 if (xmlStrEqual(name, attr->name)) {
8640 if (prefix == NULL) {
8641 if ((attr->ns == NULL) ||
8642 (attr->ns->prefix == NULL)) {
8643 n++;
8644 if (n == indx)
8645 addNode(list, cur);
8646 }
8647 } else {
8648 if ((attr->ns != NULL) &&
8649 (xmlStrEqual(URI,
8650 attr->ns->
8651 href))) {
8652 n++;
8653 if (n == indx)
8654 addNode(list, cur);
8655 }
8656 }
8657 }
8658 break;
8659 }
8660 case XML_NAMESPACE_DECL:
8661 if (cur->type == XML_NAMESPACE_DECL) {
8662 xmlNsPtr ns = (xmlNsPtr) cur;
8663
8664 if ((ns->prefix != NULL) && (name != NULL)
8665 && (xmlStrEqual(ns->prefix, name))) {
8666 n++;
8667 if (n == indx)
8668 addNode(list, cur);
8669 }
8670 }
8671 break;
8672 default:
8673 break;
8674 }
8675 break;
8676 break;
8677 }
8678 } while (n < indx);
8679 }
8680 ctxt->context->node = tmp;
8681#ifdef DEBUG_STEP_NTH
8682 xmlGenericError(xmlGenericErrorContext,
8683 "\nExamined %d nodes, found %d nodes at that step\n",
8684 t, list->nodeNr);
8685#endif
8686 xmlXPathFreeObject(obj);
8687 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8688 return(t);
8689}
8690
8691/**
8692 * xmlXPathCompOpEvalFirst:
8693 * @ctxt: the XPath parser context with the compiled expression
8694 * @op: an XPath compiled operation
8695 * @first: the first elem found so far
8696 *
8697 * Evaluate the Precompiled XPath operation searching only the first
8698 * element in document order
8699 *
8700 * Returns the number of examined objects.
8701 */
8702static int
8703xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8704 xmlXPathStepOpPtr op, xmlNodePtr * first)
8705{
8706 int total = 0, cur;
8707 xmlXPathCompExprPtr comp;
8708 xmlXPathObjectPtr arg1, arg2;
8709
8710 comp = ctxt->comp;
8711 switch (op->op) {
8712 case XPATH_OP_END:
8713 return (0);
8714 case XPATH_OP_UNION:
8715 total =
8716 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8717 first);
8718 if ((ctxt->value != NULL)
8719 && (ctxt->value->type == XPATH_NODESET)
8720 && (ctxt->value->nodesetval != NULL)
8721 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8722 /*
8723 * limit tree traversing to first node in the result
8724 */
8725 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8726 *first = ctxt->value->nodesetval->nodeTab[0];
8727 }
8728 cur =
8729 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8730 first);
8731 CHECK_TYPE0(XPATH_NODESET);
8732 arg2 = valuePop(ctxt);
8733
8734 CHECK_TYPE0(XPATH_NODESET);
8735 arg1 = valuePop(ctxt);
8736
8737 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8738 arg2->nodesetval);
8739 valuePush(ctxt, arg1);
8740 xmlXPathFreeObject(arg2);
8741 /* optimizer */
8742 if (total > cur)
8743 xmlXPathCompSwap(op);
8744 return (total + cur);
8745 case XPATH_OP_ROOT:
8746 xmlXPathRoot(ctxt);
8747 return (0);
8748 case XPATH_OP_NODE:
8749 if (op->ch1 != -1)
8750 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8751 if (op->ch2 != -1)
8752 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8753 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8754 return (total);
8755 case XPATH_OP_RESET:
8756 if (op->ch1 != -1)
8757 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8758 if (op->ch2 != -1)
8759 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8760 ctxt->context->node = NULL;
8761 return (total);
8762 case XPATH_OP_COLLECT:{
8763 if (op->ch1 == -1)
8764 return (total);
8765
8766 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8767
8768 /*
8769 * Optimization for [n] selection where n is a number
8770 */
8771 if ((op->ch2 != -1) &&
8772 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8773 (comp->steps[op->ch2].ch1 == -1) &&
8774 (comp->steps[op->ch2].ch2 != -1) &&
8775 (comp->steps[comp->steps[op->ch2].ch2].op ==
8776 XPATH_OP_VALUE)) {
8777 xmlXPathObjectPtr val;
8778
8779 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8780 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8781 int indx = (int) val->floatval;
8782
8783 if (val->floatval == (float) indx) {
8784 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8785 first, NULL);
8786 return (total);
8787 }
8788 }
8789 }
8790 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8791 return (total);
8792 }
8793 case XPATH_OP_VALUE:
8794 valuePush(ctxt,
8795 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8796 return (0);
8797 case XPATH_OP_SORT:
8798 if (op->ch1 != -1)
8799 total +=
8800 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8801 first);
8802 if ((ctxt->value != NULL)
8803 && (ctxt->value->type == XPATH_NODESET)
8804 && (ctxt->value->nodesetval != NULL))
8805 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8806 return (total);
8807 default:
8808 return (xmlXPathCompOpEval(ctxt, op));
8809 }
8810}
8811
8812/**
8813 * xmlXPathCompOpEvalLast:
8814 * @ctxt: the XPath parser context with the compiled expression
8815 * @op: an XPath compiled operation
8816 * @last: the last elem found so far
8817 *
8818 * Evaluate the Precompiled XPath operation searching only the last
8819 * element in document order
8820 *
8821 * Returns the number of node traversed
8822 */
8823static int
8824xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8825 xmlNodePtr * last)
8826{
8827 int total = 0, cur;
8828 xmlXPathCompExprPtr comp;
8829 xmlXPathObjectPtr arg1, arg2;
8830
8831 comp = ctxt->comp;
8832 switch (op->op) {
8833 case XPATH_OP_END:
8834 return (0);
8835 case XPATH_OP_UNION:
8836 total =
8837 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8838 if ((ctxt->value != NULL)
8839 && (ctxt->value->type == XPATH_NODESET)
8840 && (ctxt->value->nodesetval != NULL)
8841 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8842 /*
8843 * limit tree traversing to first node in the result
8844 */
8845 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8846 *last =
8847 ctxt->value->nodesetval->nodeTab[ctxt->value->
8848 nodesetval->nodeNr -
8849 1];
8850 }
8851 cur =
8852 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8853 if ((ctxt->value != NULL)
8854 && (ctxt->value->type == XPATH_NODESET)
8855 && (ctxt->value->nodesetval != NULL)
8856 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8857 }
8858 CHECK_TYPE0(XPATH_NODESET);
8859 arg2 = valuePop(ctxt);
8860
8861 CHECK_TYPE0(XPATH_NODESET);
8862 arg1 = valuePop(ctxt);
8863
8864 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8865 arg2->nodesetval);
8866 valuePush(ctxt, arg1);
8867 xmlXPathFreeObject(arg2);
8868 /* optimizer */
8869 if (total > cur)
8870 xmlXPathCompSwap(op);
8871 return (total + cur);
8872 case XPATH_OP_ROOT:
8873 xmlXPathRoot(ctxt);
8874 return (0);
8875 case XPATH_OP_NODE:
8876 if (op->ch1 != -1)
8877 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8878 if (op->ch2 != -1)
8879 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8880 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8881 return (total);
8882 case XPATH_OP_RESET:
8883 if (op->ch1 != -1)
8884 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8885 if (op->ch2 != -1)
8886 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8887 ctxt->context->node = NULL;
8888 return (total);
8889 case XPATH_OP_COLLECT:{
8890 if (op->ch1 == -1)
8891 return (0);
8892
8893 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8894
8895 /*
8896 * Optimization for [n] selection where n is a number
8897 */
8898 if ((op->ch2 != -1) &&
8899 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8900 (comp->steps[op->ch2].ch1 == -1) &&
8901 (comp->steps[op->ch2].ch2 != -1) &&
8902 (comp->steps[comp->steps[op->ch2].ch2].op ==
8903 XPATH_OP_VALUE)) {
8904 xmlXPathObjectPtr val;
8905
8906 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8907 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8908 int indx = (int) val->floatval;
8909
8910 if (val->floatval == (float) indx) {
8911 total +=
8912 xmlXPathNodeCollectAndTestNth(ctxt, op,
8913 indx, NULL,
8914 last);
8915 return (total);
8916 }
8917 }
8918 }
8919 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8920 return (total);
8921 }
8922 case XPATH_OP_VALUE:
8923 valuePush(ctxt,
8924 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8925 return (0);
8926 case XPATH_OP_SORT:
8927 if (op->ch1 != -1)
8928 total +=
8929 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8930 last);
8931 if ((ctxt->value != NULL)
8932 && (ctxt->value->type == XPATH_NODESET)
8933 && (ctxt->value->nodesetval != NULL))
8934 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8935 return (total);
8936 default:
8937 return (xmlXPathCompOpEval(ctxt, op));
8938 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939}
8940
Owen Taylor3473f882001-02-23 17:55:21 +00008941/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008942 * xmlXPathCompOpEval:
8943 * @ctxt: the XPath parser context with the compiled expression
8944 * @op: an XPath compiled operation
8945 *
8946 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008948 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008949static int
8950xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
8951{
8952 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008953 int equal, ret;
8954 xmlXPathCompExprPtr comp;
8955 xmlXPathObjectPtr arg1, arg2;
8956
8957 comp = ctxt->comp;
8958 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008959 case XPATH_OP_END:
8960 return (0);
8961 case XPATH_OP_AND:
8962 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8963 xmlXPathBooleanFunction(ctxt, 1);
8964 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
8965 return (total);
8966 arg2 = valuePop(ctxt);
8967 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8968 xmlXPathBooleanFunction(ctxt, 1);
8969 arg1 = valuePop(ctxt);
8970 arg1->boolval &= arg2->boolval;
8971 valuePush(ctxt, arg1);
8972 xmlXPathFreeObject(arg2);
8973 return (total);
8974 case XPATH_OP_OR:
8975 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8976 xmlXPathBooleanFunction(ctxt, 1);
8977 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
8978 return (total);
8979 arg2 = valuePop(ctxt);
8980 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8981 xmlXPathBooleanFunction(ctxt, 1);
8982 arg1 = valuePop(ctxt);
8983 arg1->boolval |= arg2->boolval;
8984 valuePush(ctxt, arg1);
8985 xmlXPathFreeObject(arg2);
8986 return (total);
8987 case XPATH_OP_EQUAL:
8988 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8989 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8990 equal = xmlXPathEqualValues(ctxt);
8991 if (op->value)
8992 valuePush(ctxt, xmlXPathNewBoolean(equal));
8993 else
8994 valuePush(ctxt, xmlXPathNewBoolean(!equal));
8995 return (total);
8996 case XPATH_OP_CMP:
8997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8998 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8999 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9000 valuePush(ctxt, xmlXPathNewBoolean(ret));
9001 return (total);
9002 case XPATH_OP_PLUS:
9003 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9004 if (op->ch2 != -1)
9005 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9006 if (op->value == 0)
9007 xmlXPathSubValues(ctxt);
9008 else if (op->value == 1)
9009 xmlXPathAddValues(ctxt);
9010 else if (op->value == 2)
9011 xmlXPathValueFlipSign(ctxt);
9012 else if (op->value == 3) {
9013 CAST_TO_NUMBER;
9014 CHECK_TYPE0(XPATH_NUMBER);
9015 }
9016 return (total);
9017 case XPATH_OP_MULT:
9018 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9019 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9020 if (op->value == 0)
9021 xmlXPathMultValues(ctxt);
9022 else if (op->value == 1)
9023 xmlXPathDivValues(ctxt);
9024 else if (op->value == 2)
9025 xmlXPathModValues(ctxt);
9026 return (total);
9027 case XPATH_OP_UNION:
9028 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9029 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9030 CHECK_TYPE0(XPATH_NODESET);
9031 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009032
Daniel Veillardf06307e2001-07-03 10:35:50 +00009033 CHECK_TYPE0(XPATH_NODESET);
9034 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009035
Daniel Veillardf06307e2001-07-03 10:35:50 +00009036 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9037 arg2->nodesetval);
9038 valuePush(ctxt, arg1);
9039 xmlXPathFreeObject(arg2);
9040 return (total);
9041 case XPATH_OP_ROOT:
9042 xmlXPathRoot(ctxt);
9043 return (total);
9044 case XPATH_OP_NODE:
9045 if (op->ch1 != -1)
9046 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9047 if (op->ch2 != -1)
9048 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9049 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9050 return (total);
9051 case XPATH_OP_RESET:
9052 if (op->ch1 != -1)
9053 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9054 if (op->ch2 != -1)
9055 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9056 ctxt->context->node = NULL;
9057 return (total);
9058 case XPATH_OP_COLLECT:{
9059 if (op->ch1 == -1)
9060 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009061
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009063
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 /*
9065 * Optimization for [n] selection where n is a number
9066 */
9067 if ((op->ch2 != -1) &&
9068 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9069 (comp->steps[op->ch2].ch1 == -1) &&
9070 (comp->steps[op->ch2].ch2 != -1) &&
9071 (comp->steps[comp->steps[op->ch2].ch2].op ==
9072 XPATH_OP_VALUE)) {
9073 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009074
Daniel Veillardf06307e2001-07-03 10:35:50 +00009075 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9076 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9077 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009078
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 if (val->floatval == (float) indx) {
9080 total +=
9081 xmlXPathNodeCollectAndTestNth(ctxt, op,
9082 indx, NULL,
9083 NULL);
9084 return (total);
9085 }
9086 }
9087 }
9088 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9089 return (total);
9090 }
9091 case XPATH_OP_VALUE:
9092 valuePush(ctxt,
9093 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9094 return (total);
9095 case XPATH_OP_VARIABLE:{
9096 if (op->ch1 != -1)
9097 total +=
9098 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9099 if (op->value5 == NULL)
9100 valuePush(ctxt,
9101 xmlXPathVariableLookup(ctxt->context,
9102 op->value4));
9103 else {
9104 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009105
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9107 if (URI == NULL) {
9108 xmlGenericError(xmlGenericErrorContext,
9109 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9110 op->value4, op->value5);
9111 return (total);
9112 }
9113 valuePush(ctxt,
9114 xmlXPathVariableLookupNS(ctxt->context,
9115 op->value4, URI));
9116 }
9117 return (total);
9118 }
9119 case XPATH_OP_FUNCTION:{
9120 xmlXPathFunction func;
9121 const xmlChar *oldFunc, *oldFuncURI;
9122
9123 if (op->ch1 != -1)
9124 total +=
9125 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9126 if (op->cache != NULL)
9127 func = (xmlXPathFunction) op->cache;
9128 else {
9129 const xmlChar *URI = NULL;
9130
9131 if (op->value5 == NULL)
9132 func =
9133 xmlXPathFunctionLookup(ctxt->context,
9134 op->value4);
9135 else {
9136 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9137 if (URI == NULL) {
9138 xmlGenericError(xmlGenericErrorContext,
9139 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9140 op->value4, op->value5);
9141 return (total);
9142 }
9143 func = xmlXPathFunctionLookupNS(ctxt->context,
9144 op->value4, URI);
9145 }
9146 if (func == NULL) {
9147 xmlGenericError(xmlGenericErrorContext,
9148 "xmlXPathRunEval: function %s not found\n",
9149 op->value4);
9150 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
9151 return (total);
9152 }
9153 op->cache = (void *) func;
9154 op->cacheURI = (void *) URI;
9155 }
9156 oldFunc = ctxt->context->function;
9157 oldFuncURI = ctxt->context->functionURI;
9158 ctxt->context->function = op->value4;
9159 ctxt->context->functionURI = op->cacheURI;
9160 func(ctxt, op->value);
9161 ctxt->context->function = oldFunc;
9162 ctxt->context->functionURI = oldFuncURI;
9163 return (total);
9164 }
9165 case XPATH_OP_ARG:
9166 if (op->ch1 != -1)
9167 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9168 if (op->ch2 != -1)
9169 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9170 return (total);
9171 case XPATH_OP_PREDICATE:
9172 case XPATH_OP_FILTER:{
9173 xmlXPathObjectPtr res;
9174 xmlXPathObjectPtr obj, tmp;
9175 xmlNodeSetPtr newset = NULL;
9176 xmlNodeSetPtr oldset;
9177 xmlNodePtr oldnode;
9178 int i;
9179
9180 /*
9181 * Optimization for ()[1] selection i.e. the first elem
9182 */
9183 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9184 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9185 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9186 xmlXPathObjectPtr val;
9187
9188 val = comp->steps[op->ch2].value4;
9189 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9190 (val->floatval == 1.0)) {
9191 xmlNodePtr first = NULL;
9192
9193 total +=
9194 xmlXPathCompOpEvalFirst(ctxt,
9195 &comp->steps[op->ch1],
9196 &first);
9197 /*
9198 * The nodeset should be in document order,
9199 * Keep only the first value
9200 */
9201 if ((ctxt->value != NULL) &&
9202 (ctxt->value->type == XPATH_NODESET) &&
9203 (ctxt->value->nodesetval != NULL) &&
9204 (ctxt->value->nodesetval->nodeNr > 1))
9205 ctxt->value->nodesetval->nodeNr = 1;
9206 return (total);
9207 }
9208 }
9209 /*
9210 * Optimization for ()[last()] selection i.e. the last elem
9211 */
9212 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9213 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9214 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9215 int f = comp->steps[op->ch2].ch1;
9216
9217 if ((f != -1) &&
9218 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9219 (comp->steps[f].value5 == NULL) &&
9220 (comp->steps[f].value == 0) &&
9221 (comp->steps[f].value4 != NULL) &&
9222 (xmlStrEqual
9223 (comp->steps[f].value4, BAD_CAST "last"))) {
9224 xmlNodePtr last = NULL;
9225
9226 total +=
9227 xmlXPathCompOpEvalLast(ctxt,
9228 &comp->steps[op->ch1],
9229 &last);
9230 /*
9231 * The nodeset should be in document order,
9232 * Keep only the last value
9233 */
9234 if ((ctxt->value != NULL) &&
9235 (ctxt->value->type == XPATH_NODESET) &&
9236 (ctxt->value->nodesetval != NULL) &&
9237 (ctxt->value->nodesetval->nodeTab != NULL) &&
9238 (ctxt->value->nodesetval->nodeNr > 1)) {
9239 ctxt->value->nodesetval->nodeTab[0] =
9240 ctxt->value->nodesetval->nodeTab[ctxt->
9241 value->
9242 nodesetval->
9243 nodeNr -
9244 1];
9245 ctxt->value->nodesetval->nodeNr = 1;
9246 }
9247 return (total);
9248 }
9249 }
9250
9251 if (op->ch1 != -1)
9252 total +=
9253 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9254 if (op->ch2 == -1)
9255 return (total);
9256 if (ctxt->value == NULL)
9257 return (total);
9258
9259 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009260
9261#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009262 /*
9263 * Hum are we filtering the result of an XPointer expression
9264 */
9265 if (ctxt->value->type == XPATH_LOCATIONSET) {
9266 xmlLocationSetPtr newlocset = NULL;
9267 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009268
Daniel Veillardf06307e2001-07-03 10:35:50 +00009269 /*
9270 * Extract the old locset, and then evaluate the result of the
9271 * expression for all the element in the locset. use it to grow
9272 * up a new locset.
9273 */
9274 CHECK_TYPE0(XPATH_LOCATIONSET);
9275 obj = valuePop(ctxt);
9276 oldlocset = obj->user;
9277 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009278
Daniel Veillardf06307e2001-07-03 10:35:50 +00009279 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9280 ctxt->context->contextSize = 0;
9281 ctxt->context->proximityPosition = 0;
9282 if (op->ch2 != -1)
9283 total +=
9284 xmlXPathCompOpEval(ctxt,
9285 &comp->steps[op->ch2]);
9286 res = valuePop(ctxt);
9287 if (res != NULL)
9288 xmlXPathFreeObject(res);
9289 valuePush(ctxt, obj);
9290 CHECK_ERROR0;
9291 return (total);
9292 }
9293 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009294
Daniel Veillardf06307e2001-07-03 10:35:50 +00009295 for (i = 0; i < oldlocset->locNr; i++) {
9296 /*
9297 * Run the evaluation with a node list made of a
9298 * single item in the nodelocset.
9299 */
9300 ctxt->context->node = oldlocset->locTab[i]->user;
9301 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9302 valuePush(ctxt, tmp);
9303 ctxt->context->contextSize = oldlocset->locNr;
9304 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009305
Daniel Veillardf06307e2001-07-03 10:35:50 +00009306 if (op->ch2 != -1)
9307 total +=
9308 xmlXPathCompOpEval(ctxt,
9309 &comp->steps[op->ch2]);
9310 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009311
Daniel Veillardf06307e2001-07-03 10:35:50 +00009312 /*
9313 * The result of the evaluation need to be tested to
9314 * decided whether the filter succeeded or not
9315 */
9316 res = valuePop(ctxt);
9317 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9318 xmlXPtrLocationSetAdd(newlocset,
9319 xmlXPathObjectCopy
9320 (oldlocset->locTab[i]));
9321 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009322
Daniel Veillardf06307e2001-07-03 10:35:50 +00009323 /*
9324 * Cleanup
9325 */
9326 if (res != NULL)
9327 xmlXPathFreeObject(res);
9328 if (ctxt->value == tmp) {
9329 res = valuePop(ctxt);
9330 xmlXPathFreeObject(res);
9331 }
9332
9333 ctxt->context->node = NULL;
9334 }
9335
9336 /*
9337 * The result is used as the new evaluation locset.
9338 */
9339 xmlXPathFreeObject(obj);
9340 ctxt->context->node = NULL;
9341 ctxt->context->contextSize = -1;
9342 ctxt->context->proximityPosition = -1;
9343 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9344 ctxt->context->node = oldnode;
9345 return (total);
9346 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009347#endif /* LIBXML_XPTR_ENABLED */
9348
Daniel Veillardf06307e2001-07-03 10:35:50 +00009349 /*
9350 * Extract the old set, and then evaluate the result of the
9351 * expression for all the element in the set. use it to grow
9352 * up a new set.
9353 */
9354 CHECK_TYPE0(XPATH_NODESET);
9355 obj = valuePop(ctxt);
9356 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009357
Daniel Veillardf06307e2001-07-03 10:35:50 +00009358 oldnode = ctxt->context->node;
9359 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009360
Daniel Veillardf06307e2001-07-03 10:35:50 +00009361 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9362 ctxt->context->contextSize = 0;
9363 ctxt->context->proximityPosition = 0;
9364 if (op->ch2 != -1)
9365 total +=
9366 xmlXPathCompOpEval(ctxt,
9367 &comp->steps[op->ch2]);
9368 res = valuePop(ctxt);
9369 if (res != NULL)
9370 xmlXPathFreeObject(res);
9371 valuePush(ctxt, obj);
9372 ctxt->context->node = oldnode;
9373 CHECK_ERROR0;
9374 } else {
9375 /*
9376 * Initialize the new set.
9377 */
9378 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009379
Daniel Veillardf06307e2001-07-03 10:35:50 +00009380 for (i = 0; i < oldset->nodeNr; i++) {
9381 /*
9382 * Run the evaluation with a node list made of
9383 * a single item in the nodeset.
9384 */
9385 ctxt->context->node = oldset->nodeTab[i];
9386 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9387 valuePush(ctxt, tmp);
9388 ctxt->context->contextSize = oldset->nodeNr;
9389 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009390
Daniel Veillardf06307e2001-07-03 10:35:50 +00009391 if (op->ch2 != -1)
9392 total +=
9393 xmlXPathCompOpEval(ctxt,
9394 &comp->steps[op->ch2]);
9395 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009396
Daniel Veillardf06307e2001-07-03 10:35:50 +00009397 /*
9398 * The result of the evaluation need to be tested to
9399 * decided whether the filter succeeded or not
9400 */
9401 res = valuePop(ctxt);
9402 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9403 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9404 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009405
Daniel Veillardf06307e2001-07-03 10:35:50 +00009406 /*
9407 * Cleanup
9408 */
9409 if (res != NULL)
9410 xmlXPathFreeObject(res);
9411 if (ctxt->value == tmp) {
9412 res = valuePop(ctxt);
9413 xmlXPathFreeObject(res);
9414 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009415
Daniel Veillardf06307e2001-07-03 10:35:50 +00009416 ctxt->context->node = NULL;
9417 }
9418
9419 /*
9420 * The result is used as the new evaluation set.
9421 */
9422 xmlXPathFreeObject(obj);
9423 ctxt->context->node = NULL;
9424 ctxt->context->contextSize = -1;
9425 ctxt->context->proximityPosition = -1;
9426 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9427 }
9428 ctxt->context->node = oldnode;
9429 return (total);
9430 }
9431 case XPATH_OP_SORT:
9432 if (op->ch1 != -1)
9433 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9434 if ((ctxt->value != NULL) &&
9435 (ctxt->value->type == XPATH_NODESET) &&
9436 (ctxt->value->nodesetval != NULL))
9437 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9438 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009439#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009440 case XPATH_OP_RANGETO:{
9441 xmlXPathObjectPtr range;
9442 xmlXPathObjectPtr res, obj;
9443 xmlXPathObjectPtr tmp;
9444 xmlLocationSetPtr newset = NULL;
9445 xmlNodeSetPtr oldset;
9446 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009447
Daniel Veillardf06307e2001-07-03 10:35:50 +00009448 if (op->ch1 != -1)
9449 total +=
9450 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9451 if (op->ch2 == -1)
9452 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009453
Daniel Veillardf06307e2001-07-03 10:35:50 +00009454 CHECK_TYPE0(XPATH_NODESET);
9455 obj = valuePop(ctxt);
9456 oldset = obj->nodesetval;
9457 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009458
Daniel Veillardf06307e2001-07-03 10:35:50 +00009459 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009460
Daniel Veillardf06307e2001-07-03 10:35:50 +00009461 if (oldset != NULL) {
9462 for (i = 0; i < oldset->nodeNr; i++) {
9463 /*
9464 * Run the evaluation with a node list made of a single item
9465 * in the nodeset.
9466 */
9467 ctxt->context->node = oldset->nodeTab[i];
9468 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9469 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009470
Daniel Veillardf06307e2001-07-03 10:35:50 +00009471 if (op->ch2 != -1)
9472 total +=
9473 xmlXPathCompOpEval(ctxt,
9474 &comp->steps[op->ch2]);
9475 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009476
Daniel Veillardf06307e2001-07-03 10:35:50 +00009477 /*
9478 * The result of the evaluation need to be tested to
9479 * decided whether the filter succeeded or not
9480 */
9481 res = valuePop(ctxt);
9482 range =
9483 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9484 res);
9485 if (range != NULL) {
9486 xmlXPtrLocationSetAdd(newset, range);
9487 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009488
Daniel Veillardf06307e2001-07-03 10:35:50 +00009489 /*
9490 * Cleanup
9491 */
9492 if (res != NULL)
9493 xmlXPathFreeObject(res);
9494 if (ctxt->value == tmp) {
9495 res = valuePop(ctxt);
9496 xmlXPathFreeObject(res);
9497 }
9498
9499 ctxt->context->node = NULL;
9500 }
9501 }
9502
9503 /*
9504 * The result is used as the new evaluation set.
9505 */
9506 xmlXPathFreeObject(obj);
9507 ctxt->context->node = NULL;
9508 ctxt->context->contextSize = -1;
9509 ctxt->context->proximityPosition = -1;
9510 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9511 return (total);
9512 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009513#endif /* LIBXML_XPTR_ENABLED */
9514 }
9515 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009516 "XPath: unknown precompiled operation %d\n", op->op);
9517 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009518}
9519
9520/**
9521 * xmlXPathRunEval:
9522 * @ctxt: the XPath parser context with the compiled expression
9523 *
9524 * Evaluate the Precompiled XPath expression in the given context.
9525 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009526static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009527xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9528 xmlXPathCompExprPtr comp;
9529
9530 if ((ctxt == NULL) || (ctxt->comp == NULL))
9531 return;
9532
9533 if (ctxt->valueTab == NULL) {
9534 /* Allocate the value stack */
9535 ctxt->valueTab = (xmlXPathObjectPtr *)
9536 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9537 if (ctxt->valueTab == NULL) {
9538 xmlFree(ctxt);
9539 xmlGenericError(xmlGenericErrorContext,
9540 "xmlXPathRunEval: out of memory\n");
9541 return;
9542 }
9543 ctxt->valueNr = 0;
9544 ctxt->valueMax = 10;
9545 ctxt->value = NULL;
9546 }
9547 comp = ctxt->comp;
9548 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9549}
9550
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009551/************************************************************************
9552 * *
9553 * Public interfaces *
9554 * *
9555 ************************************************************************/
9556
9557/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009558 * xmlXPathEvalPredicate:
9559 * @ctxt: the XPath context
9560 * @res: the Predicate Expression evaluation result
9561 *
9562 * Evaluate a predicate result for the current node.
9563 * A PredicateExpr is evaluated by evaluating the Expr and converting
9564 * the result to a boolean. If the result is a number, the result will
9565 * be converted to true if the number is equal to the position of the
9566 * context node in the context node list (as returned by the position
9567 * function) and will be converted to false otherwise; if the result
9568 * is not a number, then the result will be converted as if by a call
9569 * to the boolean function.
9570 *
9571 * Return 1 if predicate is true, 0 otherwise
9572 */
9573int
9574xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9575 if (res == NULL) return(0);
9576 switch (res->type) {
9577 case XPATH_BOOLEAN:
9578 return(res->boolval);
9579 case XPATH_NUMBER:
9580 return(res->floatval == ctxt->proximityPosition);
9581 case XPATH_NODESET:
9582 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009583 if (res->nodesetval == NULL)
9584 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009585 return(res->nodesetval->nodeNr != 0);
9586 case XPATH_STRING:
9587 return((res->stringval != NULL) &&
9588 (xmlStrlen(res->stringval) != 0));
9589 default:
9590 STRANGE
9591 }
9592 return(0);
9593}
9594
9595/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009596 * xmlXPathEvaluatePredicateResult:
9597 * @ctxt: the XPath Parser context
9598 * @res: the Predicate Expression evaluation result
9599 *
9600 * Evaluate a predicate result for the current node.
9601 * A PredicateExpr is evaluated by evaluating the Expr and converting
9602 * the result to a boolean. If the result is a number, the result will
9603 * be converted to true if the number is equal to the position of the
9604 * context node in the context node list (as returned by the position
9605 * function) and will be converted to false otherwise; if the result
9606 * is not a number, then the result will be converted as if by a call
9607 * to the boolean function.
9608 *
9609 * Return 1 if predicate is true, 0 otherwise
9610 */
9611int
9612xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9613 xmlXPathObjectPtr res) {
9614 if (res == NULL) return(0);
9615 switch (res->type) {
9616 case XPATH_BOOLEAN:
9617 return(res->boolval);
9618 case XPATH_NUMBER:
9619 return(res->floatval == ctxt->context->proximityPosition);
9620 case XPATH_NODESET:
9621 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009622 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009623 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009624 return(res->nodesetval->nodeNr != 0);
9625 case XPATH_STRING:
9626 return((res->stringval != NULL) &&
9627 (xmlStrlen(res->stringval) != 0));
9628 default:
9629 STRANGE
9630 }
9631 return(0);
9632}
9633
9634/**
9635 * xmlXPathCompile:
9636 * @str: the XPath expression
9637 *
9638 * Compile an XPath expression
9639 *
9640 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9641 * the caller has to free the object.
9642 */
9643xmlXPathCompExprPtr
9644xmlXPathCompile(const xmlChar *str) {
9645 xmlXPathParserContextPtr ctxt;
9646 xmlXPathCompExprPtr comp;
9647
9648 xmlXPathInit();
9649
9650 ctxt = xmlXPathNewParserContext(str, NULL);
9651 xmlXPathCompileExpr(ctxt);
9652
Daniel Veillard40af6492001-04-22 08:50:55 +00009653 if (*ctxt->cur != 0) {
9654 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9655 comp = NULL;
9656 } else {
9657 comp = ctxt->comp;
9658 ctxt->comp = NULL;
9659 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009660 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009661#ifdef DEBUG_EVAL_COUNTS
9662 if (comp != NULL) {
9663 comp->string = xmlStrdup(str);
9664 comp->nb = 0;
9665 }
9666#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009667 return(comp);
9668}
9669
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009670/**
9671 * xmlXPathCompiledEval:
9672 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009673 * @ctx: the XPath context
9674 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009675 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009676 *
9677 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9678 * the caller has to free the object.
9679 */
9680xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009681xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009682 xmlXPathParserContextPtr ctxt;
9683 xmlXPathObjectPtr res, tmp, init = NULL;
9684 int stack = 0;
9685
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009686 if ((comp == NULL) || (ctx == NULL))
9687 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009688 xmlXPathInit();
9689
9690 CHECK_CONTEXT(ctx)
9691
Daniel Veillardf06307e2001-07-03 10:35:50 +00009692#ifdef DEBUG_EVAL_COUNTS
9693 comp->nb++;
9694 if ((comp->string != NULL) && (comp->nb > 100)) {
9695 fprintf(stderr, "100 x %s\n", comp->string);
9696 comp->nb = 0;
9697 }
9698#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009699 ctxt = xmlXPathCompParserContext(comp, ctx);
9700 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009701
9702 if (ctxt->value == NULL) {
9703 xmlGenericError(xmlGenericErrorContext,
9704 "xmlXPathEval: evaluation failed\n");
9705 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009706 } else {
9707 res = valuePop(ctxt);
9708 }
9709
Daniel Veillardf06307e2001-07-03 10:35:50 +00009710
Owen Taylor3473f882001-02-23 17:55:21 +00009711 do {
9712 tmp = valuePop(ctxt);
9713 if (tmp != NULL) {
9714 if (tmp != init)
9715 stack++;
9716 xmlXPathFreeObject(tmp);
9717 }
9718 } while (tmp != NULL);
9719 if ((stack != 0) && (res != NULL)) {
9720 xmlGenericError(xmlGenericErrorContext,
9721 "xmlXPathEval: %d object left on the stack\n",
9722 stack);
9723 }
9724 if (ctxt->error != XPATH_EXPRESSION_OK) {
9725 xmlXPathFreeObject(res);
9726 res = NULL;
9727 }
9728
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009729
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009730 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009731 xmlXPathFreeParserContext(ctxt);
9732 return(res);
9733}
9734
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009735/**
9736 * xmlXPathEvalExpr:
9737 * @ctxt: the XPath Parser context
9738 *
9739 * Parse and evaluate an XPath expression in the given context,
9740 * then push the result on the context stack
9741 */
9742void
9743xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9744 xmlXPathCompileExpr(ctxt);
9745 xmlXPathRunEval(ctxt);
9746}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009747
9748/**
9749 * xmlXPathEval:
9750 * @str: the XPath expression
9751 * @ctx: the XPath context
9752 *
9753 * Evaluate the XPath Location Path in the given context.
9754 *
9755 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9756 * the caller has to free the object.
9757 */
9758xmlXPathObjectPtr
9759xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9760 xmlXPathParserContextPtr ctxt;
9761 xmlXPathObjectPtr res, tmp, init = NULL;
9762 int stack = 0;
9763
9764 xmlXPathInit();
9765
9766 CHECK_CONTEXT(ctx)
9767
9768 ctxt = xmlXPathNewParserContext(str, ctx);
9769 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009770
9771 if (ctxt->value == NULL) {
9772 xmlGenericError(xmlGenericErrorContext,
9773 "xmlXPathEval: evaluation failed\n");
9774 res = NULL;
9775 } else if (*ctxt->cur != 0) {
9776 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9777 res = NULL;
9778 } else {
9779 res = valuePop(ctxt);
9780 }
9781
9782 do {
9783 tmp = valuePop(ctxt);
9784 if (tmp != NULL) {
9785 if (tmp != init)
9786 stack++;
9787 xmlXPathFreeObject(tmp);
9788 }
9789 } while (tmp != NULL);
9790 if ((stack != 0) && (res != NULL)) {
9791 xmlGenericError(xmlGenericErrorContext,
9792 "xmlXPathEval: %d object left on the stack\n",
9793 stack);
9794 }
9795 if (ctxt->error != XPATH_EXPRESSION_OK) {
9796 xmlXPathFreeObject(res);
9797 res = NULL;
9798 }
9799
Owen Taylor3473f882001-02-23 17:55:21 +00009800 xmlXPathFreeParserContext(ctxt);
9801 return(res);
9802}
9803
9804/**
9805 * xmlXPathEvalExpression:
9806 * @str: the XPath expression
9807 * @ctxt: the XPath context
9808 *
9809 * Evaluate the XPath expression in the given context.
9810 *
9811 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9812 * the caller has to free the object.
9813 */
9814xmlXPathObjectPtr
9815xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9816 xmlXPathParserContextPtr pctxt;
9817 xmlXPathObjectPtr res, tmp;
9818 int stack = 0;
9819
9820 xmlXPathInit();
9821
9822 CHECK_CONTEXT(ctxt)
9823
9824 pctxt = xmlXPathNewParserContext(str, ctxt);
9825 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009826
9827 if (*pctxt->cur != 0) {
9828 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9829 res = NULL;
9830 } else {
9831 res = valuePop(pctxt);
9832 }
9833 do {
9834 tmp = valuePop(pctxt);
9835 if (tmp != NULL) {
9836 xmlXPathFreeObject(tmp);
9837 stack++;
9838 }
9839 } while (tmp != NULL);
9840 if ((stack != 0) && (res != NULL)) {
9841 xmlGenericError(xmlGenericErrorContext,
9842 "xmlXPathEvalExpression: %d object left on the stack\n",
9843 stack);
9844 }
9845 xmlXPathFreeParserContext(pctxt);
9846 return(res);
9847}
9848
9849/**
9850 * xmlXPathRegisterAllFunctions:
9851 * @ctxt: the XPath context
9852 *
9853 * Registers all default XPath functions in this context
9854 */
9855void
9856xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9857{
9858 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9859 xmlXPathBooleanFunction);
9860 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9861 xmlXPathCeilingFunction);
9862 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9863 xmlXPathCountFunction);
9864 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9865 xmlXPathConcatFunction);
9866 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9867 xmlXPathContainsFunction);
9868 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9869 xmlXPathIdFunction);
9870 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9871 xmlXPathFalseFunction);
9872 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9873 xmlXPathFloorFunction);
9874 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9875 xmlXPathLastFunction);
9876 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9877 xmlXPathLangFunction);
9878 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9879 xmlXPathLocalNameFunction);
9880 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9881 xmlXPathNotFunction);
9882 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9883 xmlXPathNameFunction);
9884 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9885 xmlXPathNamespaceURIFunction);
9886 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9887 xmlXPathNormalizeFunction);
9888 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9889 xmlXPathNumberFunction);
9890 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9891 xmlXPathPositionFunction);
9892 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9893 xmlXPathRoundFunction);
9894 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9895 xmlXPathStringFunction);
9896 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9897 xmlXPathStringLengthFunction);
9898 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9899 xmlXPathStartsWithFunction);
9900 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9901 xmlXPathSubstringFunction);
9902 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9903 xmlXPathSubstringBeforeFunction);
9904 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9905 xmlXPathSubstringAfterFunction);
9906 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9907 xmlXPathSumFunction);
9908 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9909 xmlXPathTrueFunction);
9910 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9911 xmlXPathTranslateFunction);
9912}
9913
9914#endif /* LIBXML_XPATH_ENABLED */