blob: 307bae2d456b1e14c1eeb4a80cfcf356225c8526 [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
944/*
945 * Macros for accessing the content. Those should be used only by the parser,
946 * and not exported.
947 *
948 * Dirty macros, i.e. one need to make assumption on the context to use them
949 *
950 * CUR_PTR return the current pointer to the xmlChar to be parsed.
951 * CUR returns the current xmlChar value, i.e. a 8 bit value
952 * in ISO-Latin or UTF-8.
953 * This should be used internally by the parser
954 * only to compare to ASCII values otherwise it would break when
955 * running with UTF-8 encoding.
956 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
957 * to compare on ASCII based substring.
958 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
959 * strings within the parser.
960 * CURRENT Returns the current char value, with the full decoding of
961 * UTF-8 if we are using this mode. It returns an int.
962 * NEXT Skip to the next character, this does the proper decoding
963 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
964 * It returns the pointer to the current xmlChar.
965 */
966
967#define CUR (*ctxt->cur)
968#define SKIP(val) ctxt->cur += (val)
969#define NXT(val) ctxt->cur[(val)]
970#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +0000971#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
972
973#define COPY_BUF(l,b,i,v) \
974 if (l == 1) b[i++] = (xmlChar) v; \
975 else i += xmlCopyChar(l,&b[i],v)
976
977#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +0000978
979#define SKIP_BLANKS \
980 while (IS_BLANK(*(ctxt->cur))) NEXT
981
982#define CURRENT (*ctxt->cur)
983#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
984
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000985
986#ifndef DBL_DIG
987#define DBL_DIG 16
988#endif
989#ifndef DBL_EPSILON
990#define DBL_EPSILON 1E-9
991#endif
992
993#define UPPER_DOUBLE 1E9
994#define LOWER_DOUBLE 1E-5
995
996#define INTEGER_DIGITS DBL_DIG
997#define FRACTION_DIGITS (DBL_DIG + 1)
998#define EXPONENT_DIGITS (3 + 2)
999
1000/**
1001 * xmlXPathFormatNumber:
1002 * @number: number to format
1003 * @buffer: output buffer
1004 * @buffersize: size of output buffer
1005 *
1006 * Convert the number into a string representation.
1007 */
1008static void
1009xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1010{
1011 switch (isinf(number)) {
1012 case 1:
1013 if (buffersize > (int)sizeof("+Infinity"))
1014 sprintf(buffer, "+Infinity");
1015 break;
1016 case -1:
1017 if (buffersize > (int)sizeof("-Infinity"))
1018 sprintf(buffer, "-Infinity");
1019 break;
1020 default:
1021 if (isnan(number)) {
1022 if (buffersize > (int)sizeof("NaN"))
1023 sprintf(buffer, "NaN");
1024 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001025 /* 3 is sign, decimal point, and terminating zero */
1026 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1027 int integer_place, fraction_place;
1028 char *ptr;
1029 char *after_fraction;
1030 double absolute_value;
1031 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001032
Bjorn Reese70a9da52001-04-21 16:57:29 +00001033 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001034
Bjorn Reese70a9da52001-04-21 16:57:29 +00001035 /*
1036 * First choose format - scientific or regular floating point.
1037 * In either case, result is in work, and after_fraction points
1038 * just past the fractional part.
1039 */
1040 if ( ((absolute_value > UPPER_DOUBLE) ||
1041 (absolute_value < LOWER_DOUBLE)) &&
1042 (absolute_value != 0.0) ) {
1043 /* Use scientific notation */
1044 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1045 fraction_place = DBL_DIG - 1;
1046 snprintf(work, sizeof(work),"%*.*e",
1047 integer_place, fraction_place, number);
1048 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001049 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001050 else {
1051 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001052 if (absolute_value > 0.0)
1053 integer_place = 1 + (int)log10(absolute_value);
1054 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001055 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001056 fraction_place = (integer_place > 0)
1057 ? DBL_DIG - integer_place
1058 : DBL_DIG;
1059 size = snprintf(work, sizeof(work), "%0.*f",
1060 fraction_place, number);
1061 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001062 }
1063
Bjorn Reese70a9da52001-04-21 16:57:29 +00001064 /* Remove fractional trailing zeroes */
1065 ptr = after_fraction;
1066 while (*(--ptr) == '0')
1067 ;
1068 if (*ptr != '.')
1069 ptr++;
1070 strcpy(ptr, after_fraction);
1071
1072 /* Finally copy result back to caller */
1073 size = strlen(work) + 1;
1074 if (size > buffersize) {
1075 work[buffersize - 1] = 0;
1076 size = buffersize;
1077 }
1078 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001079 }
1080 break;
1081 }
1082}
1083
Owen Taylor3473f882001-02-23 17:55:21 +00001084/************************************************************************
1085 * *
1086 * Error handling routines *
1087 * *
1088 ************************************************************************/
1089
1090
1091const char *xmlXPathErrorMessages[] = {
1092 "Ok",
1093 "Number encoding",
1094 "Unfinished litteral",
1095 "Start of litteral",
1096 "Expected $ for variable reference",
1097 "Undefined variable",
1098 "Invalid predicate",
1099 "Invalid expression",
1100 "Missing closing curly brace",
1101 "Unregistered function",
1102 "Invalid operand",
1103 "Invalid type",
1104 "Invalid number of arguments",
1105 "Invalid context size",
1106 "Invalid context position",
1107 "Memory allocation error",
1108 "Syntax error",
1109 "Resource error",
1110 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001111 "Undefined namespace prefix",
1112 "Encoding error",
1113 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001114};
1115
1116/**
1117 * xmlXPathError:
1118 * @ctxt: the XPath Parser context
1119 * @file: the file name
1120 * @line: the line number
1121 * @no: the error number
1122 *
1123 * Create a new xmlNodeSetPtr of type double and of value @val
1124 *
1125 * Returns the newly created object.
1126 */
1127void
1128xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1129 int line, int no) {
1130 int n;
1131 const xmlChar *cur;
1132 const xmlChar *base;
1133
1134 xmlGenericError(xmlGenericErrorContext,
1135 "Error %s:%d: %s\n", file, line,
1136 xmlXPathErrorMessages[no]);
1137
1138 cur = ctxt->cur;
1139 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001140 if ((cur == NULL) || (base == NULL))
1141 return;
1142
Owen Taylor3473f882001-02-23 17:55:21 +00001143 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1144 cur--;
1145 }
1146 n = 0;
1147 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1148 cur--;
1149 if ((*cur == '\n') || (*cur == '\r')) cur++;
1150 base = cur;
1151 n = 0;
1152 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1153 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1154 n++;
1155 }
1156 xmlGenericError(xmlGenericErrorContext, "\n");
1157 cur = ctxt->cur;
1158 while ((*cur == '\n') || (*cur == '\r'))
1159 cur--;
1160 n = 0;
1161 while ((cur != base) && (n++ < 80)) {
1162 xmlGenericError(xmlGenericErrorContext, " ");
1163 base++;
1164 }
1165 xmlGenericError(xmlGenericErrorContext,"^\n");
1166}
1167
1168
1169/************************************************************************
1170 * *
1171 * Routines to handle NodeSets *
1172 * *
1173 ************************************************************************/
1174
1175/**
1176 * xmlXPathCmpNodes:
1177 * @node1: the first node
1178 * @node2: the second node
1179 *
1180 * Compare two nodes w.r.t document order
1181 *
1182 * Returns -2 in case of error 1 if first point < second point, 0 if
1183 * that's the same node, -1 otherwise
1184 */
1185int
1186xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1187 int depth1, depth2;
1188 xmlNodePtr cur, root;
1189
1190 if ((node1 == NULL) || (node2 == NULL))
1191 return(-2);
1192 /*
1193 * a couple of optimizations which will avoid computations in most cases
1194 */
1195 if (node1 == node2)
1196 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001197 if ((node1->type == XML_NAMESPACE_DECL) ||
1198 (node2->type == XML_NAMESPACE_DECL))
1199 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001200 if (node1 == node2->prev)
1201 return(1);
1202 if (node1 == node2->next)
1203 return(-1);
1204
1205 /*
1206 * compute depth to root
1207 */
1208 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1209 if (cur == node1)
1210 return(1);
1211 depth2++;
1212 }
1213 root = cur;
1214 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1215 if (cur == node2)
1216 return(-1);
1217 depth1++;
1218 }
1219 /*
1220 * Distinct document (or distinct entities :-( ) case.
1221 */
1222 if (root != cur) {
1223 return(-2);
1224 }
1225 /*
1226 * get the nearest common ancestor.
1227 */
1228 while (depth1 > depth2) {
1229 depth1--;
1230 node1 = node1->parent;
1231 }
1232 while (depth2 > depth1) {
1233 depth2--;
1234 node2 = node2->parent;
1235 }
1236 while (node1->parent != node2->parent) {
1237 node1 = node1->parent;
1238 node2 = node2->parent;
1239 /* should not happen but just in case ... */
1240 if ((node1 == NULL) || (node2 == NULL))
1241 return(-2);
1242 }
1243 /*
1244 * Find who's first.
1245 */
1246 if (node1 == node2->next)
1247 return(-1);
1248 for (cur = node1->next;cur != NULL;cur = cur->next)
1249 if (cur == node2)
1250 return(1);
1251 return(-1); /* assume there is no sibling list corruption */
1252}
1253
1254/**
1255 * xmlXPathNodeSetSort:
1256 * @set: the node set
1257 *
1258 * Sort the node set in document order
1259 */
1260void
1261xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001262 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001263 xmlNodePtr tmp;
1264
1265 if (set == NULL)
1266 return;
1267
1268 /* Use Shell's sort to sort the node-set */
1269 len = set->nodeNr;
1270 for (incr = len / 2; incr > 0; incr /= 2) {
1271 for (i = incr; i < len; i++) {
1272 j = i - incr;
1273 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001274 if (xmlXPathCmpNodes(set->nodeTab[j],
1275 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001276 tmp = set->nodeTab[j];
1277 set->nodeTab[j] = set->nodeTab[j + incr];
1278 set->nodeTab[j + incr] = tmp;
1279 j -= incr;
1280 } else
1281 break;
1282 }
1283 }
1284 }
1285}
1286
1287#define XML_NODESET_DEFAULT 10
1288/**
1289 * xmlXPathNodeSetCreate:
1290 * @val: an initial xmlNodePtr, or NULL
1291 *
1292 * Create a new xmlNodeSetPtr of type double and of value @val
1293 *
1294 * Returns the newly created object.
1295 */
1296xmlNodeSetPtr
1297xmlXPathNodeSetCreate(xmlNodePtr val) {
1298 xmlNodeSetPtr ret;
1299
1300 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1301 if (ret == NULL) {
1302 xmlGenericError(xmlGenericErrorContext,
1303 "xmlXPathNewNodeSet: out of memory\n");
1304 return(NULL);
1305 }
1306 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1307 if (val != NULL) {
1308 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1309 sizeof(xmlNodePtr));
1310 if (ret->nodeTab == NULL) {
1311 xmlGenericError(xmlGenericErrorContext,
1312 "xmlXPathNewNodeSet: out of memory\n");
1313 return(NULL);
1314 }
1315 memset(ret->nodeTab, 0 ,
1316 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1317 ret->nodeMax = XML_NODESET_DEFAULT;
1318 ret->nodeTab[ret->nodeNr++] = val;
1319 }
1320 return(ret);
1321}
1322
1323/**
1324 * xmlXPathNodeSetAdd:
1325 * @cur: the initial node set
1326 * @val: a new xmlNodePtr
1327 *
1328 * add a new xmlNodePtr ot an existing NodeSet
1329 */
1330void
1331xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1332 int i;
1333
1334 if (val == NULL) return;
1335
1336 /*
1337 * check against doublons
1338 */
1339 for (i = 0;i < cur->nodeNr;i++)
1340 if (cur->nodeTab[i] == val) return;
1341
1342 /*
1343 * grow the nodeTab if needed
1344 */
1345 if (cur->nodeMax == 0) {
1346 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1347 sizeof(xmlNodePtr));
1348 if (cur->nodeTab == NULL) {
1349 xmlGenericError(xmlGenericErrorContext,
1350 "xmlXPathNodeSetAdd: out of memory\n");
1351 return;
1352 }
1353 memset(cur->nodeTab, 0 ,
1354 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1355 cur->nodeMax = XML_NODESET_DEFAULT;
1356 } else if (cur->nodeNr == cur->nodeMax) {
1357 xmlNodePtr *temp;
1358
1359 cur->nodeMax *= 2;
1360 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1361 sizeof(xmlNodePtr));
1362 if (temp == NULL) {
1363 xmlGenericError(xmlGenericErrorContext,
1364 "xmlXPathNodeSetAdd: out of memory\n");
1365 return;
1366 }
1367 cur->nodeTab = temp;
1368 }
1369 cur->nodeTab[cur->nodeNr++] = val;
1370}
1371
1372/**
1373 * xmlXPathNodeSetAddUnique:
1374 * @cur: the initial node set
1375 * @val: a new xmlNodePtr
1376 *
1377 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1378 * when we are sure the node is not already in the set.
1379 */
1380void
1381xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1382 if (val == NULL) return;
1383
1384 /*
1385 * grow the nodeTab if needed
1386 */
1387 if (cur->nodeMax == 0) {
1388 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1389 sizeof(xmlNodePtr));
1390 if (cur->nodeTab == NULL) {
1391 xmlGenericError(xmlGenericErrorContext,
1392 "xmlXPathNodeSetAddUnique: out of memory\n");
1393 return;
1394 }
1395 memset(cur->nodeTab, 0 ,
1396 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1397 cur->nodeMax = XML_NODESET_DEFAULT;
1398 } else if (cur->nodeNr == cur->nodeMax) {
1399 xmlNodePtr *temp;
1400
1401 cur->nodeMax *= 2;
1402 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1403 sizeof(xmlNodePtr));
1404 if (temp == NULL) {
1405 xmlGenericError(xmlGenericErrorContext,
1406 "xmlXPathNodeSetAddUnique: out of memory\n");
1407 return;
1408 }
1409 cur->nodeTab = temp;
1410 }
1411 cur->nodeTab[cur->nodeNr++] = val;
1412}
1413
1414/**
1415 * xmlXPathNodeSetMerge:
1416 * @val1: the first NodeSet or NULL
1417 * @val2: the second NodeSet
1418 *
1419 * Merges two nodesets, all nodes from @val2 are added to @val1
1420 * if @val1 is NULL, a new set is created and copied from @val2
1421 *
1422 * Returns val1 once extended or NULL in case of error.
1423 */
1424xmlNodeSetPtr
1425xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001426 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001427
1428 if (val2 == NULL) return(val1);
1429 if (val1 == NULL) {
1430 val1 = xmlXPathNodeSetCreate(NULL);
1431 }
1432
1433 initNr = val1->nodeNr;
1434
1435 for (i = 0;i < val2->nodeNr;i++) {
1436 /*
1437 * check against doublons
1438 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001439 skip = 0;
1440 for (j = 0; j < initNr; j++) {
1441 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1442 skip = 1;
1443 break;
1444 }
1445 }
1446 if (skip)
1447 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001448
1449 /*
1450 * grow the nodeTab if needed
1451 */
1452 if (val1->nodeMax == 0) {
1453 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1454 sizeof(xmlNodePtr));
1455 if (val1->nodeTab == NULL) {
1456 xmlGenericError(xmlGenericErrorContext,
1457 "xmlXPathNodeSetMerge: out of memory\n");
1458 return(NULL);
1459 }
1460 memset(val1->nodeTab, 0 ,
1461 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1462 val1->nodeMax = XML_NODESET_DEFAULT;
1463 } else if (val1->nodeNr == val1->nodeMax) {
1464 xmlNodePtr *temp;
1465
1466 val1->nodeMax *= 2;
1467 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1468 sizeof(xmlNodePtr));
1469 if (temp == NULL) {
1470 xmlGenericError(xmlGenericErrorContext,
1471 "xmlXPathNodeSetMerge: out of memory\n");
1472 return(NULL);
1473 }
1474 val1->nodeTab = temp;
1475 }
1476 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1477 }
1478
1479 return(val1);
1480}
1481
1482/**
1483 * xmlXPathNodeSetDel:
1484 * @cur: the initial node set
1485 * @val: an xmlNodePtr
1486 *
1487 * Removes an xmlNodePtr from an existing NodeSet
1488 */
1489void
1490xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1491 int i;
1492
1493 if (cur == NULL) return;
1494 if (val == NULL) return;
1495
1496 /*
1497 * check against doublons
1498 */
1499 for (i = 0;i < cur->nodeNr;i++)
1500 if (cur->nodeTab[i] == val) break;
1501
1502 if (i >= cur->nodeNr) {
1503#ifdef DEBUG
1504 xmlGenericError(xmlGenericErrorContext,
1505 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1506 val->name);
1507#endif
1508 return;
1509 }
1510 cur->nodeNr--;
1511 for (;i < cur->nodeNr;i++)
1512 cur->nodeTab[i] = cur->nodeTab[i + 1];
1513 cur->nodeTab[cur->nodeNr] = NULL;
1514}
1515
1516/**
1517 * xmlXPathNodeSetRemove:
1518 * @cur: the initial node set
1519 * @val: the index to remove
1520 *
1521 * Removes an entry from an existing NodeSet list.
1522 */
1523void
1524xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1525 if (cur == NULL) return;
1526 if (val >= cur->nodeNr) return;
1527 cur->nodeNr--;
1528 for (;val < cur->nodeNr;val++)
1529 cur->nodeTab[val] = cur->nodeTab[val + 1];
1530 cur->nodeTab[cur->nodeNr] = NULL;
1531}
1532
1533/**
1534 * xmlXPathFreeNodeSet:
1535 * @obj: the xmlNodeSetPtr to free
1536 *
1537 * Free the NodeSet compound (not the actual nodes !).
1538 */
1539void
1540xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1541 if (obj == NULL) return;
1542 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001543 xmlFree(obj->nodeTab);
1544 }
Owen Taylor3473f882001-02-23 17:55:21 +00001545 xmlFree(obj);
1546}
1547
1548/**
1549 * xmlXPathFreeValueTree:
1550 * @obj: the xmlNodeSetPtr to free
1551 *
1552 * Free the NodeSet compound and the actual tree, this is different
1553 * from xmlXPathFreeNodeSet()
1554 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001555static void
Owen Taylor3473f882001-02-23 17:55:21 +00001556xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1557 int i;
1558
1559 if (obj == NULL) return;
1560 for (i = 0;i < obj->nodeNr;i++)
1561 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001562 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001563
1564 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001565 xmlFree(obj->nodeTab);
1566 }
Owen Taylor3473f882001-02-23 17:55:21 +00001567 xmlFree(obj);
1568}
1569
1570#if defined(DEBUG) || defined(DEBUG_STEP)
1571/**
1572 * xmlGenericErrorContextNodeSet:
1573 * @output: a FILE * for the output
1574 * @obj: the xmlNodeSetPtr to free
1575 *
1576 * Quick display of a NodeSet
1577 */
1578void
1579xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1580 int i;
1581
1582 if (output == NULL) output = xmlGenericErrorContext;
1583 if (obj == NULL) {
1584 fprintf(output, "NodeSet == NULL !\n");
1585 return;
1586 }
1587 if (obj->nodeNr == 0) {
1588 fprintf(output, "NodeSet is empty\n");
1589 return;
1590 }
1591 if (obj->nodeTab == NULL) {
1592 fprintf(output, " nodeTab == NULL !\n");
1593 return;
1594 }
1595 for (i = 0; i < obj->nodeNr; i++) {
1596 if (obj->nodeTab[i] == NULL) {
1597 fprintf(output, " NULL !\n");
1598 return;
1599 }
1600 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1601 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1602 fprintf(output, " /");
1603 else if (obj->nodeTab[i]->name == NULL)
1604 fprintf(output, " noname!");
1605 else fprintf(output, " %s", obj->nodeTab[i]->name);
1606 }
1607 fprintf(output, "\n");
1608}
1609#endif
1610
1611/**
1612 * xmlXPathNewNodeSet:
1613 * @val: the NodePtr value
1614 *
1615 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1616 * it with the single Node @val
1617 *
1618 * Returns the newly created object.
1619 */
1620xmlXPathObjectPtr
1621xmlXPathNewNodeSet(xmlNodePtr val) {
1622 xmlXPathObjectPtr ret;
1623
1624 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1625 if (ret == NULL) {
1626 xmlGenericError(xmlGenericErrorContext,
1627 "xmlXPathNewNodeSet: out of memory\n");
1628 return(NULL);
1629 }
1630 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1631 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001632 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001633 ret->nodesetval = xmlXPathNodeSetCreate(val);
1634 return(ret);
1635}
1636
1637/**
1638 * xmlXPathNewValueTree:
1639 * @val: the NodePtr value
1640 *
1641 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1642 * it with the tree root @val
1643 *
1644 * Returns the newly created object.
1645 */
1646xmlXPathObjectPtr
1647xmlXPathNewValueTree(xmlNodePtr val) {
1648 xmlXPathObjectPtr ret;
1649
1650 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1651 if (ret == NULL) {
1652 xmlGenericError(xmlGenericErrorContext,
1653 "xmlXPathNewNodeSet: out of memory\n");
1654 return(NULL);
1655 }
1656 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1657 ret->type = XPATH_XSLT_TREE;
1658 ret->nodesetval = xmlXPathNodeSetCreate(val);
1659 return(ret);
1660}
1661
1662/**
1663 * xmlXPathNewNodeSetList:
1664 * @val: an existing NodeSet
1665 *
1666 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1667 * it with the Nodeset @val
1668 *
1669 * Returns the newly created object.
1670 */
1671xmlXPathObjectPtr
1672xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1673 xmlXPathObjectPtr ret;
1674 int i;
1675
1676 if (val == NULL)
1677 ret = NULL;
1678 else if (val->nodeTab == NULL)
1679 ret = xmlXPathNewNodeSet(NULL);
1680 else
1681 {
1682 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1683 for (i = 1; i < val->nodeNr; ++i)
1684 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1685 }
1686
1687 return(ret);
1688}
1689
1690/**
1691 * xmlXPathWrapNodeSet:
1692 * @val: the NodePtr value
1693 *
1694 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1695 *
1696 * Returns the newly created object.
1697 */
1698xmlXPathObjectPtr
1699xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1700 xmlXPathObjectPtr ret;
1701
1702 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1703 if (ret == NULL) {
1704 xmlGenericError(xmlGenericErrorContext,
1705 "xmlXPathWrapNodeSet: out of memory\n");
1706 return(NULL);
1707 }
1708 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1709 ret->type = XPATH_NODESET;
1710 ret->nodesetval = val;
1711 return(ret);
1712}
1713
1714/**
1715 * xmlXPathFreeNodeSetList:
1716 * @obj: an existing NodeSetList object
1717 *
1718 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1719 * the list contrary to xmlXPathFreeObject().
1720 */
1721void
1722xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1723 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001724 xmlFree(obj);
1725}
1726
1727/************************************************************************
1728 * *
1729 * Routines to handle extra functions *
1730 * *
1731 ************************************************************************/
1732
1733/**
1734 * xmlXPathRegisterFunc:
1735 * @ctxt: the XPath context
1736 * @name: the function name
1737 * @f: the function implementation or NULL
1738 *
1739 * Register a new function. If @f is NULL it unregisters the function
1740 *
1741 * Returns 0 in case of success, -1 in case of error
1742 */
1743int
1744xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1745 xmlXPathFunction f) {
1746 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1747}
1748
1749/**
1750 * xmlXPathRegisterFuncNS:
1751 * @ctxt: the XPath context
1752 * @name: the function name
1753 * @ns_uri: the function namespace URI
1754 * @f: the function implementation or NULL
1755 *
1756 * Register a new function. If @f is NULL it unregisters the function
1757 *
1758 * Returns 0 in case of success, -1 in case of error
1759 */
1760int
1761xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1762 const xmlChar *ns_uri, xmlXPathFunction f) {
1763 if (ctxt == NULL)
1764 return(-1);
1765 if (name == NULL)
1766 return(-1);
1767
1768 if (ctxt->funcHash == NULL)
1769 ctxt->funcHash = xmlHashCreate(0);
1770 if (ctxt->funcHash == NULL)
1771 return(-1);
1772 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1773}
1774
1775/**
1776 * xmlXPathFunctionLookup:
1777 * @ctxt: the XPath context
1778 * @name: the function name
1779 *
1780 * Search in the Function array of the context for the given
1781 * function.
1782 *
1783 * Returns the xmlXPathFunction or NULL if not found
1784 */
1785xmlXPathFunction
1786xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1787 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1788}
1789
1790/**
1791 * xmlXPathFunctionLookupNS:
1792 * @ctxt: the XPath context
1793 * @name: the function name
1794 * @ns_uri: the function namespace URI
1795 *
1796 * Search in the Function array of the context for the given
1797 * function.
1798 *
1799 * Returns the xmlXPathFunction or NULL if not found
1800 */
1801xmlXPathFunction
1802xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1803 const xmlChar *ns_uri) {
1804 if (ctxt == NULL)
1805 return(NULL);
1806 if (ctxt->funcHash == NULL)
1807 return(NULL);
1808 if (name == NULL)
1809 return(NULL);
1810
1811 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1812}
1813
1814/**
1815 * xmlXPathRegisteredFuncsCleanup:
1816 * @ctxt: the XPath context
1817 *
1818 * Cleanup the XPath context data associated to registered functions
1819 */
1820void
1821xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1822 if (ctxt == NULL)
1823 return;
1824
1825 xmlHashFree(ctxt->funcHash, NULL);
1826 ctxt->funcHash = NULL;
1827}
1828
1829/************************************************************************
1830 * *
1831 * Routines to handle Variable *
1832 * *
1833 ************************************************************************/
1834
1835/**
1836 * xmlXPathRegisterVariable:
1837 * @ctxt: the XPath context
1838 * @name: the variable name
1839 * @value: the variable value or NULL
1840 *
1841 * Register a new variable value. If @value is NULL it unregisters
1842 * the variable
1843 *
1844 * Returns 0 in case of success, -1 in case of error
1845 */
1846int
1847xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1848 xmlXPathObjectPtr value) {
1849 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1850}
1851
1852/**
1853 * xmlXPathRegisterVariableNS:
1854 * @ctxt: the XPath context
1855 * @name: the variable name
1856 * @ns_uri: the variable namespace URI
1857 * @value: the variable value or NULL
1858 *
1859 * Register a new variable value. If @value is NULL it unregisters
1860 * the variable
1861 *
1862 * Returns 0 in case of success, -1 in case of error
1863 */
1864int
1865xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1866 const xmlChar *ns_uri,
1867 xmlXPathObjectPtr value) {
1868 if (ctxt == NULL)
1869 return(-1);
1870 if (name == NULL)
1871 return(-1);
1872
1873 if (ctxt->varHash == NULL)
1874 ctxt->varHash = xmlHashCreate(0);
1875 if (ctxt->varHash == NULL)
1876 return(-1);
1877 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1878 (void *) value,
1879 (xmlHashDeallocator)xmlXPathFreeObject));
1880}
1881
1882/**
1883 * xmlXPathRegisterVariableLookup:
1884 * @ctxt: the XPath context
1885 * @f: the lookup function
1886 * @data: the lookup data
1887 *
1888 * register an external mechanism to do variable lookup
1889 */
1890void
1891xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1892 xmlXPathVariableLookupFunc f, void *data) {
1893 if (ctxt == NULL)
1894 return;
1895 ctxt->varLookupFunc = (void *) f;
1896 ctxt->varLookupData = data;
1897}
1898
1899/**
1900 * xmlXPathVariableLookup:
1901 * @ctxt: the XPath context
1902 * @name: the variable name
1903 *
1904 * Search in the Variable array of the context for the given
1905 * variable value.
1906 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00001907 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00001908 */
1909xmlXPathObjectPtr
1910xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1911 if (ctxt == NULL)
1912 return(NULL);
1913
1914 if (ctxt->varLookupFunc != NULL) {
1915 xmlXPathObjectPtr ret;
1916
1917 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1918 (ctxt->varLookupData, name, NULL);
1919 if (ret != NULL) return(ret);
1920 }
1921 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1922}
1923
1924/**
1925 * xmlXPathVariableLookupNS:
1926 * @ctxt: the XPath context
1927 * @name: the variable name
1928 * @ns_uri: the variable namespace URI
1929 *
1930 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00001931 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00001932 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00001933 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00001934 */
1935xmlXPathObjectPtr
1936xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1937 const xmlChar *ns_uri) {
1938 if (ctxt == NULL)
1939 return(NULL);
1940
1941 if (ctxt->varLookupFunc != NULL) {
1942 xmlXPathObjectPtr ret;
1943
1944 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1945 (ctxt->varLookupData, name, ns_uri);
1946 if (ret != NULL) return(ret);
1947 }
1948
1949 if (ctxt->varHash == NULL)
1950 return(NULL);
1951 if (name == NULL)
1952 return(NULL);
1953
Daniel Veillard8c357d52001-07-03 23:43:33 +00001954 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
1955 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00001956}
1957
1958/**
1959 * xmlXPathRegisteredVariablesCleanup:
1960 * @ctxt: the XPath context
1961 *
1962 * Cleanup the XPath context data associated to registered variables
1963 */
1964void
1965xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1966 if (ctxt == NULL)
1967 return;
1968
Daniel Veillard76d66f42001-05-16 21:05:17 +00001969 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00001970 ctxt->varHash = NULL;
1971}
1972
1973/**
1974 * xmlXPathRegisterNs:
1975 * @ctxt: the XPath context
1976 * @prefix: the namespace prefix
1977 * @ns_uri: the namespace name
1978 *
1979 * Register a new namespace. If @ns_uri is NULL it unregisters
1980 * the namespace
1981 *
1982 * Returns 0 in case of success, -1 in case of error
1983 */
1984int
1985xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1986 const xmlChar *ns_uri) {
1987 if (ctxt == NULL)
1988 return(-1);
1989 if (prefix == NULL)
1990 return(-1);
1991
1992 if (ctxt->nsHash == NULL)
1993 ctxt->nsHash = xmlHashCreate(10);
1994 if (ctxt->nsHash == NULL)
1995 return(-1);
1996 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1997 (xmlHashDeallocator)xmlFree));
1998}
1999
2000/**
2001 * xmlXPathNsLookup:
2002 * @ctxt: the XPath context
2003 * @prefix: the namespace prefix value
2004 *
2005 * Search in the namespace declaration array of the context for the given
2006 * namespace name associated to the given prefix
2007 *
2008 * Returns the value or NULL if not found
2009 */
2010const xmlChar *
2011xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2012 if (ctxt == NULL)
2013 return(NULL);
2014 if (prefix == NULL)
2015 return(NULL);
2016
2017#ifdef XML_XML_NAMESPACE
2018 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2019 return(XML_XML_NAMESPACE);
2020#endif
2021
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002022 if (ctxt->namespaces != NULL) {
2023 int i;
2024
2025 for (i = 0;i < ctxt->nsNr;i++) {
2026 if ((ctxt->namespaces[i] != NULL) &&
2027 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2028 return(ctxt->namespaces[i]->href);
2029 }
2030 }
Owen Taylor3473f882001-02-23 17:55:21 +00002031
2032 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2033}
2034
2035/**
2036 * xmlXPathRegisteredVariablesCleanup:
2037 * @ctxt: the XPath context
2038 *
2039 * Cleanup the XPath context data associated to registered variables
2040 */
2041void
2042xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2043 if (ctxt == NULL)
2044 return;
2045
2046 xmlHashFree(ctxt->nsHash, NULL);
2047 ctxt->nsHash = NULL;
2048}
2049
2050/************************************************************************
2051 * *
2052 * Routines to handle Values *
2053 * *
2054 ************************************************************************/
2055
2056/* Allocations are terrible, one need to optimize all this !!! */
2057
2058/**
2059 * xmlXPathNewFloat:
2060 * @val: the double value
2061 *
2062 * Create a new xmlXPathObjectPtr of type double and of value @val
2063 *
2064 * Returns the newly created object.
2065 */
2066xmlXPathObjectPtr
2067xmlXPathNewFloat(double val) {
2068 xmlXPathObjectPtr ret;
2069
2070 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2071 if (ret == NULL) {
2072 xmlGenericError(xmlGenericErrorContext,
2073 "xmlXPathNewFloat: out of memory\n");
2074 return(NULL);
2075 }
2076 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2077 ret->type = XPATH_NUMBER;
2078 ret->floatval = val;
2079 return(ret);
2080}
2081
2082/**
2083 * xmlXPathNewBoolean:
2084 * @val: the boolean value
2085 *
2086 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2087 *
2088 * Returns the newly created object.
2089 */
2090xmlXPathObjectPtr
2091xmlXPathNewBoolean(int val) {
2092 xmlXPathObjectPtr ret;
2093
2094 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2095 if (ret == NULL) {
2096 xmlGenericError(xmlGenericErrorContext,
2097 "xmlXPathNewBoolean: out of memory\n");
2098 return(NULL);
2099 }
2100 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2101 ret->type = XPATH_BOOLEAN;
2102 ret->boolval = (val != 0);
2103 return(ret);
2104}
2105
2106/**
2107 * xmlXPathNewString:
2108 * @val: the xmlChar * value
2109 *
2110 * Create a new xmlXPathObjectPtr of type string and of value @val
2111 *
2112 * Returns the newly created object.
2113 */
2114xmlXPathObjectPtr
2115xmlXPathNewString(const xmlChar *val) {
2116 xmlXPathObjectPtr ret;
2117
2118 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2119 if (ret == NULL) {
2120 xmlGenericError(xmlGenericErrorContext,
2121 "xmlXPathNewString: out of memory\n");
2122 return(NULL);
2123 }
2124 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2125 ret->type = XPATH_STRING;
2126 if (val != NULL)
2127 ret->stringval = xmlStrdup(val);
2128 else
2129 ret->stringval = xmlStrdup((const xmlChar *)"");
2130 return(ret);
2131}
2132
2133/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002134 * xmlXPathWrapString:
2135 * @val: the xmlChar * value
2136 *
2137 * Wraps the @val string into an XPath object.
2138 *
2139 * Returns the newly created object.
2140 */
2141xmlXPathObjectPtr
2142xmlXPathWrapString (xmlChar *val) {
2143 xmlXPathObjectPtr ret;
2144
2145 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2146 if (ret == NULL) {
2147 xmlGenericError(xmlGenericErrorContext,
2148 "xmlXPathWrapString: out of memory\n");
2149 return(NULL);
2150 }
2151 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2152 ret->type = XPATH_STRING;
2153 ret->stringval = val;
2154 return(ret);
2155}
2156
2157/**
Owen Taylor3473f882001-02-23 17:55:21 +00002158 * xmlXPathNewCString:
2159 * @val: the char * value
2160 *
2161 * Create a new xmlXPathObjectPtr of type string and of value @val
2162 *
2163 * Returns the newly created object.
2164 */
2165xmlXPathObjectPtr
2166xmlXPathNewCString(const char *val) {
2167 xmlXPathObjectPtr ret;
2168
2169 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2170 if (ret == NULL) {
2171 xmlGenericError(xmlGenericErrorContext,
2172 "xmlXPathNewCString: out of memory\n");
2173 return(NULL);
2174 }
2175 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2176 ret->type = XPATH_STRING;
2177 ret->stringval = xmlStrdup(BAD_CAST val);
2178 return(ret);
2179}
2180
2181/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002182 * xmlXPathWrapCString:
2183 * @val: the char * value
2184 *
2185 * Wraps a string into an XPath object.
2186 *
2187 * Returns the newly created object.
2188 */
2189xmlXPathObjectPtr
2190xmlXPathWrapCString (char * val) {
2191 return(xmlXPathWrapString((xmlChar *)(val)));
2192}
2193
2194/**
Owen Taylor3473f882001-02-23 17:55:21 +00002195 * xmlXPathObjectCopy:
2196 * @val: the original object
2197 *
2198 * allocate a new copy of a given object
2199 *
2200 * Returns the newly created object.
2201 */
2202xmlXPathObjectPtr
2203xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2204 xmlXPathObjectPtr ret;
2205
2206 if (val == NULL)
2207 return(NULL);
2208
2209 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2210 if (ret == NULL) {
2211 xmlGenericError(xmlGenericErrorContext,
2212 "xmlXPathObjectCopy: out of memory\n");
2213 return(NULL);
2214 }
2215 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2216 switch (val->type) {
2217 case XPATH_BOOLEAN:
2218 case XPATH_NUMBER:
2219 case XPATH_POINT:
2220 case XPATH_RANGE:
2221 break;
2222 case XPATH_STRING:
2223 ret->stringval = xmlStrdup(val->stringval);
2224 break;
2225 case XPATH_XSLT_TREE:
2226 if ((val->nodesetval != NULL) &&
2227 (val->nodesetval->nodeTab != NULL))
2228 ret->nodesetval = xmlXPathNodeSetCreate(
2229 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2230 else
2231 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2232 break;
2233 case XPATH_NODESET:
2234 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2235 break;
2236 case XPATH_LOCATIONSET:
2237#ifdef LIBXML_XPTR_ENABLED
2238 {
2239 xmlLocationSetPtr loc = val->user;
2240 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2241 break;
2242 }
2243#endif
2244 case XPATH_UNDEFINED:
2245 case XPATH_USERS:
2246 xmlGenericError(xmlGenericErrorContext,
2247 "xmlXPathObjectCopy: unsupported type %d\n",
2248 val->type);
2249 break;
2250 }
2251 return(ret);
2252}
2253
2254/**
2255 * xmlXPathFreeObject:
2256 * @obj: the object to free
2257 *
2258 * Free up an xmlXPathObjectPtr object.
2259 */
2260void
2261xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2262 if (obj == NULL) return;
2263 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002264 if (obj->boolval) {
2265 obj->type = XPATH_XSLT_TREE;
2266 if (obj->nodesetval != NULL)
2267 xmlXPathFreeValueTree(obj->nodesetval);
2268 } else {
2269 if (obj->nodesetval != NULL)
2270 xmlXPathFreeNodeSet(obj->nodesetval);
2271 }
Owen Taylor3473f882001-02-23 17:55:21 +00002272#ifdef LIBXML_XPTR_ENABLED
2273 } else if (obj->type == XPATH_LOCATIONSET) {
2274 if (obj->user != NULL)
2275 xmlXPtrFreeLocationSet(obj->user);
2276#endif
2277 } else if (obj->type == XPATH_STRING) {
2278 if (obj->stringval != NULL)
2279 xmlFree(obj->stringval);
2280 } else if (obj->type == XPATH_XSLT_TREE) {
2281 if (obj->nodesetval != NULL)
2282 xmlXPathFreeValueTree(obj->nodesetval);
2283 }
2284
Owen Taylor3473f882001-02-23 17:55:21 +00002285 xmlFree(obj);
2286}
2287
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002288
2289/************************************************************************
2290 * *
2291 * Type Casting Routines *
2292 * *
2293 ************************************************************************/
2294
2295/**
2296 * xmlXPathCastBooleanToString:
2297 * @val: a boolean
2298 *
2299 * Converts a boolean to its string value.
2300 *
2301 * Returns a newly allocated string.
2302 */
2303xmlChar *
2304xmlXPathCastBooleanToString (int val) {
2305 xmlChar *ret;
2306 if (val)
2307 ret = xmlStrdup((const xmlChar *) "true");
2308 else
2309 ret = xmlStrdup((const xmlChar *) "false");
2310 return(ret);
2311}
2312
2313/**
2314 * xmlXPathCastNumberToString:
2315 * @val: a number
2316 *
2317 * Converts a number to its string value.
2318 *
2319 * Returns a newly allocated string.
2320 */
2321xmlChar *
2322xmlXPathCastNumberToString (double val) {
2323 xmlChar *ret;
2324 switch (isinf(val)) {
2325 case 1:
2326 ret = xmlStrdup((const xmlChar *) "+Infinity");
2327 break;
2328 case -1:
2329 ret = xmlStrdup((const xmlChar *) "-Infinity");
2330 break;
2331 default:
2332 if (isnan(val)) {
2333 ret = xmlStrdup((const xmlChar *) "NaN");
2334 } else {
2335 /* could be improved */
2336 char buf[100];
2337 xmlXPathFormatNumber(val, buf, 100);
2338 ret = xmlStrdup((const xmlChar *) buf);
2339 }
2340 }
2341 return(ret);
2342}
2343
2344/**
2345 * xmlXPathCastNodeToString:
2346 * @node: a node
2347 *
2348 * Converts a node to its string value.
2349 *
2350 * Returns a newly allocated string.
2351 */
2352xmlChar *
2353xmlXPathCastNodeToString (xmlNodePtr node) {
2354 return(xmlNodeGetContent(node));
2355}
2356
2357/**
2358 * xmlXPathCastNodeSetToString:
2359 * @ns: a node-set
2360 *
2361 * Converts a node-set to its string value.
2362 *
2363 * Returns a newly allocated string.
2364 */
2365xmlChar *
2366xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2367 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2368 return(xmlStrdup((const xmlChar *) ""));
2369
2370 xmlXPathNodeSetSort(ns);
2371 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2372}
2373
2374/**
2375 * xmlXPathCastToString:
2376 * @val: an XPath object
2377 *
2378 * Converts an existing object to its string() equivalent
2379 *
2380 * Returns the string value of the object, NULL in case of error.
2381 * A new string is allocated only if needed (val isn't a
2382 * string object).
2383 */
2384xmlChar *
2385xmlXPathCastToString(xmlXPathObjectPtr val) {
2386 xmlChar *ret = NULL;
2387
2388 if (val == NULL)
2389 return(xmlStrdup((const xmlChar *) ""));
2390 switch (val->type) {
2391 case XPATH_UNDEFINED:
2392#ifdef DEBUG_EXPR
2393 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2394#endif
2395 ret = xmlStrdup((const xmlChar *) "");
2396 break;
2397 case XPATH_XSLT_TREE:
2398 case XPATH_NODESET:
2399 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2400 break;
2401 case XPATH_STRING:
2402 return(val->stringval);
2403 case XPATH_BOOLEAN:
2404 ret = xmlXPathCastBooleanToString(val->boolval);
2405 break;
2406 case XPATH_NUMBER: {
2407 ret = xmlXPathCastNumberToString(val->floatval);
2408 break;
2409 }
2410 case XPATH_USERS:
2411 case XPATH_POINT:
2412 case XPATH_RANGE:
2413 case XPATH_LOCATIONSET:
2414 TODO
2415 ret = xmlStrdup((const xmlChar *) "");
2416 break;
2417 }
2418 return(ret);
2419}
2420
2421/**
2422 * xmlXPathConvertString:
2423 * @val: an XPath object
2424 *
2425 * Converts an existing object to its string() equivalent
2426 *
2427 * Returns the new object, the old one is freed (or the operation
2428 * is done directly on @val)
2429 */
2430xmlXPathObjectPtr
2431xmlXPathConvertString(xmlXPathObjectPtr val) {
2432 xmlChar *res = NULL;
2433
2434 if (val == NULL)
2435 return(xmlXPathNewCString(""));
2436
2437 switch (val->type) {
2438 case XPATH_UNDEFINED:
2439#ifdef DEBUG_EXPR
2440 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2441#endif
2442 break;
2443 case XPATH_XSLT_TREE:
2444 case XPATH_NODESET:
2445 res = xmlXPathCastNodeSetToString(val->nodesetval);
2446 break;
2447 case XPATH_STRING:
2448 return(val);
2449 case XPATH_BOOLEAN:
2450 res = xmlXPathCastBooleanToString(val->boolval);
2451 break;
2452 case XPATH_NUMBER:
2453 res = xmlXPathCastNumberToString(val->floatval);
2454 break;
2455 case XPATH_USERS:
2456 case XPATH_POINT:
2457 case XPATH_RANGE:
2458 case XPATH_LOCATIONSET:
2459 TODO;
2460 break;
2461 }
2462 xmlXPathFreeObject(val);
2463 if (res == NULL)
2464 return(xmlXPathNewCString(""));
2465 return(xmlXPathWrapString(res));
2466}
2467
2468/**
2469 * xmlXPathCastBooleanToNumber:
2470 * @val: a boolean
2471 *
2472 * Converts a boolean to its number value
2473 *
2474 * Returns the number value
2475 */
2476double
2477xmlXPathCastBooleanToNumber(int val) {
2478 if (val)
2479 return(1.0);
2480 return(0.0);
2481}
2482
2483/**
2484 * xmlXPathCastStringToNumber:
2485 * @val: a string
2486 *
2487 * Converts a string to its number value
2488 *
2489 * Returns the number value
2490 */
2491double
2492xmlXPathCastStringToNumber(const xmlChar * val) {
2493 return(xmlXPathStringEvalNumber(val));
2494}
2495
2496/**
2497 * xmlXPathCastNodeToNumber:
2498 * @node: a node
2499 *
2500 * Converts a node to its number value
2501 *
2502 * Returns the number value
2503 */
2504double
2505xmlXPathCastNodeToNumber (xmlNodePtr node) {
2506 xmlChar *strval;
2507 double ret;
2508
2509 if (node == NULL)
2510 return(xmlXPathNAN);
2511 strval = xmlXPathCastNodeToString(node);
2512 if (strval == NULL)
2513 return(xmlXPathNAN);
2514 ret = xmlXPathCastStringToNumber(strval);
2515 xmlFree(strval);
2516
2517 return(ret);
2518}
2519
2520/**
2521 * xmlXPathCastNodeSetToNumber:
2522 * @ns: a node-set
2523 *
2524 * Converts a node-set to its number value
2525 *
2526 * Returns the number value
2527 */
2528double
2529xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
2530 xmlChar *str;
2531 double ret;
2532
2533 if (ns == NULL)
2534 return(xmlXPathNAN);
2535 str = xmlXPathCastNodeSetToString(ns);
2536 ret = xmlXPathCastStringToNumber(str);
2537 xmlFree(str);
2538 return(ret);
2539}
2540
2541/**
2542 * xmlXPathCastToNumber:
2543 * @val: an XPath object
2544 *
2545 * Converts an XPath object to its number value
2546 *
2547 * Returns the number value
2548 */
2549double
2550xmlXPathCastToNumber(xmlXPathObjectPtr val) {
2551 double ret = 0.0;
2552
2553 if (val == NULL)
2554 return(xmlXPathNAN);
2555 switch (val->type) {
2556 case XPATH_UNDEFINED:
2557#ifdef DEGUB_EXPR
2558 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
2559#endif
2560 ret = xmlXPathNAN;
2561 break;
2562 case XPATH_XSLT_TREE:
2563 case XPATH_NODESET:
2564 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
2565 break;
2566 case XPATH_STRING:
2567 ret = xmlXPathCastStringToNumber(val->stringval);
2568 break;
2569 case XPATH_NUMBER:
2570 ret = val->floatval;
2571 break;
2572 case XPATH_BOOLEAN:
2573 ret = xmlXPathCastBooleanToNumber(val->boolval);
2574 break;
2575 case XPATH_USERS:
2576 case XPATH_POINT:
2577 case XPATH_RANGE:
2578 case XPATH_LOCATIONSET:
2579 TODO;
2580 ret = xmlXPathNAN;
2581 break;
2582 }
2583 return(ret);
2584}
2585
2586/**
2587 * xmlXPathConvertNumber:
2588 * @val: an XPath object
2589 *
2590 * Converts an existing object to its number() equivalent
2591 *
2592 * Returns the new object, the old one is freed (or the operation
2593 * is done directly on @val)
2594 */
2595xmlXPathObjectPtr
2596xmlXPathConvertNumber(xmlXPathObjectPtr val) {
2597 xmlXPathObjectPtr ret;
2598
2599 if (val == NULL)
2600 return(xmlXPathNewFloat(0.0));
2601 if (val->type == XPATH_NUMBER)
2602 return(val);
2603 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
2604 xmlXPathFreeObject(val);
2605 return(ret);
2606}
2607
2608/**
2609 * xmlXPathCastNumberToBoolean:
2610 * @val: a number
2611 *
2612 * Converts a number to its boolean value
2613 *
2614 * Returns the boolean value
2615 */
2616int
2617xmlXPathCastNumberToBoolean (double val) {
2618 if (isnan(val) || (val == 0.0))
2619 return(0);
2620 return(1);
2621}
2622
2623/**
2624 * xmlXPathCastStringToBoolean:
2625 * @val: a string
2626 *
2627 * Converts a string to its boolean value
2628 *
2629 * Returns the boolean value
2630 */
2631int
2632xmlXPathCastStringToBoolean (const xmlChar *val) {
2633 if ((val == NULL) || (xmlStrlen(val) == 0))
2634 return(0);
2635 return(1);
2636}
2637
2638/**
2639 * xmlXPathCastNodeSetToBoolean:
2640 * @ns: a node-set
2641 *
2642 * Converts a node-set to its boolean value
2643 *
2644 * Returns the boolean value
2645 */
2646int
2647xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
2648 if ((ns == NULL) || (ns->nodeNr == 0))
2649 return(0);
2650 return(1);
2651}
2652
2653/**
2654 * xmlXpathCastToBoolean:
2655 * @val: an XPath object
2656 *
2657 * Converts an XPath object to its boolean value
2658 *
2659 * Returns the boolean value
2660 */
2661int
2662xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
2663 int ret = 0;
2664
2665 if (val == NULL)
2666 return(0);
2667 switch (val->type) {
2668 case XPATH_UNDEFINED:
2669#ifdef DEBUG_EXPR
2670 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
2671#endif
2672 ret = 0;
2673 break;
2674 case XPATH_XSLT_TREE:
2675 case XPATH_NODESET:
2676 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
2677 break;
2678 case XPATH_STRING:
2679 ret = xmlXPathCastStringToBoolean(val->stringval);
2680 break;
2681 case XPATH_NUMBER:
2682 ret = xmlXPathCastNumberToBoolean(val->floatval);
2683 break;
2684 case XPATH_BOOLEAN:
2685 ret = val->boolval;
2686 break;
2687 case XPATH_USERS:
2688 case XPATH_POINT:
2689 case XPATH_RANGE:
2690 case XPATH_LOCATIONSET:
2691 TODO;
2692 ret = 0;
2693 break;
2694 }
2695 return(ret);
2696}
2697
2698
2699/**
2700 * xmlXPathConvertBoolean:
2701 * @val: an XPath object
2702 *
2703 * Converts an existing object to its boolean() equivalent
2704 *
2705 * Returns the new object, the old one is freed (or the operation
2706 * is done directly on @val)
2707 */
2708xmlXPathObjectPtr
2709xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
2710 xmlXPathObjectPtr ret;
2711
2712 if (val == NULL)
2713 return(xmlXPathNewBoolean(0));
2714 if (val->type == XPATH_BOOLEAN)
2715 return(val);
2716 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
2717 xmlXPathFreeObject(val);
2718 return(ret);
2719}
2720
Owen Taylor3473f882001-02-23 17:55:21 +00002721/************************************************************************
2722 * *
2723 * Routines to handle XPath contexts *
2724 * *
2725 ************************************************************************/
2726
2727/**
2728 * xmlXPathNewContext:
2729 * @doc: the XML document
2730 *
2731 * Create a new xmlXPathContext
2732 *
2733 * Returns the xmlXPathContext just allocated.
2734 */
2735xmlXPathContextPtr
2736xmlXPathNewContext(xmlDocPtr doc) {
2737 xmlXPathContextPtr ret;
2738
2739 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2740 if (ret == NULL) {
2741 xmlGenericError(xmlGenericErrorContext,
2742 "xmlXPathNewContext: out of memory\n");
2743 return(NULL);
2744 }
2745 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2746 ret->doc = doc;
2747 ret->node = NULL;
2748
2749 ret->varHash = NULL;
2750
2751 ret->nb_types = 0;
2752 ret->max_types = 0;
2753 ret->types = NULL;
2754
2755 ret->funcHash = xmlHashCreate(0);
2756
2757 ret->nb_axis = 0;
2758 ret->max_axis = 0;
2759 ret->axis = NULL;
2760
2761 ret->nsHash = NULL;
2762 ret->user = NULL;
2763
2764 ret->contextSize = -1;
2765 ret->proximityPosition = -1;
2766
2767 xmlXPathRegisterAllFunctions(ret);
2768
2769 return(ret);
2770}
2771
2772/**
2773 * xmlXPathFreeContext:
2774 * @ctxt: the context to free
2775 *
2776 * Free up an xmlXPathContext
2777 */
2778void
2779xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2780 xmlXPathRegisteredNsCleanup(ctxt);
2781 xmlXPathRegisteredFuncsCleanup(ctxt);
2782 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002783 xmlFree(ctxt);
2784}
2785
2786/************************************************************************
2787 * *
2788 * Routines to handle XPath parser contexts *
2789 * *
2790 ************************************************************************/
2791
2792#define CHECK_CTXT(ctxt) \
2793 if (ctxt == NULL) { \
2794 xmlGenericError(xmlGenericErrorContext, \
2795 "%s:%d Internal error: ctxt == NULL\n", \
2796 __FILE__, __LINE__); \
2797 } \
2798
2799
2800#define CHECK_CONTEXT(ctxt) \
2801 if (ctxt == NULL) { \
2802 xmlGenericError(xmlGenericErrorContext, \
2803 "%s:%d Internal error: no context\n", \
2804 __FILE__, __LINE__); \
2805 } \
2806 else if (ctxt->doc == NULL) { \
2807 xmlGenericError(xmlGenericErrorContext, \
2808 "%s:%d Internal error: no document\n", \
2809 __FILE__, __LINE__); \
2810 } \
2811 else if (ctxt->doc->children == NULL) { \
2812 xmlGenericError(xmlGenericErrorContext, \
2813 "%s:%d Internal error: document without root\n", \
2814 __FILE__, __LINE__); \
2815 } \
2816
2817
2818/**
2819 * xmlXPathNewParserContext:
2820 * @str: the XPath expression
2821 * @ctxt: the XPath context
2822 *
2823 * Create a new xmlXPathParserContext
2824 *
2825 * Returns the xmlXPathParserContext just allocated.
2826 */
2827xmlXPathParserContextPtr
2828xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2829 xmlXPathParserContextPtr ret;
2830
2831 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2832 if (ret == NULL) {
2833 xmlGenericError(xmlGenericErrorContext,
2834 "xmlXPathNewParserContext: out of memory\n");
2835 return(NULL);
2836 }
2837 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2838 ret->cur = ret->base = str;
2839 ret->context = ctxt;
2840
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002841 ret->comp = xmlXPathNewCompExpr();
2842 if (ret->comp == NULL) {
2843 xmlFree(ret->valueTab);
2844 xmlFree(ret);
2845 return(NULL);
2846 }
2847
2848 return(ret);
2849}
2850
2851/**
2852 * xmlXPathCompParserContext:
2853 * @comp: the XPath compiled expression
2854 * @ctxt: the XPath context
2855 *
2856 * Create a new xmlXPathParserContext when processing a compiled expression
2857 *
2858 * Returns the xmlXPathParserContext just allocated.
2859 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002860static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002861xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2862 xmlXPathParserContextPtr ret;
2863
2864 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2865 if (ret == NULL) {
2866 xmlGenericError(xmlGenericErrorContext,
2867 "xmlXPathNewParserContext: out of memory\n");
2868 return(NULL);
2869 }
2870 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2871
Owen Taylor3473f882001-02-23 17:55:21 +00002872 /* Allocate the value stack */
2873 ret->valueTab = (xmlXPathObjectPtr *)
2874 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002875 if (ret->valueTab == NULL) {
2876 xmlFree(ret);
2877 xmlGenericError(xmlGenericErrorContext,
2878 "xmlXPathNewParserContext: out of memory\n");
2879 return(NULL);
2880 }
Owen Taylor3473f882001-02-23 17:55:21 +00002881 ret->valueNr = 0;
2882 ret->valueMax = 10;
2883 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002884
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002885 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002886 ret->comp = comp;
2887
Owen Taylor3473f882001-02-23 17:55:21 +00002888 return(ret);
2889}
2890
2891/**
2892 * xmlXPathFreeParserContext:
2893 * @ctxt: the context to free
2894 *
2895 * Free up an xmlXPathParserContext
2896 */
2897void
2898xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2899 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002900 xmlFree(ctxt->valueTab);
2901 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002902 if (ctxt->comp)
2903 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002904 xmlFree(ctxt);
2905}
2906
2907/************************************************************************
2908 * *
2909 * The implicit core function library *
2910 * *
2911 ************************************************************************/
2912
Owen Taylor3473f882001-02-23 17:55:21 +00002913/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00002914 * xmlXPathNodeStringHash:
2915 * @node: a node pointer
2916 *
2917 * Function computing the beginning of the string value of the node,
2918 * used to speed up comparisons
2919 *
2920 * Returns an int usable as a hash
2921 */
2922static unsigned int
2923xmlXPathNodeValHash(xmlNodePtr node) {
2924 int len = 2;
2925 const xmlChar * string = NULL;
2926 xmlNodePtr tmp = NULL;
2927 unsigned int ret = 0;
2928
2929 if (node == NULL)
2930 return(0);
2931
2932
2933 switch (node->type) {
2934 case XML_COMMENT_NODE:
2935 case XML_PI_NODE:
2936 case XML_CDATA_SECTION_NODE:
2937 case XML_TEXT_NODE:
2938 string = node->content;
2939 if (string == NULL)
2940 return(0);
2941 if (string[0] == 0)
2942 return(0);
2943 return(((unsigned int) string[0]) +
2944 (((unsigned int) string[1]) << 8));
2945 case XML_NAMESPACE_DECL:
2946 string = ((xmlNsPtr)node)->href;
2947 if (string == NULL)
2948 return(0);
2949 if (string[0] == 0)
2950 return(0);
2951 return(((unsigned int) string[0]) +
2952 (((unsigned int) string[1]) << 8));
2953 case XML_ATTRIBUTE_NODE:
2954 tmp = ((xmlAttrPtr) node)->children;
2955 break;
2956 case XML_ELEMENT_NODE:
2957 tmp = node->children;
2958 break;
2959 default:
2960 return(0);
2961 }
2962 while (tmp != NULL) {
2963 switch (tmp->type) {
2964 case XML_COMMENT_NODE:
2965 case XML_PI_NODE:
2966 case XML_CDATA_SECTION_NODE:
2967 case XML_TEXT_NODE:
2968 string = tmp->content;
2969 break;
2970 case XML_NAMESPACE_DECL:
2971 string = ((xmlNsPtr)tmp)->href;
2972 break;
2973 default:
2974 break;
2975 }
2976 if ((string != NULL) && (string[0] != 0)) {
2977 if (string[0] == 0)
2978 return(0);
2979 if (len == 1) {
2980 return(ret + (((unsigned int) string[0]) << 8));
2981 }
2982 if (string[1] == 0) {
2983 len = 1;
2984 ret = (unsigned int) string[0];
2985 } else {
2986 return(((unsigned int) string[0]) +
2987 (((unsigned int) string[1]) << 8));
2988 }
2989 }
2990 /*
2991 * Skip to next node
2992 */
2993 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
2994 if (tmp->children->type != XML_ENTITY_DECL) {
2995 tmp = tmp->children;
2996 continue;
2997 }
2998 }
2999 if (tmp == node)
3000 break;
3001
3002 if (tmp->next != NULL) {
3003 tmp = tmp->next;
3004 continue;
3005 }
3006
3007 do {
3008 tmp = tmp->parent;
3009 if (tmp == NULL)
3010 break;
3011 if (tmp == node) {
3012 tmp = NULL;
3013 break;
3014 }
3015 if (tmp->next != NULL) {
3016 tmp = tmp->next;
3017 break;
3018 }
3019 } while (tmp != NULL);
3020 }
3021 return(ret);
3022}
3023
3024/**
3025 * xmlXPathStringHash:
3026 * @string: a string
3027 *
3028 * Function computing the beginning of the string value of the node,
3029 * used to speed up comparisons
3030 *
3031 * Returns an int usable as a hash
3032 */
3033static unsigned int
3034xmlXPathStringHash(const xmlChar * string) {
3035 if (string == NULL)
3036 return((unsigned int) 0);
3037 if (string[0] == 0)
3038 return(0);
3039 return(((unsigned int) string[0]) +
3040 (((unsigned int) string[1]) << 8));
3041}
3042
3043/**
Owen Taylor3473f882001-02-23 17:55:21 +00003044 * xmlXPathCompareNodeSetFloat:
3045 * @ctxt: the XPath Parser context
3046 * @inf: less than (1) or greater than (0)
3047 * @strict: is the comparison strict
3048 * @arg: the node set
3049 * @f: the value
3050 *
3051 * Implement the compare operation between a nodeset and a number
3052 * @ns < @val (1, 1, ...
3053 * @ns <= @val (1, 0, ...
3054 * @ns > @val (0, 1, ...
3055 * @ns >= @val (0, 0, ...
3056 *
3057 * If one object to be compared is a node-set and the other is a number,
3058 * then the comparison will be true if and only if there is a node in the
3059 * node-set such that the result of performing the comparison on the number
3060 * to be compared and on the result of converting the string-value of that
3061 * node to a number using the number function is true.
3062 *
3063 * Returns 0 or 1 depending on the results of the test.
3064 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003065static int
Owen Taylor3473f882001-02-23 17:55:21 +00003066xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3067 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3068 int i, ret = 0;
3069 xmlNodeSetPtr ns;
3070 xmlChar *str2;
3071
3072 if ((f == NULL) || (arg == NULL) ||
3073 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3074 xmlXPathFreeObject(arg);
3075 xmlXPathFreeObject(f);
3076 return(0);
3077 }
3078 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003079 if (ns != NULL) {
3080 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003081 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003082 if (str2 != NULL) {
3083 valuePush(ctxt,
3084 xmlXPathNewString(str2));
3085 xmlFree(str2);
3086 xmlXPathNumberFunction(ctxt, 1);
3087 valuePush(ctxt, xmlXPathObjectCopy(f));
3088 ret = xmlXPathCompareValues(ctxt, inf, strict);
3089 if (ret)
3090 break;
3091 }
3092 }
Owen Taylor3473f882001-02-23 17:55:21 +00003093 }
3094 xmlXPathFreeObject(arg);
3095 xmlXPathFreeObject(f);
3096 return(ret);
3097}
3098
3099/**
3100 * xmlXPathCompareNodeSetString:
3101 * @ctxt: the XPath Parser context
3102 * @inf: less than (1) or greater than (0)
3103 * @strict: is the comparison strict
3104 * @arg: the node set
3105 * @s: the value
3106 *
3107 * Implement the compare operation between a nodeset and a string
3108 * @ns < @val (1, 1, ...
3109 * @ns <= @val (1, 0, ...
3110 * @ns > @val (0, 1, ...
3111 * @ns >= @val (0, 0, ...
3112 *
3113 * If one object to be compared is a node-set and the other is a string,
3114 * then the comparison will be true if and only if there is a node in
3115 * the node-set such that the result of performing the comparison on the
3116 * string-value of the node and the other string is true.
3117 *
3118 * Returns 0 or 1 depending on the results of the test.
3119 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003120static int
Owen Taylor3473f882001-02-23 17:55:21 +00003121xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3122 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3123 int i, ret = 0;
3124 xmlNodeSetPtr ns;
3125 xmlChar *str2;
3126
3127 if ((s == NULL) || (arg == NULL) ||
3128 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3129 xmlXPathFreeObject(arg);
3130 xmlXPathFreeObject(s);
3131 return(0);
3132 }
3133 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003134 if (ns != NULL) {
3135 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003136 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003137 if (str2 != NULL) {
3138 valuePush(ctxt,
3139 xmlXPathNewString(str2));
3140 xmlFree(str2);
3141 valuePush(ctxt, xmlXPathObjectCopy(s));
3142 ret = xmlXPathCompareValues(ctxt, inf, strict);
3143 if (ret)
3144 break;
3145 }
3146 }
Owen Taylor3473f882001-02-23 17:55:21 +00003147 }
3148 xmlXPathFreeObject(arg);
3149 xmlXPathFreeObject(s);
3150 return(ret);
3151}
3152
3153/**
3154 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003155 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003156 * @strict: is the comparison strict
3157 * @arg1: the fist node set object
3158 * @arg2: the second node set object
3159 *
3160 * Implement the compare operation on nodesets:
3161 *
3162 * If both objects to be compared are node-sets, then the comparison
3163 * will be true if and only if there is a node in the first node-set
3164 * and a node in the second node-set such that the result of performing
3165 * the comparison on the string-values of the two nodes is true.
3166 * ....
3167 * When neither object to be compared is a node-set and the operator
3168 * is <=, <, >= or >, then the objects are compared by converting both
3169 * objects to numbers and comparing the numbers according to IEEE 754.
3170 * ....
3171 * The number function converts its argument to a number as follows:
3172 * - a string that consists of optional whitespace followed by an
3173 * optional minus sign followed by a Number followed by whitespace
3174 * is converted to the IEEE 754 number that is nearest (according
3175 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3176 * represented by the string; any other string is converted to NaN
3177 *
3178 * Conclusion all nodes need to be converted first to their string value
3179 * and then the comparison must be done when possible
3180 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003181static int
3182xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003183 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3184 int i, j, init = 0;
3185 double val1;
3186 double *values2;
3187 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003188 xmlNodeSetPtr ns1;
3189 xmlNodeSetPtr ns2;
3190
3191 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003192 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3193 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003194 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003195 }
Owen Taylor3473f882001-02-23 17:55:21 +00003196 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003197 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3198 xmlXPathFreeObject(arg1);
3199 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003200 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003201 }
Owen Taylor3473f882001-02-23 17:55:21 +00003202
3203 ns1 = arg1->nodesetval;
3204 ns2 = arg2->nodesetval;
3205
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003206 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003207 xmlXPathFreeObject(arg1);
3208 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003209 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003210 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003211 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003212 xmlXPathFreeObject(arg1);
3213 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003214 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003215 }
Owen Taylor3473f882001-02-23 17:55:21 +00003216
3217 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3218 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003219 xmlXPathFreeObject(arg1);
3220 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003221 return(0);
3222 }
3223 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003224 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003225 if (isnan(val1))
3226 continue;
3227 for (j = 0;j < ns2->nodeNr;j++) {
3228 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003229 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003230 }
3231 if (isnan(values2[j]))
3232 continue;
3233 if (inf && strict)
3234 ret = (val1 < values2[j]);
3235 else if (inf && !strict)
3236 ret = (val1 <= values2[j]);
3237 else if (!inf && strict)
3238 ret = (val1 > values2[j]);
3239 else if (!inf && !strict)
3240 ret = (val1 >= values2[j]);
3241 if (ret)
3242 break;
3243 }
3244 if (ret)
3245 break;
3246 init = 1;
3247 }
3248 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003249 xmlXPathFreeObject(arg1);
3250 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003251 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003252}
3253
3254/**
3255 * xmlXPathCompareNodeSetValue:
3256 * @ctxt: the XPath Parser context
3257 * @inf: less than (1) or greater than (0)
3258 * @strict: is the comparison strict
3259 * @arg: the node set
3260 * @val: the value
3261 *
3262 * Implement the compare operation between a nodeset and a value
3263 * @ns < @val (1, 1, ...
3264 * @ns <= @val (1, 0, ...
3265 * @ns > @val (0, 1, ...
3266 * @ns >= @val (0, 0, ...
3267 *
3268 * If one object to be compared is a node-set and the other is a boolean,
3269 * then the comparison will be true if and only if the result of performing
3270 * the comparison on the boolean and on the result of converting
3271 * the node-set to a boolean using the boolean function is true.
3272 *
3273 * Returns 0 or 1 depending on the results of the test.
3274 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003275static int
Owen Taylor3473f882001-02-23 17:55:21 +00003276xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3277 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3278 if ((val == NULL) || (arg == NULL) ||
3279 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3280 return(0);
3281
3282 switch(val->type) {
3283 case XPATH_NUMBER:
3284 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3285 case XPATH_NODESET:
3286 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003287 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003288 case XPATH_STRING:
3289 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3290 case XPATH_BOOLEAN:
3291 valuePush(ctxt, arg);
3292 xmlXPathBooleanFunction(ctxt, 1);
3293 valuePush(ctxt, val);
3294 return(xmlXPathCompareValues(ctxt, inf, strict));
3295 default:
3296 TODO
3297 return(0);
3298 }
3299 return(0);
3300}
3301
3302/**
3303 * xmlXPathEqualNodeSetString
3304 * @arg: the nodeset object argument
3305 * @str: the string to compare to.
3306 *
3307 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3308 * If one object to be compared is a node-set and the other is a string,
3309 * then the comparison will be true if and only if there is a node in
3310 * the node-set such that the result of performing the comparison on the
3311 * string-value of the node and the other string is true.
3312 *
3313 * Returns 0 or 1 depending on the results of the test.
3314 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003315static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003316xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3317{
Owen Taylor3473f882001-02-23 17:55:21 +00003318 int i;
3319 xmlNodeSetPtr ns;
3320 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003321 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003322
3323 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003324 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3325 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003326 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003327 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003328 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003329 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003330 if (ns->nodeNr <= 0) {
3331 if (hash == 0)
3332 return(1);
3333 return(0);
3334 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003335 for (i = 0; i < ns->nodeNr; i++) {
3336 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3337 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3338 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3339 xmlFree(str2);
3340 return (1);
3341 }
3342 if (str2 != NULL)
3343 xmlFree(str2);
3344 }
Owen Taylor3473f882001-02-23 17:55:21 +00003345 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003346 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003347}
3348
3349/**
3350 * xmlXPathEqualNodeSetFloat
3351 * @arg: the nodeset object argument
3352 * @f: the float to compare to
3353 *
3354 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3355 * If one object to be compared is a node-set and the other is a number,
3356 * then the comparison will be true if and only if there is a node in
3357 * the node-set such that the result of performing the comparison on the
3358 * number to be compared and on the result of converting the string-value
3359 * of that node to a number using the number function is true.
3360 *
3361 * Returns 0 or 1 depending on the results of the test.
3362 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003363static int
Owen Taylor3473f882001-02-23 17:55:21 +00003364xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3365 char buf[100] = "";
3366
3367 if ((arg == NULL) ||
3368 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3369 return(0);
3370
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003371 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003372 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3373}
3374
3375
3376/**
3377 * xmlXPathEqualNodeSets
3378 * @arg1: first nodeset object argument
3379 * @arg2: second nodeset object argument
3380 *
3381 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3382 * If both objects to be compared are node-sets, then the comparison
3383 * will be true if and only if there is a node in the first node-set and
3384 * a node in the second node-set such that the result of performing the
3385 * comparison on the string-values of the two nodes is true.
3386 *
3387 * (needless to say, this is a costly operation)
3388 *
3389 * Returns 0 or 1 depending on the results of the test.
3390 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003391static int
Owen Taylor3473f882001-02-23 17:55:21 +00003392xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3393 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003394 unsigned int *hashs1;
3395 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003396 xmlChar **values1;
3397 xmlChar **values2;
3398 int ret = 0;
3399 xmlNodeSetPtr ns1;
3400 xmlNodeSetPtr ns2;
3401
3402 if ((arg1 == NULL) ||
3403 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3404 return(0);
3405 if ((arg2 == NULL) ||
3406 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3407 return(0);
3408
3409 ns1 = arg1->nodesetval;
3410 ns2 = arg2->nodesetval;
3411
Daniel Veillard911f49a2001-04-07 15:39:35 +00003412 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003413 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003414 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003415 return(0);
3416
3417 /*
3418 * check if there is a node pertaining to both sets
3419 */
3420 for (i = 0;i < ns1->nodeNr;i++)
3421 for (j = 0;j < ns2->nodeNr;j++)
3422 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3423 return(1);
3424
3425 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3426 if (values1 == NULL)
3427 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003428 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3429 if (hashs1 == NULL) {
3430 xmlFree(values1);
3431 return(0);
3432 }
Owen Taylor3473f882001-02-23 17:55:21 +00003433 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3434 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3435 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003436 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003437 xmlFree(values1);
3438 return(0);
3439 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003440 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3441 if (hashs2 == NULL) {
3442 xmlFree(hashs1);
3443 xmlFree(values1);
3444 xmlFree(values2);
3445 return(0);
3446 }
Owen Taylor3473f882001-02-23 17:55:21 +00003447 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3448 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003449 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003450 for (j = 0;j < ns2->nodeNr;j++) {
3451 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003452 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
3453 if (hashs1[i] == hashs2[j]) {
3454 if (values1[i] == NULL)
3455 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3456 if (values2[j] == NULL)
3457 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3458 ret = xmlStrEqual(values1[i], values2[j]);
3459 if (ret)
3460 break;
3461 }
Owen Taylor3473f882001-02-23 17:55:21 +00003462 }
3463 if (ret)
3464 break;
3465 }
3466 for (i = 0;i < ns1->nodeNr;i++)
3467 if (values1[i] != NULL)
3468 xmlFree(values1[i]);
3469 for (j = 0;j < ns2->nodeNr;j++)
3470 if (values2[j] != NULL)
3471 xmlFree(values2[j]);
3472 xmlFree(values1);
3473 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003474 xmlFree(hashs1);
3475 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00003476 return(ret);
3477}
3478
3479/**
3480 * xmlXPathEqualValues:
3481 * @ctxt: the XPath Parser context
3482 *
3483 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3484 *
3485 * Returns 0 or 1 depending on the results of the test.
3486 */
3487int
3488xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
3489 xmlXPathObjectPtr arg1, arg2;
3490 int ret = 0;
3491
3492 arg1 = valuePop(ctxt);
3493 if (arg1 == NULL)
3494 XP_ERROR0(XPATH_INVALID_OPERAND);
3495
3496 arg2 = valuePop(ctxt);
3497 if (arg2 == NULL) {
3498 xmlXPathFreeObject(arg1);
3499 XP_ERROR0(XPATH_INVALID_OPERAND);
3500 }
3501
3502 if (arg1 == arg2) {
3503#ifdef DEBUG_EXPR
3504 xmlGenericError(xmlGenericErrorContext,
3505 "Equal: by pointer\n");
3506#endif
3507 return(1);
3508 }
3509
3510 switch (arg1->type) {
3511 case XPATH_UNDEFINED:
3512#ifdef DEBUG_EXPR
3513 xmlGenericError(xmlGenericErrorContext,
3514 "Equal: undefined\n");
3515#endif
3516 break;
3517 case XPATH_XSLT_TREE:
3518 case XPATH_NODESET:
3519 switch (arg2->type) {
3520 case XPATH_UNDEFINED:
3521#ifdef DEBUG_EXPR
3522 xmlGenericError(xmlGenericErrorContext,
3523 "Equal: undefined\n");
3524#endif
3525 break;
3526 case XPATH_XSLT_TREE:
3527 case XPATH_NODESET:
3528 ret = xmlXPathEqualNodeSets(arg1, arg2);
3529 break;
3530 case XPATH_BOOLEAN:
3531 if ((arg1->nodesetval == NULL) ||
3532 (arg1->nodesetval->nodeNr == 0)) ret = 0;
3533 else
3534 ret = 1;
3535 ret = (ret == arg2->boolval);
3536 break;
3537 case XPATH_NUMBER:
3538 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
3539 break;
3540 case XPATH_STRING:
3541 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
3542 break;
3543 case XPATH_USERS:
3544 case XPATH_POINT:
3545 case XPATH_RANGE:
3546 case XPATH_LOCATIONSET:
3547 TODO
3548 break;
3549 }
3550 break;
3551 case XPATH_BOOLEAN:
3552 switch (arg2->type) {
3553 case XPATH_UNDEFINED:
3554#ifdef DEBUG_EXPR
3555 xmlGenericError(xmlGenericErrorContext,
3556 "Equal: undefined\n");
3557#endif
3558 break;
3559 case XPATH_NODESET:
3560 case XPATH_XSLT_TREE:
3561 if ((arg2->nodesetval == NULL) ||
3562 (arg2->nodesetval->nodeNr == 0)) ret = 0;
3563 else
3564 ret = 1;
3565 break;
3566 case XPATH_BOOLEAN:
3567#ifdef DEBUG_EXPR
3568 xmlGenericError(xmlGenericErrorContext,
3569 "Equal: %d boolean %d \n",
3570 arg1->boolval, arg2->boolval);
3571#endif
3572 ret = (arg1->boolval == arg2->boolval);
3573 break;
3574 case XPATH_NUMBER:
3575 if (arg2->floatval) ret = 1;
3576 else ret = 0;
3577 ret = (arg1->boolval == ret);
3578 break;
3579 case XPATH_STRING:
3580 if ((arg2->stringval == NULL) ||
3581 (arg2->stringval[0] == 0)) ret = 0;
3582 else
3583 ret = 1;
3584 ret = (arg1->boolval == ret);
3585 break;
3586 case XPATH_USERS:
3587 case XPATH_POINT:
3588 case XPATH_RANGE:
3589 case XPATH_LOCATIONSET:
3590 TODO
3591 break;
3592 }
3593 break;
3594 case XPATH_NUMBER:
3595 switch (arg2->type) {
3596 case XPATH_UNDEFINED:
3597#ifdef DEBUG_EXPR
3598 xmlGenericError(xmlGenericErrorContext,
3599 "Equal: undefined\n");
3600#endif
3601 break;
3602 case XPATH_NODESET:
3603 case XPATH_XSLT_TREE:
3604 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
3605 break;
3606 case XPATH_BOOLEAN:
3607 if (arg1->floatval) ret = 1;
3608 else ret = 0;
3609 ret = (arg2->boolval == ret);
3610 break;
3611 case XPATH_STRING:
3612 valuePush(ctxt, arg2);
3613 xmlXPathNumberFunction(ctxt, 1);
3614 arg2 = valuePop(ctxt);
3615 /* no break on purpose */
3616 case XPATH_NUMBER:
3617 ret = (arg1->floatval == arg2->floatval);
3618 break;
3619 case XPATH_USERS:
3620 case XPATH_POINT:
3621 case XPATH_RANGE:
3622 case XPATH_LOCATIONSET:
3623 TODO
3624 break;
3625 }
3626 break;
3627 case XPATH_STRING:
3628 switch (arg2->type) {
3629 case XPATH_UNDEFINED:
3630#ifdef DEBUG_EXPR
3631 xmlGenericError(xmlGenericErrorContext,
3632 "Equal: undefined\n");
3633#endif
3634 break;
3635 case XPATH_NODESET:
3636 case XPATH_XSLT_TREE:
3637 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
3638 break;
3639 case XPATH_BOOLEAN:
3640 if ((arg1->stringval == NULL) ||
3641 (arg1->stringval[0] == 0)) ret = 0;
3642 else
3643 ret = 1;
3644 ret = (arg2->boolval == ret);
3645 break;
3646 case XPATH_STRING:
3647 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
3648 break;
3649 case XPATH_NUMBER:
3650 valuePush(ctxt, arg1);
3651 xmlXPathNumberFunction(ctxt, 1);
3652 arg1 = valuePop(ctxt);
3653 ret = (arg1->floatval == arg2->floatval);
3654 break;
3655 case XPATH_USERS:
3656 case XPATH_POINT:
3657 case XPATH_RANGE:
3658 case XPATH_LOCATIONSET:
3659 TODO
3660 break;
3661 }
3662 break;
3663 case XPATH_USERS:
3664 case XPATH_POINT:
3665 case XPATH_RANGE:
3666 case XPATH_LOCATIONSET:
3667 TODO
3668 break;
3669 }
3670 xmlXPathFreeObject(arg1);
3671 xmlXPathFreeObject(arg2);
3672 return(ret);
3673}
3674
3675
3676/**
3677 * xmlXPathCompareValues:
3678 * @ctxt: the XPath Parser context
3679 * @inf: less than (1) or greater than (0)
3680 * @strict: is the comparison strict
3681 *
3682 * Implement the compare operation on XPath objects:
3683 * @arg1 < @arg2 (1, 1, ...
3684 * @arg1 <= @arg2 (1, 0, ...
3685 * @arg1 > @arg2 (0, 1, ...
3686 * @arg1 >= @arg2 (0, 0, ...
3687 *
3688 * When neither object to be compared is a node-set and the operator is
3689 * <=, <, >=, >, then the objects are compared by converted both objects
3690 * to numbers and comparing the numbers according to IEEE 754. The <
3691 * comparison will be true if and only if the first number is less than the
3692 * second number. The <= comparison will be true if and only if the first
3693 * number is less than or equal to the second number. The > comparison
3694 * will be true if and only if the first number is greater than the second
3695 * number. The >= comparison will be true if and only if the first number
3696 * is greater than or equal to the second number.
3697 *
3698 * Returns 1 if the comparaison succeeded, 0 if it failed
3699 */
3700int
3701xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3702 int ret = 0;
3703 xmlXPathObjectPtr arg1, arg2;
3704
3705 arg2 = valuePop(ctxt);
3706 if (arg2 == NULL) {
3707 XP_ERROR0(XPATH_INVALID_OPERAND);
3708 }
3709
3710 arg1 = valuePop(ctxt);
3711 if (arg1 == NULL) {
3712 xmlXPathFreeObject(arg2);
3713 XP_ERROR0(XPATH_INVALID_OPERAND);
3714 }
3715
3716 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3717 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003718 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003719 } else {
3720 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003721 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3722 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003723 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003724 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3725 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003726 }
3727 }
3728 return(ret);
3729 }
3730
3731 if (arg1->type != XPATH_NUMBER) {
3732 valuePush(ctxt, arg1);
3733 xmlXPathNumberFunction(ctxt, 1);
3734 arg1 = valuePop(ctxt);
3735 }
3736 if (arg1->type != XPATH_NUMBER) {
3737 xmlXPathFreeObject(arg1);
3738 xmlXPathFreeObject(arg2);
3739 XP_ERROR0(XPATH_INVALID_OPERAND);
3740 }
3741 if (arg2->type != XPATH_NUMBER) {
3742 valuePush(ctxt, arg2);
3743 xmlXPathNumberFunction(ctxt, 1);
3744 arg2 = valuePop(ctxt);
3745 }
3746 if (arg2->type != XPATH_NUMBER) {
3747 xmlXPathFreeObject(arg1);
3748 xmlXPathFreeObject(arg2);
3749 XP_ERROR0(XPATH_INVALID_OPERAND);
3750 }
3751 /*
3752 * Add tests for infinity and nan
3753 * => feedback on 3.4 for Inf and NaN
3754 */
3755 if (inf && strict)
3756 ret = (arg1->floatval < arg2->floatval);
3757 else if (inf && !strict)
3758 ret = (arg1->floatval <= arg2->floatval);
3759 else if (!inf && strict)
3760 ret = (arg1->floatval > arg2->floatval);
3761 else if (!inf && !strict)
3762 ret = (arg1->floatval >= arg2->floatval);
3763 xmlXPathFreeObject(arg1);
3764 xmlXPathFreeObject(arg2);
3765 return(ret);
3766}
3767
3768/**
3769 * xmlXPathValueFlipSign:
3770 * @ctxt: the XPath Parser context
3771 *
3772 * Implement the unary - operation on an XPath object
3773 * The numeric operators convert their operands to numbers as if
3774 * by calling the number function.
3775 */
3776void
3777xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003778 CAST_TO_NUMBER;
3779 CHECK_TYPE(XPATH_NUMBER);
3780 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00003781}
3782
3783/**
3784 * xmlXPathAddValues:
3785 * @ctxt: the XPath Parser context
3786 *
3787 * Implement the add operation on XPath objects:
3788 * The numeric operators convert their operands to numbers as if
3789 * by calling the number function.
3790 */
3791void
3792xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3793 xmlXPathObjectPtr arg;
3794 double val;
3795
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003796 arg = valuePop(ctxt);
3797 if (arg == NULL)
3798 XP_ERROR(XPATH_INVALID_OPERAND);
3799 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003800 xmlXPathFreeObject(arg);
3801
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003802 CAST_TO_NUMBER;
3803 CHECK_TYPE(XPATH_NUMBER);
3804 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00003805}
3806
3807/**
3808 * xmlXPathSubValues:
3809 * @ctxt: the XPath Parser context
3810 *
3811 * Implement the substraction operation on XPath objects:
3812 * The numeric operators convert their operands to numbers as if
3813 * by calling the number function.
3814 */
3815void
3816xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3817 xmlXPathObjectPtr arg;
3818 double val;
3819
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003820 arg = valuePop(ctxt);
3821 if (arg == NULL)
3822 XP_ERROR(XPATH_INVALID_OPERAND);
3823 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003824 xmlXPathFreeObject(arg);
3825
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003826 CAST_TO_NUMBER;
3827 CHECK_TYPE(XPATH_NUMBER);
3828 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003829}
3830
3831/**
3832 * xmlXPathMultValues:
3833 * @ctxt: the XPath Parser context
3834 *
3835 * Implement the multiply operation on XPath objects:
3836 * The numeric operators convert their operands to numbers as if
3837 * by calling the number function.
3838 */
3839void
3840xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3841 xmlXPathObjectPtr arg;
3842 double val;
3843
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003844 arg = valuePop(ctxt);
3845 if (arg == NULL)
3846 XP_ERROR(XPATH_INVALID_OPERAND);
3847 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003848 xmlXPathFreeObject(arg);
3849
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003850 CAST_TO_NUMBER;
3851 CHECK_TYPE(XPATH_NUMBER);
3852 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003853}
3854
3855/**
3856 * xmlXPathDivValues:
3857 * @ctxt: the XPath Parser context
3858 *
3859 * Implement the div operation on XPath objects @arg1 / @arg2:
3860 * The numeric operators convert their operands to numbers as if
3861 * by calling the number function.
3862 */
3863void
3864xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3865 xmlXPathObjectPtr arg;
3866 double val;
3867
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003868 arg = valuePop(ctxt);
3869 if (arg == NULL)
3870 XP_ERROR(XPATH_INVALID_OPERAND);
3871 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003872 xmlXPathFreeObject(arg);
3873
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003874 CAST_TO_NUMBER;
3875 CHECK_TYPE(XPATH_NUMBER);
3876 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003877}
3878
3879/**
3880 * xmlXPathModValues:
3881 * @ctxt: the XPath Parser context
3882 *
3883 * Implement the mod operation on XPath objects: @arg1 / @arg2
3884 * The numeric operators convert their operands to numbers as if
3885 * by calling the number function.
3886 */
3887void
3888xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3889 xmlXPathObjectPtr arg;
3890 int arg1, arg2;
3891
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003892 arg = valuePop(ctxt);
3893 if (arg == NULL)
3894 XP_ERROR(XPATH_INVALID_OPERAND);
3895 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003896 xmlXPathFreeObject(arg);
3897
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003898 CAST_TO_NUMBER;
3899 CHECK_TYPE(XPATH_NUMBER);
3900 arg1 = (int) ctxt->value->floatval;
3901 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00003902}
3903
3904/************************************************************************
3905 * *
3906 * The traversal functions *
3907 * *
3908 ************************************************************************/
3909
Owen Taylor3473f882001-02-23 17:55:21 +00003910/*
3911 * A traversal function enumerates nodes along an axis.
3912 * Initially it must be called with NULL, and it indicates
3913 * termination on the axis by returning NULL.
3914 */
3915typedef xmlNodePtr (*xmlXPathTraversalFunction)
3916 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3917
3918/**
3919 * xmlXPathNextSelf:
3920 * @ctxt: the XPath Parser context
3921 * @cur: the current node in the traversal
3922 *
3923 * Traversal function for the "self" direction
3924 * The self axis contains just the context node itself
3925 *
3926 * Returns the next element following that axis
3927 */
3928xmlNodePtr
3929xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3930 if (cur == NULL)
3931 return(ctxt->context->node);
3932 return(NULL);
3933}
3934
3935/**
3936 * xmlXPathNextChild:
3937 * @ctxt: the XPath Parser context
3938 * @cur: the current node in the traversal
3939 *
3940 * Traversal function for the "child" direction
3941 * The child axis contains the children of the context node in document order.
3942 *
3943 * Returns the next element following that axis
3944 */
3945xmlNodePtr
3946xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3947 if (cur == NULL) {
3948 if (ctxt->context->node == NULL) return(NULL);
3949 switch (ctxt->context->node->type) {
3950 case XML_ELEMENT_NODE:
3951 case XML_TEXT_NODE:
3952 case XML_CDATA_SECTION_NODE:
3953 case XML_ENTITY_REF_NODE:
3954 case XML_ENTITY_NODE:
3955 case XML_PI_NODE:
3956 case XML_COMMENT_NODE:
3957 case XML_NOTATION_NODE:
3958 case XML_DTD_NODE:
3959 return(ctxt->context->node->children);
3960 case XML_DOCUMENT_NODE:
3961 case XML_DOCUMENT_TYPE_NODE:
3962 case XML_DOCUMENT_FRAG_NODE:
3963 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003964#ifdef LIBXML_DOCB_ENABLED
3965 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003966#endif
3967 return(((xmlDocPtr) ctxt->context->node)->children);
3968 case XML_ELEMENT_DECL:
3969 case XML_ATTRIBUTE_DECL:
3970 case XML_ENTITY_DECL:
3971 case XML_ATTRIBUTE_NODE:
3972 case XML_NAMESPACE_DECL:
3973 case XML_XINCLUDE_START:
3974 case XML_XINCLUDE_END:
3975 return(NULL);
3976 }
3977 return(NULL);
3978 }
3979 if ((cur->type == XML_DOCUMENT_NODE) ||
3980 (cur->type == XML_HTML_DOCUMENT_NODE))
3981 return(NULL);
3982 return(cur->next);
3983}
3984
3985/**
3986 * xmlXPathNextDescendant:
3987 * @ctxt: the XPath Parser context
3988 * @cur: the current node in the traversal
3989 *
3990 * Traversal function for the "descendant" direction
3991 * the descendant axis contains the descendants of the context node in document
3992 * order; a descendant is a child or a child of a child and so on.
3993 *
3994 * Returns the next element following that axis
3995 */
3996xmlNodePtr
3997xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3998 if (cur == NULL) {
3999 if (ctxt->context->node == NULL)
4000 return(NULL);
4001 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4002 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4003 return(NULL);
4004
4005 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4006 return(ctxt->context->doc->children);
4007 return(ctxt->context->node->children);
4008 }
4009
4010 if (cur->children != NULL)
4011 {
4012 if (cur->children->type != XML_ENTITY_DECL)
4013 return(cur->children);
4014 }
4015 if (cur->next != NULL) return(cur->next);
4016
4017 do {
4018 cur = cur->parent;
4019 if (cur == NULL) return(NULL);
4020 if (cur == ctxt->context->node) return(NULL);
4021 if (cur->next != NULL) {
4022 cur = cur->next;
4023 return(cur);
4024 }
4025 } while (cur != NULL);
4026 return(cur);
4027}
4028
4029/**
4030 * xmlXPathNextDescendantOrSelf:
4031 * @ctxt: the XPath Parser context
4032 * @cur: the current node in the traversal
4033 *
4034 * Traversal function for the "descendant-or-self" direction
4035 * the descendant-or-self axis contains the context node and the descendants
4036 * of the context node in document order; thus the context node is the first
4037 * node on the axis, and the first child of the context node is the second node
4038 * on the axis
4039 *
4040 * Returns the next element following that axis
4041 */
4042xmlNodePtr
4043xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4044 if (cur == NULL) {
4045 if (ctxt->context->node == NULL)
4046 return(NULL);
4047 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4048 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4049 return(NULL);
4050 return(ctxt->context->node);
4051 }
4052
4053 return(xmlXPathNextDescendant(ctxt, cur));
4054}
4055
4056/**
4057 * xmlXPathNextParent:
4058 * @ctxt: the XPath Parser context
4059 * @cur: the current node in the traversal
4060 *
4061 * Traversal function for the "parent" direction
4062 * The parent axis contains the parent of the context node, if there is one.
4063 *
4064 * Returns the next element following that axis
4065 */
4066xmlNodePtr
4067xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4068 /*
4069 * the parent of an attribute or namespace node is the element
4070 * to which the attribute or namespace node is attached
4071 * Namespace handling !!!
4072 */
4073 if (cur == NULL) {
4074 if (ctxt->context->node == NULL) return(NULL);
4075 switch (ctxt->context->node->type) {
4076 case XML_ELEMENT_NODE:
4077 case XML_TEXT_NODE:
4078 case XML_CDATA_SECTION_NODE:
4079 case XML_ENTITY_REF_NODE:
4080 case XML_ENTITY_NODE:
4081 case XML_PI_NODE:
4082 case XML_COMMENT_NODE:
4083 case XML_NOTATION_NODE:
4084 case XML_DTD_NODE:
4085 case XML_ELEMENT_DECL:
4086 case XML_ATTRIBUTE_DECL:
4087 case XML_XINCLUDE_START:
4088 case XML_XINCLUDE_END:
4089 case XML_ENTITY_DECL:
4090 if (ctxt->context->node->parent == NULL)
4091 return((xmlNodePtr) ctxt->context->doc);
4092 return(ctxt->context->node->parent);
4093 case XML_ATTRIBUTE_NODE: {
4094 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4095
4096 return(att->parent);
4097 }
4098 case XML_DOCUMENT_NODE:
4099 case XML_DOCUMENT_TYPE_NODE:
4100 case XML_DOCUMENT_FRAG_NODE:
4101 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004102#ifdef LIBXML_DOCB_ENABLED
4103 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004104#endif
4105 return(NULL);
4106 case XML_NAMESPACE_DECL:
4107 /*
4108 * TODO !!! may require extending struct _xmlNs with
4109 * parent field
4110 * C.f. Infoset case...
4111 */
4112 return(NULL);
4113 }
4114 }
4115 return(NULL);
4116}
4117
4118/**
4119 * xmlXPathNextAncestor:
4120 * @ctxt: the XPath Parser context
4121 * @cur: the current node in the traversal
4122 *
4123 * Traversal function for the "ancestor" direction
4124 * the ancestor axis contains the ancestors of the context node; the ancestors
4125 * of the context node consist of the parent of context node and the parent's
4126 * parent and so on; the nodes are ordered in reverse document order; thus the
4127 * parent is the first node on the axis, and the parent's parent is the second
4128 * node on the axis
4129 *
4130 * Returns the next element following that axis
4131 */
4132xmlNodePtr
4133xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4134 /*
4135 * the parent of an attribute or namespace node is the element
4136 * to which the attribute or namespace node is attached
4137 * !!!!!!!!!!!!!
4138 */
4139 if (cur == NULL) {
4140 if (ctxt->context->node == NULL) return(NULL);
4141 switch (ctxt->context->node->type) {
4142 case XML_ELEMENT_NODE:
4143 case XML_TEXT_NODE:
4144 case XML_CDATA_SECTION_NODE:
4145 case XML_ENTITY_REF_NODE:
4146 case XML_ENTITY_NODE:
4147 case XML_PI_NODE:
4148 case XML_COMMENT_NODE:
4149 case XML_DTD_NODE:
4150 case XML_ELEMENT_DECL:
4151 case XML_ATTRIBUTE_DECL:
4152 case XML_ENTITY_DECL:
4153 case XML_NOTATION_NODE:
4154 case XML_XINCLUDE_START:
4155 case XML_XINCLUDE_END:
4156 if (ctxt->context->node->parent == NULL)
4157 return((xmlNodePtr) ctxt->context->doc);
4158 return(ctxt->context->node->parent);
4159 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004160 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004161
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004162 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004163 }
4164 case XML_DOCUMENT_NODE:
4165 case XML_DOCUMENT_TYPE_NODE:
4166 case XML_DOCUMENT_FRAG_NODE:
4167 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004168#ifdef LIBXML_DOCB_ENABLED
4169 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004170#endif
4171 return(NULL);
4172 case XML_NAMESPACE_DECL:
4173 /*
4174 * TODO !!! may require extending struct _xmlNs with
4175 * parent field
4176 * C.f. Infoset case...
4177 */
4178 return(NULL);
4179 }
4180 return(NULL);
4181 }
4182 if (cur == ctxt->context->doc->children)
4183 return((xmlNodePtr) ctxt->context->doc);
4184 if (cur == (xmlNodePtr) ctxt->context->doc)
4185 return(NULL);
4186 switch (cur->type) {
4187 case XML_ELEMENT_NODE:
4188 case XML_TEXT_NODE:
4189 case XML_CDATA_SECTION_NODE:
4190 case XML_ENTITY_REF_NODE:
4191 case XML_ENTITY_NODE:
4192 case XML_PI_NODE:
4193 case XML_COMMENT_NODE:
4194 case XML_NOTATION_NODE:
4195 case XML_DTD_NODE:
4196 case XML_ELEMENT_DECL:
4197 case XML_ATTRIBUTE_DECL:
4198 case XML_ENTITY_DECL:
4199 case XML_XINCLUDE_START:
4200 case XML_XINCLUDE_END:
4201 return(cur->parent);
4202 case XML_ATTRIBUTE_NODE: {
4203 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4204
4205 return(att->parent);
4206 }
4207 case XML_DOCUMENT_NODE:
4208 case XML_DOCUMENT_TYPE_NODE:
4209 case XML_DOCUMENT_FRAG_NODE:
4210 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004211#ifdef LIBXML_DOCB_ENABLED
4212 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004213#endif
4214 return(NULL);
4215 case XML_NAMESPACE_DECL:
4216 /*
4217 * TODO !!! may require extending struct _xmlNs with
4218 * parent field
4219 * C.f. Infoset case...
4220 */
4221 return(NULL);
4222 }
4223 return(NULL);
4224}
4225
4226/**
4227 * xmlXPathNextAncestorOrSelf:
4228 * @ctxt: the XPath Parser context
4229 * @cur: the current node in the traversal
4230 *
4231 * Traversal function for the "ancestor-or-self" direction
4232 * he ancestor-or-self axis contains the context node and ancestors of
4233 * the context node in reverse document order; thus the context node is
4234 * the first node on the axis, and the context node's parent the second;
4235 * parent here is defined the same as with the parent axis.
4236 *
4237 * Returns the next element following that axis
4238 */
4239xmlNodePtr
4240xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4241 if (cur == NULL)
4242 return(ctxt->context->node);
4243 return(xmlXPathNextAncestor(ctxt, cur));
4244}
4245
4246/**
4247 * xmlXPathNextFollowingSibling:
4248 * @ctxt: the XPath Parser context
4249 * @cur: the current node in the traversal
4250 *
4251 * Traversal function for the "following-sibling" direction
4252 * The following-sibling axis contains the following siblings of the context
4253 * node in document order.
4254 *
4255 * Returns the next element following that axis
4256 */
4257xmlNodePtr
4258xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4259 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4260 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4261 return(NULL);
4262 if (cur == (xmlNodePtr) ctxt->context->doc)
4263 return(NULL);
4264 if (cur == NULL)
4265 return(ctxt->context->node->next);
4266 return(cur->next);
4267}
4268
4269/**
4270 * xmlXPathNextPrecedingSibling:
4271 * @ctxt: the XPath Parser context
4272 * @cur: the current node in the traversal
4273 *
4274 * Traversal function for the "preceding-sibling" direction
4275 * The preceding-sibling axis contains the preceding siblings of the context
4276 * node in reverse document order; the first preceding sibling is first on the
4277 * axis; the sibling preceding that node is the second on the axis and so on.
4278 *
4279 * Returns the next element following that axis
4280 */
4281xmlNodePtr
4282xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4283 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4284 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4285 return(NULL);
4286 if (cur == (xmlNodePtr) ctxt->context->doc)
4287 return(NULL);
4288 if (cur == NULL)
4289 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004290 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4291 cur = cur->prev;
4292 if (cur == NULL)
4293 return(ctxt->context->node->prev);
4294 }
Owen Taylor3473f882001-02-23 17:55:21 +00004295 return(cur->prev);
4296}
4297
4298/**
4299 * xmlXPathNextFollowing:
4300 * @ctxt: the XPath Parser context
4301 * @cur: the current node in the traversal
4302 *
4303 * Traversal function for the "following" direction
4304 * The following axis contains all nodes in the same document as the context
4305 * node that are after the context node in document order, excluding any
4306 * descendants and excluding attribute nodes and namespace nodes; the nodes
4307 * are ordered in document order
4308 *
4309 * Returns the next element following that axis
4310 */
4311xmlNodePtr
4312xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4313 if (cur != NULL && cur->children != NULL)
4314 return cur->children ;
4315 if (cur == NULL) cur = ctxt->context->node;
4316 if (cur == NULL) return(NULL) ; /* ERROR */
4317 if (cur->next != NULL) return(cur->next) ;
4318 do {
4319 cur = cur->parent;
4320 if (cur == NULL) return(NULL);
4321 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4322 if (cur->next != NULL) return(cur->next);
4323 } while (cur != NULL);
4324 return(cur);
4325}
4326
4327/*
4328 * xmlXPathIsAncestor:
4329 * @ancestor: the ancestor node
4330 * @node: the current node
4331 *
4332 * Check that @ancestor is a @node's ancestor
4333 *
4334 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4335 */
4336static int
4337xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4338 if ((ancestor == NULL) || (node == NULL)) return(0);
4339 /* nodes need to be in the same document */
4340 if (ancestor->doc != node->doc) return(0);
4341 /* avoid searching if ancestor or node is the root node */
4342 if (ancestor == (xmlNodePtr) node->doc) return(1);
4343 if (node == (xmlNodePtr) ancestor->doc) return(0);
4344 while (node->parent != NULL) {
4345 if (node->parent == ancestor)
4346 return(1);
4347 node = node->parent;
4348 }
4349 return(0);
4350}
4351
4352/**
4353 * xmlXPathNextPreceding:
4354 * @ctxt: the XPath Parser context
4355 * @cur: the current node in the traversal
4356 *
4357 * Traversal function for the "preceding" direction
4358 * the preceding axis contains all nodes in the same document as the context
4359 * node that are before the context node in document order, excluding any
4360 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4361 * ordered in reverse document order
4362 *
4363 * Returns the next element following that axis
4364 */
4365xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004366xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4367{
Owen Taylor3473f882001-02-23 17:55:21 +00004368 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004369 cur = ctxt->context->node;
4370 if (cur == NULL)
4371 return (NULL);
4372 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4373 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004374 do {
4375 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004376 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4377 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004378 }
4379
4380 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004381 if (cur == NULL)
4382 return (NULL);
4383 if (cur == ctxt->context->doc->children)
4384 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004385 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004386 return (cur);
4387}
4388
4389/**
4390 * xmlXPathNextPrecedingInternal:
4391 * @ctxt: the XPath Parser context
4392 * @cur: the current node in the traversal
4393 *
4394 * Traversal function for the "preceding" direction
4395 * the preceding axis contains all nodes in the same document as the context
4396 * node that are before the context node in document order, excluding any
4397 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4398 * ordered in reverse document order
4399 * This is a faster implementation but internal only since it requires a
4400 * state kept in the parser context: ctxt->ancestor.
4401 *
4402 * Returns the next element following that axis
4403 */
4404static xmlNodePtr
4405xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4406 xmlNodePtr cur)
4407{
4408 if (cur == NULL) {
4409 cur = ctxt->context->node;
4410 if (cur == NULL)
4411 return (NULL);
4412 ctxt->ancestor = cur->parent;
4413 }
4414 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4415 cur = cur->prev;
4416 while (cur->prev == NULL) {
4417 cur = cur->parent;
4418 if (cur == NULL)
4419 return (NULL);
4420 if (cur == ctxt->context->doc->children)
4421 return (NULL);
4422 if (cur != ctxt->ancestor)
4423 return (cur);
4424 ctxt->ancestor = cur->parent;
4425 }
4426 cur = cur->prev;
4427 while (cur->last != NULL)
4428 cur = cur->last;
4429 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004430}
4431
4432/**
4433 * xmlXPathNextNamespace:
4434 * @ctxt: the XPath Parser context
4435 * @cur: the current attribute in the traversal
4436 *
4437 * Traversal function for the "namespace" direction
4438 * the namespace axis contains the namespace nodes of the context node;
4439 * the order of nodes on this axis is implementation-defined; the axis will
4440 * be empty unless the context node is an element
4441 *
4442 * Returns the next element following that axis
4443 */
4444xmlNodePtr
4445xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4446 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
4447 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
4448 if (ctxt->context->namespaces != NULL)
4449 xmlFree(ctxt->context->namespaces);
4450 ctxt->context->namespaces =
4451 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
4452 if (ctxt->context->namespaces == NULL) return(NULL);
4453 ctxt->context->nsNr = 0;
4454 }
4455 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
4456}
4457
4458/**
4459 * xmlXPathNextAttribute:
4460 * @ctxt: the XPath Parser context
4461 * @cur: the current attribute in the traversal
4462 *
4463 * Traversal function for the "attribute" direction
4464 * TODO: support DTD inherited default attributes
4465 *
4466 * Returns the next element following that axis
4467 */
4468xmlNodePtr
4469xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00004470 if (ctxt->context->node == NULL)
4471 return(NULL);
4472 if (ctxt->context->node->type != XML_ELEMENT_NODE)
4473 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004474 if (cur == NULL) {
4475 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4476 return(NULL);
4477 return((xmlNodePtr)ctxt->context->node->properties);
4478 }
4479 return((xmlNodePtr)cur->next);
4480}
4481
4482/************************************************************************
4483 * *
4484 * NodeTest Functions *
4485 * *
4486 ************************************************************************/
4487
Owen Taylor3473f882001-02-23 17:55:21 +00004488#define IS_FUNCTION 200
4489
Owen Taylor3473f882001-02-23 17:55:21 +00004490
4491/************************************************************************
4492 * *
4493 * Implicit tree core function library *
4494 * *
4495 ************************************************************************/
4496
4497/**
4498 * xmlXPathRoot:
4499 * @ctxt: the XPath Parser context
4500 *
4501 * Initialize the context to the root of the document
4502 */
4503void
4504xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
4505 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
4506 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4507}
4508
4509/************************************************************************
4510 * *
4511 * The explicit core function library *
4512 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
4513 * *
4514 ************************************************************************/
4515
4516
4517/**
4518 * xmlXPathLastFunction:
4519 * @ctxt: the XPath Parser context
4520 * @nargs: the number of arguments
4521 *
4522 * Implement the last() XPath function
4523 * number last()
4524 * The last function returns the number of nodes in the context node list.
4525 */
4526void
4527xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4528 CHECK_ARITY(0);
4529 if (ctxt->context->contextSize >= 0) {
4530 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
4531#ifdef DEBUG_EXPR
4532 xmlGenericError(xmlGenericErrorContext,
4533 "last() : %d\n", ctxt->context->contextSize);
4534#endif
4535 } else {
4536 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
4537 }
4538}
4539
4540/**
4541 * xmlXPathPositionFunction:
4542 * @ctxt: the XPath Parser context
4543 * @nargs: the number of arguments
4544 *
4545 * Implement the position() XPath function
4546 * number position()
4547 * The position function returns the position of the context node in the
4548 * context node list. The first position is 1, and so the last positionr
4549 * will be equal to last().
4550 */
4551void
4552xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4553 CHECK_ARITY(0);
4554 if (ctxt->context->proximityPosition >= 0) {
4555 valuePush(ctxt,
4556 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
4557#ifdef DEBUG_EXPR
4558 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
4559 ctxt->context->proximityPosition);
4560#endif
4561 } else {
4562 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
4563 }
4564}
4565
4566/**
4567 * xmlXPathCountFunction:
4568 * @ctxt: the XPath Parser context
4569 * @nargs: the number of arguments
4570 *
4571 * Implement the count() XPath function
4572 * number count(node-set)
4573 */
4574void
4575xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4576 xmlXPathObjectPtr cur;
4577
4578 CHECK_ARITY(1);
4579 if ((ctxt->value == NULL) ||
4580 ((ctxt->value->type != XPATH_NODESET) &&
4581 (ctxt->value->type != XPATH_XSLT_TREE)))
4582 XP_ERROR(XPATH_INVALID_TYPE);
4583 cur = valuePop(ctxt);
4584
Daniel Veillard911f49a2001-04-07 15:39:35 +00004585 if ((cur == NULL) || (cur->nodesetval == NULL))
4586 valuePush(ctxt, xmlXPathNewFloat((double) 0));
4587 else
4588 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00004589 xmlXPathFreeObject(cur);
4590}
4591
4592/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004593 * xmlXPathGetElementsByIds:
4594 * @doc: the document
4595 * @ids: a whitespace separated list of IDs
4596 *
4597 * Selects elements by their unique ID.
4598 *
4599 * Returns a node-set of selected elements.
4600 */
4601static xmlNodeSetPtr
4602xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
4603 xmlNodeSetPtr ret;
4604 const xmlChar *cur = ids;
4605 xmlChar *ID;
4606 xmlAttrPtr attr;
4607 xmlNodePtr elem = NULL;
4608
4609 ret = xmlXPathNodeSetCreate(NULL);
4610
4611 while (IS_BLANK(*cur)) cur++;
4612 while (*cur != 0) {
4613 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
4614 (*cur == '.') || (*cur == '-') ||
4615 (*cur == '_') || (*cur == ':') ||
4616 (IS_COMBINING(*cur)) ||
4617 (IS_EXTENDER(*cur)))
4618 cur++;
4619
4620 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
4621
4622 ID = xmlStrndup(ids, cur - ids);
4623 attr = xmlGetID(doc, ID);
4624 if (attr != NULL) {
4625 elem = attr->parent;
4626 xmlXPathNodeSetAdd(ret, elem);
4627 }
4628 if (ID != NULL)
4629 xmlFree(ID);
4630
4631 while (IS_BLANK(*cur)) cur++;
4632 ids = cur;
4633 }
4634 return(ret);
4635}
4636
4637/**
Owen Taylor3473f882001-02-23 17:55:21 +00004638 * xmlXPathIdFunction:
4639 * @ctxt: the XPath Parser context
4640 * @nargs: the number of arguments
4641 *
4642 * Implement the id() XPath function
4643 * node-set id(object)
4644 * The id function selects elements by their unique ID
4645 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
4646 * then the result is the union of the result of applying id to the
4647 * string value of each of the nodes in the argument node-set. When the
4648 * argument to id is of any other type, the argument is converted to a
4649 * string as if by a call to the string function; the string is split
4650 * into a whitespace-separated list of tokens (whitespace is any sequence
4651 * of characters matching the production S); the result is a node-set
4652 * containing the elements in the same document as the context node that
4653 * have a unique ID equal to any of the tokens in the list.
4654 */
4655void
4656xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004657 xmlChar *tokens;
4658 xmlNodeSetPtr ret;
4659 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00004660
4661 CHECK_ARITY(1);
4662 obj = valuePop(ctxt);
4663 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
4664 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004665 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00004666 int i;
4667
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004668 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004669
Daniel Veillard911f49a2001-04-07 15:39:35 +00004670 if (obj->nodesetval != NULL) {
4671 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004672 tokens =
4673 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
4674 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
4675 ret = xmlXPathNodeSetMerge(ret, ns);
4676 xmlXPathFreeNodeSet(ns);
4677 if (tokens != NULL)
4678 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004679 }
Owen Taylor3473f882001-02-23 17:55:21 +00004680 }
4681
4682 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004683 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004684 return;
4685 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004686 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00004687
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004688 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
4689 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004690
Owen Taylor3473f882001-02-23 17:55:21 +00004691 xmlXPathFreeObject(obj);
4692 return;
4693}
4694
4695/**
4696 * xmlXPathLocalNameFunction:
4697 * @ctxt: the XPath Parser context
4698 * @nargs: the number of arguments
4699 *
4700 * Implement the local-name() XPath function
4701 * string local-name(node-set?)
4702 * The local-name function returns a string containing the local part
4703 * of the name of the node in the argument node-set that is first in
4704 * document order. If the node-set is empty or the first node has no
4705 * name, an empty string is returned. If the argument is omitted it
4706 * defaults to the context node.
4707 */
4708void
4709xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4710 xmlXPathObjectPtr cur;
4711
4712 if (nargs == 0) {
4713 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4714 nargs = 1;
4715 }
4716
4717 CHECK_ARITY(1);
4718 if ((ctxt->value == NULL) ||
4719 ((ctxt->value->type != XPATH_NODESET) &&
4720 (ctxt->value->type != XPATH_XSLT_TREE)))
4721 XP_ERROR(XPATH_INVALID_TYPE);
4722 cur = valuePop(ctxt);
4723
Daniel Veillard911f49a2001-04-07 15:39:35 +00004724 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004725 valuePush(ctxt, xmlXPathNewCString(""));
4726 } else {
4727 int i = 0; /* Should be first in document order !!!!! */
4728 switch (cur->nodesetval->nodeTab[i]->type) {
4729 case XML_ELEMENT_NODE:
4730 case XML_ATTRIBUTE_NODE:
4731 case XML_PI_NODE:
4732 valuePush(ctxt,
4733 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4734 break;
4735 case XML_NAMESPACE_DECL:
4736 valuePush(ctxt, xmlXPathNewString(
4737 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4738 break;
4739 default:
4740 valuePush(ctxt, xmlXPathNewCString(""));
4741 }
4742 }
4743 xmlXPathFreeObject(cur);
4744}
4745
4746/**
4747 * xmlXPathNamespaceURIFunction:
4748 * @ctxt: the XPath Parser context
4749 * @nargs: the number of arguments
4750 *
4751 * Implement the namespace-uri() XPath function
4752 * string namespace-uri(node-set?)
4753 * The namespace-uri function returns a string containing the
4754 * namespace URI of the expanded name of the node in the argument
4755 * node-set that is first in document order. If the node-set is empty,
4756 * the first node has no name, or the expanded name has no namespace
4757 * URI, an empty string is returned. If the argument is omitted it
4758 * defaults to the context node.
4759 */
4760void
4761xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4762 xmlXPathObjectPtr cur;
4763
4764 if (nargs == 0) {
4765 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4766 nargs = 1;
4767 }
4768 CHECK_ARITY(1);
4769 if ((ctxt->value == NULL) ||
4770 ((ctxt->value->type != XPATH_NODESET) &&
4771 (ctxt->value->type != XPATH_XSLT_TREE)))
4772 XP_ERROR(XPATH_INVALID_TYPE);
4773 cur = valuePop(ctxt);
4774
Daniel Veillard911f49a2001-04-07 15:39:35 +00004775 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004776 valuePush(ctxt, xmlXPathNewCString(""));
4777 } else {
4778 int i = 0; /* Should be first in document order !!!!! */
4779 switch (cur->nodesetval->nodeTab[i]->type) {
4780 case XML_ELEMENT_NODE:
4781 case XML_ATTRIBUTE_NODE:
4782 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4783 valuePush(ctxt, xmlXPathNewCString(""));
4784 else
4785 valuePush(ctxt, xmlXPathNewString(
4786 cur->nodesetval->nodeTab[i]->ns->href));
4787 break;
4788 default:
4789 valuePush(ctxt, xmlXPathNewCString(""));
4790 }
4791 }
4792 xmlXPathFreeObject(cur);
4793}
4794
4795/**
4796 * xmlXPathNameFunction:
4797 * @ctxt: the XPath Parser context
4798 * @nargs: the number of arguments
4799 *
4800 * Implement the name() XPath function
4801 * string name(node-set?)
4802 * The name function returns a string containing a QName representing
4803 * the name of the node in the argument node-set that is first in documenti
4804 * order. The QName must represent the name with respect to the namespace
4805 * declarations in effect on the node whose name is being represented.
4806 * Typically, this will be the form in which the name occurred in the XML
4807 * source. This need not be the case if there are namespace declarations
4808 * in effect on the node that associate multiple prefixes with the same
4809 * namespace. However, an implementation may include information about
4810 * the original prefix in its representation of nodes; in this case, an
4811 * implementation can ensure that the returned string is always the same
4812 * as the QName used in the XML source. If the argument it omitted it
4813 * defaults to the context node.
4814 * Libxml keep the original prefix so the "real qualified name" used is
4815 * returned.
4816 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004817static void
Owen Taylor3473f882001-02-23 17:55:21 +00004818xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4819 xmlXPathObjectPtr cur;
4820
4821 if (nargs == 0) {
4822 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4823 nargs = 1;
4824 }
4825
4826 CHECK_ARITY(1);
4827 if ((ctxt->value == NULL) ||
4828 ((ctxt->value->type != XPATH_NODESET) &&
4829 (ctxt->value->type != XPATH_XSLT_TREE)))
4830 XP_ERROR(XPATH_INVALID_TYPE);
4831 cur = valuePop(ctxt);
4832
Daniel Veillard911f49a2001-04-07 15:39:35 +00004833 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004834 valuePush(ctxt, xmlXPathNewCString(""));
4835 } else {
4836 int i = 0; /* Should be first in document order !!!!! */
4837
4838 switch (cur->nodesetval->nodeTab[i]->type) {
4839 case XML_ELEMENT_NODE:
4840 case XML_ATTRIBUTE_NODE:
4841 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4842 valuePush(ctxt, xmlXPathNewString(
4843 cur->nodesetval->nodeTab[i]->name));
4844
4845 else {
4846 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004847 snprintf(name, sizeof(name), "%s:%s",
4848 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4849 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004850 name[sizeof(name) - 1] = 0;
4851 valuePush(ctxt, xmlXPathNewCString(name));
4852 }
4853 break;
4854 default:
4855 valuePush(ctxt,
4856 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4857 xmlXPathLocalNameFunction(ctxt, 1);
4858 }
4859 }
4860 xmlXPathFreeObject(cur);
4861}
4862
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004863
4864/**
Owen Taylor3473f882001-02-23 17:55:21 +00004865 * xmlXPathStringFunction:
4866 * @ctxt: the XPath Parser context
4867 * @nargs: the number of arguments
4868 *
4869 * Implement the string() XPath function
4870 * string string(object?)
4871 * he string function converts an object to a string as follows:
4872 * - A node-set is converted to a string by returning the value of
4873 * the node in the node-set that is first in document order.
4874 * If the node-set is empty, an empty string is returned.
4875 * - A number is converted to a string as follows
4876 * + NaN is converted to the string NaN
4877 * + positive zero is converted to the string 0
4878 * + negative zero is converted to the string 0
4879 * + positive infinity is converted to the string Infinity
4880 * + negative infinity is converted to the string -Infinity
4881 * + if the number is an integer, the number is represented in
4882 * decimal form as a Number with no decimal point and no leading
4883 * zeros, preceded by a minus sign (-) if the number is negative
4884 * + otherwise, the number is represented in decimal form as a
4885 * Number including a decimal point with at least one digit
4886 * before the decimal point and at least one digit after the
4887 * decimal point, preceded by a minus sign (-) if the number
4888 * is negative; there must be no leading zeros before the decimal
4889 * point apart possibly from the one required digit immediatelyi
4890 * before the decimal point; beyond the one required digit
4891 * after the decimal point there must be as many, but only as
4892 * many, more digits as are needed to uniquely distinguish the
4893 * number from all other IEEE 754 numeric values.
4894 * - The boolean false value is converted to the string false.
4895 * The boolean true value is converted to the string true.
4896 *
4897 * If the argument is omitted, it defaults to a node-set with the
4898 * context node as its only member.
4899 */
4900void
4901xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4902 xmlXPathObjectPtr cur;
4903
4904 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004905 valuePush(ctxt,
4906 xmlXPathWrapString(
4907 xmlXPathCastNodeToString(ctxt->context->node)));
4908 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004909 }
4910
4911 CHECK_ARITY(1);
4912 cur = valuePop(ctxt);
4913 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004914 cur = xmlXPathConvertString(cur);
4915 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004916}
4917
4918/**
4919 * xmlXPathStringLengthFunction:
4920 * @ctxt: the XPath Parser context
4921 * @nargs: the number of arguments
4922 *
4923 * Implement the string-length() XPath function
4924 * number string-length(string?)
4925 * The string-length returns the number of characters in the string
4926 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4927 * the context node converted to a string, in other words the value
4928 * of the context node.
4929 */
4930void
4931xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4932 xmlXPathObjectPtr cur;
4933
4934 if (nargs == 0) {
4935 if (ctxt->context->node == NULL) {
4936 valuePush(ctxt, xmlXPathNewFloat(0));
4937 } else {
4938 xmlChar *content;
4939
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004940 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004941 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004942 xmlFree(content);
4943 }
4944 return;
4945 }
4946 CHECK_ARITY(1);
4947 CAST_TO_STRING;
4948 CHECK_TYPE(XPATH_STRING);
4949 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004950 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004951 xmlXPathFreeObject(cur);
4952}
4953
4954/**
4955 * xmlXPathConcatFunction:
4956 * @ctxt: the XPath Parser context
4957 * @nargs: the number of arguments
4958 *
4959 * Implement the concat() XPath function
4960 * string concat(string, string, string*)
4961 * The concat function returns the concatenation of its arguments.
4962 */
4963void
4964xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4965 xmlXPathObjectPtr cur, newobj;
4966 xmlChar *tmp;
4967
4968 if (nargs < 2) {
4969 CHECK_ARITY(2);
4970 }
4971
4972 CAST_TO_STRING;
4973 cur = valuePop(ctxt);
4974 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4975 xmlXPathFreeObject(cur);
4976 return;
4977 }
4978 nargs--;
4979
4980 while (nargs > 0) {
4981 CAST_TO_STRING;
4982 newobj = valuePop(ctxt);
4983 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4984 xmlXPathFreeObject(newobj);
4985 xmlXPathFreeObject(cur);
4986 XP_ERROR(XPATH_INVALID_TYPE);
4987 }
4988 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4989 newobj->stringval = cur->stringval;
4990 cur->stringval = tmp;
4991
4992 xmlXPathFreeObject(newobj);
4993 nargs--;
4994 }
4995 valuePush(ctxt, cur);
4996}
4997
4998/**
4999 * xmlXPathContainsFunction:
5000 * @ctxt: the XPath Parser context
5001 * @nargs: the number of arguments
5002 *
5003 * Implement the contains() XPath function
5004 * boolean contains(string, string)
5005 * The contains function returns true if the first argument string
5006 * contains the second argument string, and otherwise returns false.
5007 */
5008void
5009xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5010 xmlXPathObjectPtr hay, needle;
5011
5012 CHECK_ARITY(2);
5013 CAST_TO_STRING;
5014 CHECK_TYPE(XPATH_STRING);
5015 needle = valuePop(ctxt);
5016 CAST_TO_STRING;
5017 hay = valuePop(ctxt);
5018 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5019 xmlXPathFreeObject(hay);
5020 xmlXPathFreeObject(needle);
5021 XP_ERROR(XPATH_INVALID_TYPE);
5022 }
5023 if (xmlStrstr(hay->stringval, needle->stringval))
5024 valuePush(ctxt, xmlXPathNewBoolean(1));
5025 else
5026 valuePush(ctxt, xmlXPathNewBoolean(0));
5027 xmlXPathFreeObject(hay);
5028 xmlXPathFreeObject(needle);
5029}
5030
5031/**
5032 * xmlXPathStartsWithFunction:
5033 * @ctxt: the XPath Parser context
5034 * @nargs: the number of arguments
5035 *
5036 * Implement the starts-with() XPath function
5037 * boolean starts-with(string, string)
5038 * The starts-with function returns true if the first argument string
5039 * starts with the second argument string, and otherwise returns false.
5040 */
5041void
5042xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5043 xmlXPathObjectPtr hay, needle;
5044 int n;
5045
5046 CHECK_ARITY(2);
5047 CAST_TO_STRING;
5048 CHECK_TYPE(XPATH_STRING);
5049 needle = valuePop(ctxt);
5050 CAST_TO_STRING;
5051 hay = valuePop(ctxt);
5052 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5053 xmlXPathFreeObject(hay);
5054 xmlXPathFreeObject(needle);
5055 XP_ERROR(XPATH_INVALID_TYPE);
5056 }
5057 n = xmlStrlen(needle->stringval);
5058 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5059 valuePush(ctxt, xmlXPathNewBoolean(0));
5060 else
5061 valuePush(ctxt, xmlXPathNewBoolean(1));
5062 xmlXPathFreeObject(hay);
5063 xmlXPathFreeObject(needle);
5064}
5065
5066/**
5067 * xmlXPathSubstringFunction:
5068 * @ctxt: the XPath Parser context
5069 * @nargs: the number of arguments
5070 *
5071 * Implement the substring() XPath function
5072 * string substring(string, number, number?)
5073 * The substring function returns the substring of the first argument
5074 * starting at the position specified in the second argument with
5075 * length specified in the third argument. For example,
5076 * substring("12345",2,3) returns "234". If the third argument is not
5077 * specified, it returns the substring starting at the position specified
5078 * in the second argument and continuing to the end of the string. For
5079 * example, substring("12345",2) returns "2345". More precisely, each
5080 * character in the string (see [3.6 Strings]) is considered to have a
5081 * numeric position: the position of the first character is 1, the position
5082 * of the second character is 2 and so on. The returned substring contains
5083 * those characters for which the position of the character is greater than
5084 * or equal to the second argument and, if the third argument is specified,
5085 * less than the sum of the second and third arguments; the comparisons
5086 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5087 * - substring("12345", 1.5, 2.6) returns "234"
5088 * - substring("12345", 0, 3) returns "12"
5089 * - substring("12345", 0 div 0, 3) returns ""
5090 * - substring("12345", 1, 0 div 0) returns ""
5091 * - substring("12345", -42, 1 div 0) returns "12345"
5092 * - substring("12345", -1 div 0, 1 div 0) returns ""
5093 */
5094void
5095xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5096 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005097 double le=0, in;
5098 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005099 xmlChar *ret;
5100
Owen Taylor3473f882001-02-23 17:55:21 +00005101 if (nargs < 2) {
5102 CHECK_ARITY(2);
5103 }
5104 if (nargs > 3) {
5105 CHECK_ARITY(3);
5106 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005107 /*
5108 * take care of possible last (position) argument
5109 */
Owen Taylor3473f882001-02-23 17:55:21 +00005110 if (nargs == 3) {
5111 CAST_TO_NUMBER;
5112 CHECK_TYPE(XPATH_NUMBER);
5113 len = valuePop(ctxt);
5114 le = len->floatval;
5115 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005116 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005117
Owen Taylor3473f882001-02-23 17:55:21 +00005118 CAST_TO_NUMBER;
5119 CHECK_TYPE(XPATH_NUMBER);
5120 start = valuePop(ctxt);
5121 in = start->floatval;
5122 xmlXPathFreeObject(start);
5123 CAST_TO_STRING;
5124 CHECK_TYPE(XPATH_STRING);
5125 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005126 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005127
Daniel Veillard97ac1312001-05-30 19:14:17 +00005128 /*
5129 * If last pos not present, calculate last position
5130 */
5131 if (nargs != 3)
5132 le = m;
5133
5134 /*
5135 * To meet our requirements, initial index calculations
5136 * must be done before we convert to integer format
5137 *
5138 * First we normalize indices
5139 */
5140 in -= 1.0;
5141 le += in;
5142 if (in < 0.0)
5143 in = 0.0;
5144 if (le > (double)m)
5145 le = (double)m;
5146
5147 /*
5148 * Now we go to integer form, rounding up
5149 */
Owen Taylor3473f882001-02-23 17:55:21 +00005150 i = (int) in;
5151 if (((double)i) != in) i++;
5152
Owen Taylor3473f882001-02-23 17:55:21 +00005153 l = (int) le;
5154 if (((double)l) != le) l++;
5155
Daniel Veillard97ac1312001-05-30 19:14:17 +00005156 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005157
5158 /* number of chars to copy */
5159 l -= i;
5160
Daniel Veillard97ac1312001-05-30 19:14:17 +00005161 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005162 if (ret == NULL)
5163 valuePush(ctxt, xmlXPathNewCString(""));
5164 else {
5165 valuePush(ctxt, xmlXPathNewString(ret));
5166 xmlFree(ret);
5167 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005168
Owen Taylor3473f882001-02-23 17:55:21 +00005169 xmlXPathFreeObject(str);
5170}
5171
5172/**
5173 * xmlXPathSubstringBeforeFunction:
5174 * @ctxt: the XPath Parser context
5175 * @nargs: the number of arguments
5176 *
5177 * Implement the substring-before() XPath function
5178 * string substring-before(string, string)
5179 * The substring-before function returns the substring of the first
5180 * argument string that precedes the first occurrence of the second
5181 * argument string in the first argument string, or the empty string
5182 * if the first argument string does not contain the second argument
5183 * string. For example, substring-before("1999/04/01","/") returns 1999.
5184 */
5185void
5186xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5187 xmlXPathObjectPtr str;
5188 xmlXPathObjectPtr find;
5189 xmlBufferPtr target;
5190 const xmlChar *point;
5191 int offset;
5192
5193 CHECK_ARITY(2);
5194 CAST_TO_STRING;
5195 find = valuePop(ctxt);
5196 CAST_TO_STRING;
5197 str = valuePop(ctxt);
5198
5199 target = xmlBufferCreate();
5200 if (target) {
5201 point = xmlStrstr(str->stringval, find->stringval);
5202 if (point) {
5203 offset = (int)(point - str->stringval);
5204 xmlBufferAdd(target, str->stringval, offset);
5205 }
5206 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5207 xmlBufferFree(target);
5208 }
5209
5210 xmlXPathFreeObject(str);
5211 xmlXPathFreeObject(find);
5212}
5213
5214/**
5215 * xmlXPathSubstringAfterFunction:
5216 * @ctxt: the XPath Parser context
5217 * @nargs: the number of arguments
5218 *
5219 * Implement the substring-after() XPath function
5220 * string substring-after(string, string)
5221 * The substring-after function returns the substring of the first
5222 * argument string that follows the first occurrence of the second
5223 * argument string in the first argument string, or the empty stringi
5224 * if the first argument string does not contain the second argument
5225 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5226 * and substring-after("1999/04/01","19") returns 99/04/01.
5227 */
5228void
5229xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5230 xmlXPathObjectPtr str;
5231 xmlXPathObjectPtr find;
5232 xmlBufferPtr target;
5233 const xmlChar *point;
5234 int offset;
5235
5236 CHECK_ARITY(2);
5237 CAST_TO_STRING;
5238 find = valuePop(ctxt);
5239 CAST_TO_STRING;
5240 str = valuePop(ctxt);
5241
5242 target = xmlBufferCreate();
5243 if (target) {
5244 point = xmlStrstr(str->stringval, find->stringval);
5245 if (point) {
5246 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5247 xmlBufferAdd(target, &str->stringval[offset],
5248 xmlStrlen(str->stringval) - offset);
5249 }
5250 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5251 xmlBufferFree(target);
5252 }
5253
5254 xmlXPathFreeObject(str);
5255 xmlXPathFreeObject(find);
5256}
5257
5258/**
5259 * xmlXPathNormalizeFunction:
5260 * @ctxt: the XPath Parser context
5261 * @nargs: the number of arguments
5262 *
5263 * Implement the normalize-space() XPath function
5264 * string normalize-space(string?)
5265 * The normalize-space function returns the argument string with white
5266 * space normalized by stripping leading and trailing whitespace
5267 * and replacing sequences of whitespace characters by a single
5268 * space. Whitespace characters are the same allowed by the S production
5269 * in XML. If the argument is omitted, it defaults to the context
5270 * node converted to a string, in other words the value of the context node.
5271 */
5272void
5273xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5274 xmlXPathObjectPtr obj = NULL;
5275 xmlChar *source = NULL;
5276 xmlBufferPtr target;
5277 xmlChar blank;
5278
5279 if (nargs == 0) {
5280 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005281 valuePush(ctxt,
5282 xmlXPathWrapString(
5283 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005284 nargs = 1;
5285 }
5286
5287 CHECK_ARITY(1);
5288 CAST_TO_STRING;
5289 CHECK_TYPE(XPATH_STRING);
5290 obj = valuePop(ctxt);
5291 source = obj->stringval;
5292
5293 target = xmlBufferCreate();
5294 if (target && source) {
5295
5296 /* Skip leading whitespaces */
5297 while (IS_BLANK(*source))
5298 source++;
5299
5300 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5301 blank = 0;
5302 while (*source) {
5303 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005304 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005305 } else {
5306 if (blank) {
5307 xmlBufferAdd(target, &blank, 1);
5308 blank = 0;
5309 }
5310 xmlBufferAdd(target, source, 1);
5311 }
5312 source++;
5313 }
5314
5315 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5316 xmlBufferFree(target);
5317 }
5318 xmlXPathFreeObject(obj);
5319}
5320
5321/**
5322 * xmlXPathTranslateFunction:
5323 * @ctxt: the XPath Parser context
5324 * @nargs: the number of arguments
5325 *
5326 * Implement the translate() XPath function
5327 * string translate(string, string, string)
5328 * The translate function returns the first argument string with
5329 * occurrences of characters in the second argument string replaced
5330 * by the character at the corresponding position in the third argument
5331 * string. For example, translate("bar","abc","ABC") returns the string
5332 * BAr. If there is a character in the second argument string with no
5333 * character at a corresponding position in the third argument string
5334 * (because the second argument string is longer than the third argument
5335 * string), then occurrences of that character in the first argument
5336 * string are removed. For example, translate("--aaa--","abc-","ABC")
5337 * returns "AAA". If a character occurs more than once in second
5338 * argument string, then the first occurrence determines the replacement
5339 * character. If the third argument string is longer than the second
5340 * argument string, then excess characters are ignored.
5341 */
5342void
5343xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005344 xmlXPathObjectPtr str;
5345 xmlXPathObjectPtr from;
5346 xmlXPathObjectPtr to;
5347 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005348 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005349 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005350 xmlChar *point;
5351 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005352
Daniel Veillarde043ee12001-04-16 14:08:07 +00005353 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005354
Daniel Veillarde043ee12001-04-16 14:08:07 +00005355 CAST_TO_STRING;
5356 to = valuePop(ctxt);
5357 CAST_TO_STRING;
5358 from = valuePop(ctxt);
5359 CAST_TO_STRING;
5360 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005361
Daniel Veillarde043ee12001-04-16 14:08:07 +00005362 target = xmlBufferCreate();
5363 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005364 max = xmlUTF8Strlen(to->stringval);
5365 for (cptr = str->stringval; (ch=*cptr); ) {
5366 offset = xmlUTF8Strloc(from->stringval, cptr);
5367 if (offset >= 0) {
5368 if (offset < max) {
5369 point = xmlUTF8Strpos(to->stringval, offset);
5370 if (point)
5371 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5372 }
5373 } else
5374 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5375
5376 /* Step to next character in input */
5377 cptr++;
5378 if ( ch & 0x80 ) {
5379 /* if not simple ascii, verify proper format */
5380 if ( (ch & 0xc0) != 0xc0 ) {
5381 xmlGenericError(xmlGenericErrorContext,
5382 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5383 break;
5384 }
5385 /* then skip over remaining bytes for this char */
5386 while ( (ch <<= 1) & 0x80 )
5387 if ( (*cptr++ & 0xc0) != 0x80 ) {
5388 xmlGenericError(xmlGenericErrorContext,
5389 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5390 break;
5391 }
5392 if (ch & 0x80) /* must have had error encountered */
5393 break;
5394 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005395 }
Owen Taylor3473f882001-02-23 17:55:21 +00005396 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005397 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5398 xmlBufferFree(target);
5399 xmlXPathFreeObject(str);
5400 xmlXPathFreeObject(from);
5401 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005402}
5403
5404/**
5405 * xmlXPathBooleanFunction:
5406 * @ctxt: the XPath Parser context
5407 * @nargs: the number of arguments
5408 *
5409 * Implement the boolean() XPath function
5410 * boolean boolean(object)
5411 * he boolean function converts its argument to a boolean as follows:
5412 * - a number is true if and only if it is neither positive or
5413 * negative zero nor NaN
5414 * - a node-set is true if and only if it is non-empty
5415 * - a string is true if and only if its length is non-zero
5416 */
5417void
5418xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5419 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005420
5421 CHECK_ARITY(1);
5422 cur = valuePop(ctxt);
5423 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005424 cur = xmlXPathConvertBoolean(cur);
5425 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005426}
5427
5428/**
5429 * xmlXPathNotFunction:
5430 * @ctxt: the XPath Parser context
5431 * @nargs: the number of arguments
5432 *
5433 * Implement the not() XPath function
5434 * boolean not(boolean)
5435 * The not function returns true if its argument is false,
5436 * and false otherwise.
5437 */
5438void
5439xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5440 CHECK_ARITY(1);
5441 CAST_TO_BOOLEAN;
5442 CHECK_TYPE(XPATH_BOOLEAN);
5443 ctxt->value->boolval = ! ctxt->value->boolval;
5444}
5445
5446/**
5447 * xmlXPathTrueFunction:
5448 * @ctxt: the XPath Parser context
5449 * @nargs: the number of arguments
5450 *
5451 * Implement the true() XPath function
5452 * boolean true()
5453 */
5454void
5455xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5456 CHECK_ARITY(0);
5457 valuePush(ctxt, xmlXPathNewBoolean(1));
5458}
5459
5460/**
5461 * xmlXPathFalseFunction:
5462 * @ctxt: the XPath Parser context
5463 * @nargs: the number of arguments
5464 *
5465 * Implement the false() XPath function
5466 * boolean false()
5467 */
5468void
5469xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5470 CHECK_ARITY(0);
5471 valuePush(ctxt, xmlXPathNewBoolean(0));
5472}
5473
5474/**
5475 * xmlXPathLangFunction:
5476 * @ctxt: the XPath Parser context
5477 * @nargs: the number of arguments
5478 *
5479 * Implement the lang() XPath function
5480 * boolean lang(string)
5481 * The lang function returns true or false depending on whether the
5482 * language of the context node as specified by xml:lang attributes
5483 * is the same as or is a sublanguage of the language specified by
5484 * the argument string. The language of the context node is determined
5485 * by the value of the xml:lang attribute on the context node, or, if
5486 * the context node has no xml:lang attribute, by the value of the
5487 * xml:lang attribute on the nearest ancestor of the context node that
5488 * has an xml:lang attribute. If there is no such attribute, then lang
5489 * returns false. If there is such an attribute, then lang returns
5490 * true if the attribute value is equal to the argument ignoring case,
5491 * or if there is some suffix starting with - such that the attribute
5492 * value is equal to the argument ignoring that suffix of the attribute
5493 * value and ignoring case.
5494 */
5495void
5496xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5497 xmlXPathObjectPtr val;
5498 const xmlChar *theLang;
5499 const xmlChar *lang;
5500 int ret = 0;
5501 int i;
5502
5503 CHECK_ARITY(1);
5504 CAST_TO_STRING;
5505 CHECK_TYPE(XPATH_STRING);
5506 val = valuePop(ctxt);
5507 lang = val->stringval;
5508 theLang = xmlNodeGetLang(ctxt->context->node);
5509 if ((theLang != NULL) && (lang != NULL)) {
5510 for (i = 0;lang[i] != 0;i++)
5511 if (toupper(lang[i]) != toupper(theLang[i]))
5512 goto not_equal;
5513 ret = 1;
5514 }
5515not_equal:
5516 xmlXPathFreeObject(val);
5517 valuePush(ctxt, xmlXPathNewBoolean(ret));
5518}
5519
5520/**
5521 * xmlXPathNumberFunction:
5522 * @ctxt: the XPath Parser context
5523 * @nargs: the number of arguments
5524 *
5525 * Implement the number() XPath function
5526 * number number(object?)
5527 */
5528void
5529xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5530 xmlXPathObjectPtr cur;
5531 double res;
5532
5533 if (nargs == 0) {
5534 if (ctxt->context->node == NULL) {
5535 valuePush(ctxt, xmlXPathNewFloat(0.0));
5536 } else {
5537 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
5538
5539 res = xmlXPathStringEvalNumber(content);
5540 valuePush(ctxt, xmlXPathNewFloat(res));
5541 xmlFree(content);
5542 }
5543 return;
5544 }
5545
5546 CHECK_ARITY(1);
5547 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005548 cur = xmlXPathConvertNumber(cur);
5549 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005550}
5551
5552/**
5553 * xmlXPathSumFunction:
5554 * @ctxt: the XPath Parser context
5555 * @nargs: the number of arguments
5556 *
5557 * Implement the sum() XPath function
5558 * number sum(node-set)
5559 * The sum function returns the sum of the values of the nodes in
5560 * the argument node-set.
5561 */
5562void
5563xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5564 xmlXPathObjectPtr cur;
5565 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005566 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00005567
5568 CHECK_ARITY(1);
5569 if ((ctxt->value == NULL) ||
5570 ((ctxt->value->type != XPATH_NODESET) &&
5571 (ctxt->value->type != XPATH_XSLT_TREE)))
5572 XP_ERROR(XPATH_INVALID_TYPE);
5573 cur = valuePop(ctxt);
5574
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005575 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005576 valuePush(ctxt, xmlXPathNewFloat(0.0));
5577 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005578 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
5579 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00005580 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005581 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00005582 }
5583 xmlXPathFreeObject(cur);
5584}
5585
5586/**
5587 * xmlXPathFloorFunction:
5588 * @ctxt: the XPath Parser context
5589 * @nargs: the number of arguments
5590 *
5591 * Implement the floor() XPath function
5592 * number floor(number)
5593 * The floor function returns the largest (closest to positive infinity)
5594 * number that is not greater than the argument and that is an integer.
5595 */
5596void
5597xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5598 CHECK_ARITY(1);
5599 CAST_TO_NUMBER;
5600 CHECK_TYPE(XPATH_NUMBER);
5601#if 0
5602 ctxt->value->floatval = floor(ctxt->value->floatval);
5603#else
5604 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5605 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5606#endif
5607}
5608
5609/**
5610 * xmlXPathCeilingFunction:
5611 * @ctxt: the XPath Parser context
5612 * @nargs: the number of arguments
5613 *
5614 * Implement the ceiling() XPath function
5615 * number ceiling(number)
5616 * The ceiling function returns the smallest (closest to negative infinity)
5617 * number that is not less than the argument and that is an integer.
5618 */
5619void
5620xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5621 double f;
5622
5623 CHECK_ARITY(1);
5624 CAST_TO_NUMBER;
5625 CHECK_TYPE(XPATH_NUMBER);
5626
5627#if 0
5628 ctxt->value->floatval = ceil(ctxt->value->floatval);
5629#else
5630 f = (double)((int) ctxt->value->floatval);
5631 if (f != ctxt->value->floatval)
5632 ctxt->value->floatval = f + 1;
5633#endif
5634}
5635
5636/**
5637 * xmlXPathRoundFunction:
5638 * @ctxt: the XPath Parser context
5639 * @nargs: the number of arguments
5640 *
5641 * Implement the round() XPath function
5642 * number round(number)
5643 * The round function returns the number that is closest to the
5644 * argument and that is an integer. If there are two such numbers,
5645 * then the one that is even is returned.
5646 */
5647void
5648xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5649 double f;
5650
5651 CHECK_ARITY(1);
5652 CAST_TO_NUMBER;
5653 CHECK_TYPE(XPATH_NUMBER);
5654
5655 if ((ctxt->value->floatval == xmlXPathNAN) ||
5656 (ctxt->value->floatval == xmlXPathPINF) ||
5657 (ctxt->value->floatval == xmlXPathNINF) ||
5658 (ctxt->value->floatval == 0.0))
5659 return;
5660
5661#if 0
5662 f = floor(ctxt->value->floatval);
5663#else
5664 f = (double)((int) ctxt->value->floatval);
5665#endif
5666 if (ctxt->value->floatval < f + 0.5)
5667 ctxt->value->floatval = f;
5668 else
5669 ctxt->value->floatval = f + 1;
5670}
5671
5672/************************************************************************
5673 * *
5674 * The Parser *
5675 * *
5676 ************************************************************************/
5677
5678/*
5679 * a couple of forward declarations since we use a recursive call based
5680 * implementation.
5681 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005682static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005683static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005684static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005685#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005686static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5687#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005688#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005689static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005690#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005691static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5692 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005693
5694/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005695 * xmlXPathCurrentChar:
5696 * @ctxt: the XPath parser context
5697 * @cur: pointer to the beginning of the char
5698 * @len: pointer to the length of the char read
5699 *
5700 * The current char value, if using UTF-8 this may actaully span multiple
5701 * bytes in the input buffer.
5702 *
5703 * Returns the current char value and its lenght
5704 */
5705
5706static int
5707xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5708 unsigned char c;
5709 unsigned int val;
5710 const xmlChar *cur;
5711
5712 if (ctxt == NULL)
5713 return(0);
5714 cur = ctxt->cur;
5715
5716 /*
5717 * We are supposed to handle UTF8, check it's valid
5718 * From rfc2044: encoding of the Unicode values on UTF-8:
5719 *
5720 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5721 * 0000 0000-0000 007F 0xxxxxxx
5722 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5723 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5724 *
5725 * Check for the 0x110000 limit too
5726 */
5727 c = *cur;
5728 if (c & 0x80) {
5729 if ((cur[1] & 0xc0) != 0x80)
5730 goto encoding_error;
5731 if ((c & 0xe0) == 0xe0) {
5732
5733 if ((cur[2] & 0xc0) != 0x80)
5734 goto encoding_error;
5735 if ((c & 0xf0) == 0xf0) {
5736 if (((c & 0xf8) != 0xf0) ||
5737 ((cur[3] & 0xc0) != 0x80))
5738 goto encoding_error;
5739 /* 4-byte code */
5740 *len = 4;
5741 val = (cur[0] & 0x7) << 18;
5742 val |= (cur[1] & 0x3f) << 12;
5743 val |= (cur[2] & 0x3f) << 6;
5744 val |= cur[3] & 0x3f;
5745 } else {
5746 /* 3-byte code */
5747 *len = 3;
5748 val = (cur[0] & 0xf) << 12;
5749 val |= (cur[1] & 0x3f) << 6;
5750 val |= cur[2] & 0x3f;
5751 }
5752 } else {
5753 /* 2-byte code */
5754 *len = 2;
5755 val = (cur[0] & 0x1f) << 6;
5756 val |= cur[1] & 0x3f;
5757 }
5758 if (!IS_CHAR(val)) {
5759 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5760 }
5761 return(val);
5762 } else {
5763 /* 1-byte code */
5764 *len = 1;
5765 return((int) *cur);
5766 }
5767encoding_error:
5768 /*
5769 * If we detect an UTF8 error that probably mean that the
5770 * input encoding didn't get properly advertized in the
5771 * declaration header. Report the error and switch the encoding
5772 * to ISO-Latin-1 (if you don't like this policy, just declare the
5773 * encoding !)
5774 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00005775 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00005776 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005777}
5778
5779/**
Owen Taylor3473f882001-02-23 17:55:21 +00005780 * xmlXPathParseNCName:
5781 * @ctxt: the XPath Parser context
5782 *
5783 * parse an XML namespace non qualified name.
5784 *
5785 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5786 *
5787 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5788 * CombiningChar | Extender
5789 *
5790 * Returns the namespace name or NULL
5791 */
5792
5793xmlChar *
5794xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005795 const xmlChar *in;
5796 xmlChar *ret;
5797 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005798
Daniel Veillard2156a562001-04-28 12:24:34 +00005799 /*
5800 * Accelerator for simple ASCII names
5801 */
5802 in = ctxt->cur;
5803 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5804 ((*in >= 0x41) && (*in <= 0x5A)) ||
5805 (*in == '_')) {
5806 in++;
5807 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5808 ((*in >= 0x41) && (*in <= 0x5A)) ||
5809 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00005810 (*in == '_') || (*in == '.') ||
5811 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00005812 in++;
5813 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5814 (*in == '[') || (*in == ']') || (*in == ':') ||
5815 (*in == '@') || (*in == '*')) {
5816 count = in - ctxt->cur;
5817 if (count == 0)
5818 return(NULL);
5819 ret = xmlStrndup(ctxt->cur, count);
5820 ctxt->cur = in;
5821 return(ret);
5822 }
5823 }
5824 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005825}
5826
Daniel Veillard2156a562001-04-28 12:24:34 +00005827
Owen Taylor3473f882001-02-23 17:55:21 +00005828/**
5829 * xmlXPathParseQName:
5830 * @ctxt: the XPath Parser context
5831 * @prefix: a xmlChar **
5832 *
5833 * parse an XML qualified name
5834 *
5835 * [NS 5] QName ::= (Prefix ':')? LocalPart
5836 *
5837 * [NS 6] Prefix ::= NCName
5838 *
5839 * [NS 7] LocalPart ::= NCName
5840 *
5841 * Returns the function returns the local part, and prefix is updated
5842 * to get the Prefix if any.
5843 */
5844
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005845static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005846xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5847 xmlChar *ret = NULL;
5848
5849 *prefix = NULL;
5850 ret = xmlXPathParseNCName(ctxt);
5851 if (CUR == ':') {
5852 *prefix = ret;
5853 NEXT;
5854 ret = xmlXPathParseNCName(ctxt);
5855 }
5856 return(ret);
5857}
5858
5859/**
5860 * xmlXPathParseName:
5861 * @ctxt: the XPath Parser context
5862 *
5863 * parse an XML name
5864 *
5865 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5866 * CombiningChar | Extender
5867 *
5868 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5869 *
5870 * Returns the namespace name or NULL
5871 */
5872
5873xmlChar *
5874xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005875 const xmlChar *in;
5876 xmlChar *ret;
5877 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005878
Daniel Veillard61d80a22001-04-27 17:13:01 +00005879 /*
5880 * Accelerator for simple ASCII names
5881 */
5882 in = ctxt->cur;
5883 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5884 ((*in >= 0x41) && (*in <= 0x5A)) ||
5885 (*in == '_') || (*in == ':')) {
5886 in++;
5887 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5888 ((*in >= 0x41) && (*in <= 0x5A)) ||
5889 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00005890 (*in == '_') || (*in == '-') ||
5891 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00005892 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00005893 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005894 count = in - ctxt->cur;
5895 ret = xmlStrndup(ctxt->cur, count);
5896 ctxt->cur = in;
5897 return(ret);
5898 }
5899 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005900 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005901}
5902
Daniel Veillard61d80a22001-04-27 17:13:01 +00005903static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005904xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005905 xmlChar buf[XML_MAX_NAMELEN + 5];
5906 int len = 0, l;
5907 int c;
5908
5909 /*
5910 * Handler for more complex cases
5911 */
5912 c = CUR_CHAR(l);
5913 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005914 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5915 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005916 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005917 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005918 return(NULL);
5919 }
5920
5921 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5922 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5923 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005924 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005925 (IS_COMBINING(c)) ||
5926 (IS_EXTENDER(c)))) {
5927 COPY_BUF(l,buf,len,c);
5928 NEXTL(l);
5929 c = CUR_CHAR(l);
5930 if (len >= XML_MAX_NAMELEN) {
5931 /*
5932 * Okay someone managed to make a huge name, so he's ready to pay
5933 * for the processing speed.
5934 */
5935 xmlChar *buffer;
5936 int max = len * 2;
5937
5938 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5939 if (buffer == NULL) {
5940 XP_ERROR0(XPATH_MEMORY_ERROR);
5941 }
5942 memcpy(buffer, buf, len);
5943 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5944 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005945 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005946 (IS_COMBINING(c)) ||
5947 (IS_EXTENDER(c))) {
5948 if (len + 10 > max) {
5949 max *= 2;
5950 buffer = (xmlChar *) xmlRealloc(buffer,
5951 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00005952 if (buffer == NULL) {
5953 XP_ERROR0(XPATH_MEMORY_ERROR);
5954 }
5955 }
5956 COPY_BUF(l,buffer,len,c);
5957 NEXTL(l);
5958 c = CUR_CHAR(l);
5959 }
5960 buffer[len] = 0;
5961 return(buffer);
5962 }
5963 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005964 if (len == 0)
5965 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005966 return(xmlStrndup(buf, len));
5967}
Owen Taylor3473f882001-02-23 17:55:21 +00005968/**
5969 * xmlXPathStringEvalNumber:
5970 * @str: A string to scan
5971 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005972 * [30a] Float ::= Number ('e' Digits?)?
5973 *
Owen Taylor3473f882001-02-23 17:55:21 +00005974 * [30] Number ::= Digits ('.' Digits?)?
5975 * | '.' Digits
5976 * [31] Digits ::= [0-9]+
5977 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005978 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005979 * In complement of the Number expression, this function also handles
5980 * negative values : '-' Number.
5981 *
5982 * Returns the double value.
5983 */
5984double
5985xmlXPathStringEvalNumber(const xmlChar *str) {
5986 const xmlChar *cur = str;
5987 double ret = 0.0;
5988 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005989 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005990 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005991 int exponent = 0;
5992 int is_exponent_negative = 0;
5993
Owen Taylor3473f882001-02-23 17:55:21 +00005994 while (IS_BLANK(*cur)) cur++;
5995 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5996 return(xmlXPathNAN);
5997 }
5998 if (*cur == '-') {
5999 isneg = 1;
6000 cur++;
6001 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006002 /*
6003 * tmp is a workaroudn against a gcc compiler bug
6004 */
Owen Taylor3473f882001-02-23 17:55:21 +00006005 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006006 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006007 ok = 1;
6008 cur++;
6009 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006010 ret = (double) tmp;
6011
Owen Taylor3473f882001-02-23 17:55:21 +00006012 if (*cur == '.') {
6013 cur++;
6014 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6015 return(xmlXPathNAN);
6016 }
6017 while ((*cur >= '0') && (*cur <= '9')) {
6018 mult /= 10;
6019 ret = ret + (*cur - '0') * mult;
6020 cur++;
6021 }
6022 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006023 if ((*cur == 'e') || (*cur == 'E')) {
6024 cur++;
6025 if (*cur == '-') {
6026 is_exponent_negative = 1;
6027 cur++;
6028 }
6029 while ((*cur >= '0') && (*cur <= '9')) {
6030 exponent = exponent * 10 + (*cur - '0');
6031 cur++;
6032 }
6033 }
Owen Taylor3473f882001-02-23 17:55:21 +00006034 while (IS_BLANK(*cur)) cur++;
6035 if (*cur != 0) return(xmlXPathNAN);
6036 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006037 if (is_exponent_negative) exponent = -exponent;
6038 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006039 return(ret);
6040}
6041
6042/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006043 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006044 * @ctxt: the XPath Parser context
6045 *
6046 * [30] Number ::= Digits ('.' Digits?)?
6047 * | '.' Digits
6048 * [31] Digits ::= [0-9]+
6049 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006050 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006051 *
6052 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006053static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006054xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6055{
Owen Taylor3473f882001-02-23 17:55:21 +00006056 double ret = 0.0;
6057 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006058 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006059 int exponent = 0;
6060 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006061
6062 CHECK_ERROR;
6063 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6064 XP_ERROR(XPATH_NUMBER_ERROR);
6065 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006066 /*
6067 * Try to work around a gcc optimizer bug
6068 */
Owen Taylor3473f882001-02-23 17:55:21 +00006069 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006070 tmp = tmp * 10 + (CUR - '0');
6071 ok = 1;
6072 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006073 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006074 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006075 if (CUR == '.') {
6076 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006077 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6078 XP_ERROR(XPATH_NUMBER_ERROR);
6079 }
6080 while ((CUR >= '0') && (CUR <= '9')) {
6081 mult /= 10;
6082 ret = ret + (CUR - '0') * mult;
6083 NEXT;
6084 }
Owen Taylor3473f882001-02-23 17:55:21 +00006085 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006086 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006087 NEXT;
6088 if (CUR == '-') {
6089 is_exponent_negative = 1;
6090 NEXT;
6091 }
6092 while ((CUR >= '0') && (CUR <= '9')) {
6093 exponent = exponent * 10 + (CUR - '0');
6094 NEXT;
6095 }
6096 if (is_exponent_negative)
6097 exponent = -exponent;
6098 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006099 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006100 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006101 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006102}
6103
6104/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006105 * xmlXPathParseLiteral:
6106 * @ctxt: the XPath Parser context
6107 *
6108 * Parse a Literal
6109 *
6110 * [29] Literal ::= '"' [^"]* '"'
6111 * | "'" [^']* "'"
6112 *
6113 * Returns the value found or NULL in case of error
6114 */
6115static xmlChar *
6116xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6117 const xmlChar *q;
6118 xmlChar *ret = NULL;
6119
6120 if (CUR == '"') {
6121 NEXT;
6122 q = CUR_PTR;
6123 while ((IS_CHAR(CUR)) && (CUR != '"'))
6124 NEXT;
6125 if (!IS_CHAR(CUR)) {
6126 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6127 } else {
6128 ret = xmlStrndup(q, CUR_PTR - q);
6129 NEXT;
6130 }
6131 } else if (CUR == '\'') {
6132 NEXT;
6133 q = CUR_PTR;
6134 while ((IS_CHAR(CUR)) && (CUR != '\''))
6135 NEXT;
6136 if (!IS_CHAR(CUR)) {
6137 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6138 } else {
6139 ret = xmlStrndup(q, CUR_PTR - q);
6140 NEXT;
6141 }
6142 } else {
6143 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6144 }
6145 return(ret);
6146}
6147
6148/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006149 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006150 * @ctxt: the XPath Parser context
6151 *
6152 * Parse a Literal and push it on the stack.
6153 *
6154 * [29] Literal ::= '"' [^"]* '"'
6155 * | "'" [^']* "'"
6156 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006157 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006158 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006159static void
6160xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006161 const xmlChar *q;
6162 xmlChar *ret = NULL;
6163
6164 if (CUR == '"') {
6165 NEXT;
6166 q = CUR_PTR;
6167 while ((IS_CHAR(CUR)) && (CUR != '"'))
6168 NEXT;
6169 if (!IS_CHAR(CUR)) {
6170 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6171 } else {
6172 ret = xmlStrndup(q, CUR_PTR - q);
6173 NEXT;
6174 }
6175 } else if (CUR == '\'') {
6176 NEXT;
6177 q = CUR_PTR;
6178 while ((IS_CHAR(CUR)) && (CUR != '\''))
6179 NEXT;
6180 if (!IS_CHAR(CUR)) {
6181 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6182 } else {
6183 ret = xmlStrndup(q, CUR_PTR - q);
6184 NEXT;
6185 }
6186 } else {
6187 XP_ERROR(XPATH_START_LITERAL_ERROR);
6188 }
6189 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006190 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6191 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006192 xmlFree(ret);
6193}
6194
6195/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006196 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006197 * @ctxt: the XPath Parser context
6198 *
6199 * Parse a VariableReference, evaluate it and push it on the stack.
6200 *
6201 * The variable bindings consist of a mapping from variable names
6202 * to variable values. The value of a variable is an object, which
6203 * of any of the types that are possible for the value of an expression,
6204 * and may also be of additional types not specified here.
6205 *
6206 * Early evaluation is possible since:
6207 * The variable bindings [...] used to evaluate a subexpression are
6208 * always the same as those used to evaluate the containing expression.
6209 *
6210 * [36] VariableReference ::= '$' QName
6211 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006212static void
6213xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006214 xmlChar *name;
6215 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006216
6217 SKIP_BLANKS;
6218 if (CUR != '$') {
6219 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6220 }
6221 NEXT;
6222 name = xmlXPathParseQName(ctxt, &prefix);
6223 if (name == NULL) {
6224 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6225 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006226 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006227 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6228 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006229 SKIP_BLANKS;
6230}
6231
6232/**
6233 * xmlXPathIsNodeType:
6234 * @ctxt: the XPath Parser context
6235 * @name: a name string
6236 *
6237 * Is the name given a NodeType one.
6238 *
6239 * [38] NodeType ::= 'comment'
6240 * | 'text'
6241 * | 'processing-instruction'
6242 * | 'node'
6243 *
6244 * Returns 1 if true 0 otherwise
6245 */
6246int
6247xmlXPathIsNodeType(const xmlChar *name) {
6248 if (name == NULL)
6249 return(0);
6250
6251 if (xmlStrEqual(name, BAD_CAST "comment"))
6252 return(1);
6253 if (xmlStrEqual(name, BAD_CAST "text"))
6254 return(1);
6255 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6256 return(1);
6257 if (xmlStrEqual(name, BAD_CAST "node"))
6258 return(1);
6259 return(0);
6260}
6261
6262/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006263 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006264 * @ctxt: the XPath Parser context
6265 *
6266 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6267 * [17] Argument ::= Expr
6268 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006269 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006270 * pushed on the stack
6271 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006272static void
6273xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006274 xmlChar *name;
6275 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006276 int nbargs = 0;
6277
6278 name = xmlXPathParseQName(ctxt, &prefix);
6279 if (name == NULL) {
6280 XP_ERROR(XPATH_EXPR_ERROR);
6281 }
6282 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006283#ifdef DEBUG_EXPR
6284 if (prefix == NULL)
6285 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6286 name);
6287 else
6288 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6289 prefix, name);
6290#endif
6291
Owen Taylor3473f882001-02-23 17:55:21 +00006292 if (CUR != '(') {
6293 XP_ERROR(XPATH_EXPR_ERROR);
6294 }
6295 NEXT;
6296 SKIP_BLANKS;
6297
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006298 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006299 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006300 int op1 = ctxt->comp->last;
6301 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006302 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006303 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006304 nbargs++;
6305 if (CUR == ')') break;
6306 if (CUR != ',') {
6307 XP_ERROR(XPATH_EXPR_ERROR);
6308 }
6309 NEXT;
6310 SKIP_BLANKS;
6311 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006312 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6313 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006314 NEXT;
6315 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006316}
6317
6318/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006319 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006320 * @ctxt: the XPath Parser context
6321 *
6322 * [15] PrimaryExpr ::= VariableReference
6323 * | '(' Expr ')'
6324 * | Literal
6325 * | Number
6326 * | FunctionCall
6327 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006328 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006329 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006330static void
6331xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006332 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006333 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006334 else if (CUR == '(') {
6335 NEXT;
6336 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006337 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006338 if (CUR != ')') {
6339 XP_ERROR(XPATH_EXPR_ERROR);
6340 }
6341 NEXT;
6342 SKIP_BLANKS;
6343 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006344 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006345 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006346 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006347 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006348 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006349 }
6350 SKIP_BLANKS;
6351}
6352
6353/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006354 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006355 * @ctxt: the XPath Parser context
6356 *
6357 * [20] FilterExpr ::= PrimaryExpr
6358 * | FilterExpr Predicate
6359 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006360 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006361 * Square brackets are used to filter expressions in the same way that
6362 * they are used in location paths. It is an error if the expression to
6363 * be filtered does not evaluate to a node-set. The context node list
6364 * used for evaluating the expression in square brackets is the node-set
6365 * to be filtered listed in document order.
6366 */
6367
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006368static void
6369xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6370 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006371 CHECK_ERROR;
6372 SKIP_BLANKS;
6373
6374 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006375 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006376 SKIP_BLANKS;
6377 }
6378
6379
6380}
6381
6382/**
6383 * xmlXPathScanName:
6384 * @ctxt: the XPath Parser context
6385 *
6386 * Trickery: parse an XML name but without consuming the input flow
6387 * Needed to avoid insanity in the parser state.
6388 *
6389 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6390 * CombiningChar | Extender
6391 *
6392 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6393 *
6394 * [6] Names ::= Name (S Name)*
6395 *
6396 * Returns the Name parsed or NULL
6397 */
6398
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006399static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006400xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6401 xmlChar buf[XML_MAX_NAMELEN];
6402 int len = 0;
6403
6404 SKIP_BLANKS;
6405 if (!IS_LETTER(CUR) && (CUR != '_') &&
6406 (CUR != ':')) {
6407 return(NULL);
6408 }
6409
6410 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6411 (NXT(len) == '.') || (NXT(len) == '-') ||
6412 (NXT(len) == '_') || (NXT(len) == ':') ||
6413 (IS_COMBINING(NXT(len))) ||
6414 (IS_EXTENDER(NXT(len)))) {
6415 buf[len] = NXT(len);
6416 len++;
6417 if (len >= XML_MAX_NAMELEN) {
6418 xmlGenericError(xmlGenericErrorContext,
6419 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6420 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6421 (NXT(len) == '.') || (NXT(len) == '-') ||
6422 (NXT(len) == '_') || (NXT(len) == ':') ||
6423 (IS_COMBINING(NXT(len))) ||
6424 (IS_EXTENDER(NXT(len))))
6425 len++;
6426 break;
6427 }
6428 }
6429 return(xmlStrndup(buf, len));
6430}
6431
6432/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006433 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006434 * @ctxt: the XPath Parser context
6435 *
6436 * [19] PathExpr ::= LocationPath
6437 * | FilterExpr
6438 * | FilterExpr '/' RelativeLocationPath
6439 * | FilterExpr '//' RelativeLocationPath
6440 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006441 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006442 * The / operator and // operators combine an arbitrary expression
6443 * and a relative location path. It is an error if the expression
6444 * does not evaluate to a node-set.
6445 * The / operator does composition in the same way as when / is
6446 * used in a location path. As in location paths, // is short for
6447 * /descendant-or-self::node()/.
6448 */
6449
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006450static void
6451xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006452 int lc = 1; /* Should we branch to LocationPath ? */
6453 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6454
6455 SKIP_BLANKS;
6456 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6457 (CUR == '\'') || (CUR == '"')) {
6458 lc = 0;
6459 } else if (CUR == '*') {
6460 /* relative or absolute location path */
6461 lc = 1;
6462 } else if (CUR == '/') {
6463 /* relative or absolute location path */
6464 lc = 1;
6465 } else if (CUR == '@') {
6466 /* relative abbreviated attribute location path */
6467 lc = 1;
6468 } else if (CUR == '.') {
6469 /* relative abbreviated attribute location path */
6470 lc = 1;
6471 } else {
6472 /*
6473 * Problem is finding if we have a name here whether it's:
6474 * - a nodetype
6475 * - a function call in which case it's followed by '('
6476 * - an axis in which case it's followed by ':'
6477 * - a element name
6478 * We do an a priori analysis here rather than having to
6479 * maintain parsed token content through the recursive function
6480 * calls. This looks uglier but makes the code quite easier to
6481 * read/write/debug.
6482 */
6483 SKIP_BLANKS;
6484 name = xmlXPathScanName(ctxt);
6485 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6486#ifdef DEBUG_STEP
6487 xmlGenericError(xmlGenericErrorContext,
6488 "PathExpr: Axis\n");
6489#endif
6490 lc = 1;
6491 xmlFree(name);
6492 } else if (name != NULL) {
6493 int len =xmlStrlen(name);
6494 int blank = 0;
6495
6496
6497 while (NXT(len) != 0) {
6498 if (NXT(len) == '/') {
6499 /* element name */
6500#ifdef DEBUG_STEP
6501 xmlGenericError(xmlGenericErrorContext,
6502 "PathExpr: AbbrRelLocation\n");
6503#endif
6504 lc = 1;
6505 break;
6506 } else if (IS_BLANK(NXT(len))) {
6507 /* skip to next */
6508 blank = 1;
6509 } else if (NXT(len) == ':') {
6510#ifdef DEBUG_STEP
6511 xmlGenericError(xmlGenericErrorContext,
6512 "PathExpr: AbbrRelLocation\n");
6513#endif
6514 lc = 1;
6515 break;
6516 } else if ((NXT(len) == '(')) {
6517 /* Note Type or Function */
6518 if (xmlXPathIsNodeType(name)) {
6519#ifdef DEBUG_STEP
6520 xmlGenericError(xmlGenericErrorContext,
6521 "PathExpr: Type search\n");
6522#endif
6523 lc = 1;
6524 } else {
6525#ifdef DEBUG_STEP
6526 xmlGenericError(xmlGenericErrorContext,
6527 "PathExpr: function call\n");
6528#endif
6529 lc = 0;
6530 }
6531 break;
6532 } else if ((NXT(len) == '[')) {
6533 /* element name */
6534#ifdef DEBUG_STEP
6535 xmlGenericError(xmlGenericErrorContext,
6536 "PathExpr: AbbrRelLocation\n");
6537#endif
6538 lc = 1;
6539 break;
6540 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6541 (NXT(len) == '=')) {
6542 lc = 1;
6543 break;
6544 } else {
6545 lc = 1;
6546 break;
6547 }
6548 len++;
6549 }
6550 if (NXT(len) == 0) {
6551#ifdef DEBUG_STEP
6552 xmlGenericError(xmlGenericErrorContext,
6553 "PathExpr: AbbrRelLocation\n");
6554#endif
6555 /* element name */
6556 lc = 1;
6557 }
6558 xmlFree(name);
6559 } else {
6560 /* make sure all cases are covered explicitely */
6561 XP_ERROR(XPATH_EXPR_ERROR);
6562 }
6563 }
6564
6565 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006566 if (CUR == '/') {
6567 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6568 } else {
6569 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006570 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006571 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006572 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006573 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006574 CHECK_ERROR;
6575 if ((CUR == '/') && (NXT(1) == '/')) {
6576 SKIP(2);
6577 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006578
6579 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6580 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6581 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6582
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006583 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006584 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006585 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006586 }
6587 }
6588 SKIP_BLANKS;
6589}
6590
6591/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006592 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006593 * @ctxt: the XPath Parser context
6594 *
6595 * [18] UnionExpr ::= PathExpr
6596 * | UnionExpr '|' PathExpr
6597 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006598 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006599 */
6600
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006601static void
6602xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6603 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006604 CHECK_ERROR;
6605 SKIP_BLANKS;
6606 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006607 int op1 = ctxt->comp->last;
6608 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006609
6610 NEXT;
6611 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006612 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006613
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006614 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6615
Owen Taylor3473f882001-02-23 17:55:21 +00006616 SKIP_BLANKS;
6617 }
Owen Taylor3473f882001-02-23 17:55:21 +00006618}
6619
6620/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006621 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006622 * @ctxt: the XPath Parser context
6623 *
6624 * [27] UnaryExpr ::= UnionExpr
6625 * | '-' UnaryExpr
6626 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006627 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006628 */
6629
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006630static void
6631xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006632 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006633 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006634
6635 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006636 while (CUR == '-') {
6637 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006638 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006639 NEXT;
6640 SKIP_BLANKS;
6641 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006642
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006643 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006644 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006645 if (found) {
6646 if (minus)
6647 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6648 else
6649 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006650 }
6651}
6652
6653/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006654 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006655 * @ctxt: the XPath Parser context
6656 *
6657 * [26] MultiplicativeExpr ::= UnaryExpr
6658 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6659 * | MultiplicativeExpr 'div' UnaryExpr
6660 * | MultiplicativeExpr 'mod' UnaryExpr
6661 * [34] MultiplyOperator ::= '*'
6662 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006663 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006664 */
6665
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006666static void
6667xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6668 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006669 CHECK_ERROR;
6670 SKIP_BLANKS;
6671 while ((CUR == '*') ||
6672 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6673 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6674 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006675 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006676
6677 if (CUR == '*') {
6678 op = 0;
6679 NEXT;
6680 } else if (CUR == 'd') {
6681 op = 1;
6682 SKIP(3);
6683 } else if (CUR == 'm') {
6684 op = 2;
6685 SKIP(3);
6686 }
6687 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006688 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006689 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006690 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006691 SKIP_BLANKS;
6692 }
6693}
6694
6695/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006696 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006697 * @ctxt: the XPath Parser context
6698 *
6699 * [25] AdditiveExpr ::= MultiplicativeExpr
6700 * | AdditiveExpr '+' MultiplicativeExpr
6701 * | AdditiveExpr '-' MultiplicativeExpr
6702 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006703 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006704 */
6705
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006706static void
6707xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006708
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006709 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006710 CHECK_ERROR;
6711 SKIP_BLANKS;
6712 while ((CUR == '+') || (CUR == '-')) {
6713 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006714 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006715
6716 if (CUR == '+') plus = 1;
6717 else plus = 0;
6718 NEXT;
6719 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006720 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006721 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006722 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006723 SKIP_BLANKS;
6724 }
6725}
6726
6727/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006728 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006729 * @ctxt: the XPath Parser context
6730 *
6731 * [24] RelationalExpr ::= AdditiveExpr
6732 * | RelationalExpr '<' AdditiveExpr
6733 * | RelationalExpr '>' AdditiveExpr
6734 * | RelationalExpr '<=' AdditiveExpr
6735 * | RelationalExpr '>=' AdditiveExpr
6736 *
6737 * A <= B > C is allowed ? Answer from James, yes with
6738 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6739 * which is basically what got implemented.
6740 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006741 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006742 * on the stack
6743 */
6744
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006745static void
6746xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6747 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006748 CHECK_ERROR;
6749 SKIP_BLANKS;
6750 while ((CUR == '<') ||
6751 (CUR == '>') ||
6752 ((CUR == '<') && (NXT(1) == '=')) ||
6753 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006754 int inf, strict;
6755 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006756
6757 if (CUR == '<') inf = 1;
6758 else inf = 0;
6759 if (NXT(1) == '=') strict = 0;
6760 else strict = 1;
6761 NEXT;
6762 if (!strict) NEXT;
6763 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006764 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006765 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006766 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006767 SKIP_BLANKS;
6768 }
6769}
6770
6771/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006772 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006773 * @ctxt: the XPath Parser context
6774 *
6775 * [23] EqualityExpr ::= RelationalExpr
6776 * | EqualityExpr '=' RelationalExpr
6777 * | EqualityExpr '!=' RelationalExpr
6778 *
6779 * A != B != C is allowed ? Answer from James, yes with
6780 * (RelationalExpr = RelationalExpr) = RelationalExpr
6781 * (RelationalExpr != RelationalExpr) != RelationalExpr
6782 * which is basically what got implemented.
6783 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006784 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006785 *
6786 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006787static void
6788xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6789 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006790 CHECK_ERROR;
6791 SKIP_BLANKS;
6792 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006793 int eq;
6794 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006795
6796 if (CUR == '=') eq = 1;
6797 else eq = 0;
6798 NEXT;
6799 if (!eq) NEXT;
6800 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006801 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006802 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006803 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006804 SKIP_BLANKS;
6805 }
6806}
6807
6808/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006809 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006810 * @ctxt: the XPath Parser context
6811 *
6812 * [22] AndExpr ::= EqualityExpr
6813 * | AndExpr 'and' EqualityExpr
6814 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006815 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006816 *
6817 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006818static void
6819xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6820 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006821 CHECK_ERROR;
6822 SKIP_BLANKS;
6823 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006824 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006825 SKIP(3);
6826 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006827 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006828 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006829 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006830 SKIP_BLANKS;
6831 }
6832}
6833
6834/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006835 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006836 * @ctxt: the XPath Parser context
6837 *
6838 * [14] Expr ::= OrExpr
6839 * [21] OrExpr ::= AndExpr
6840 * | OrExpr 'or' AndExpr
6841 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006842 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006843 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006844static void
6845xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6846 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006847 CHECK_ERROR;
6848 SKIP_BLANKS;
6849 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006850 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006851 SKIP(2);
6852 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006853 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006854 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006855 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6856 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006857 SKIP_BLANKS;
6858 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006859 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6860 /* more ops could be optimized too */
6861 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6862 }
Owen Taylor3473f882001-02-23 17:55:21 +00006863}
6864
6865/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006866 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006867 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006868 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006869 *
6870 * [8] Predicate ::= '[' PredicateExpr ']'
6871 * [9] PredicateExpr ::= Expr
6872 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006873 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006874 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006875static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006876xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006877 int op1 = ctxt->comp->last;
6878
6879 SKIP_BLANKS;
6880 if (CUR != '[') {
6881 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6882 }
6883 NEXT;
6884 SKIP_BLANKS;
6885
6886 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006887 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006888 CHECK_ERROR;
6889
6890 if (CUR != ']') {
6891 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6892 }
6893
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006894 if (filter)
6895 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6896 else
6897 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006898
6899 NEXT;
6900 SKIP_BLANKS;
6901}
6902
6903/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006904 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006905 * @ctxt: the XPath Parser context
6906 * @test: pointer to a xmlXPathTestVal
6907 * @type: pointer to a xmlXPathTypeVal
6908 * @prefix: placeholder for a possible name prefix
6909 *
6910 * [7] NodeTest ::= NameTest
6911 * | NodeType '(' ')'
6912 * | 'processing-instruction' '(' Literal ')'
6913 *
6914 * [37] NameTest ::= '*'
6915 * | NCName ':' '*'
6916 * | QName
6917 * [38] NodeType ::= 'comment'
6918 * | 'text'
6919 * | 'processing-instruction'
6920 * | 'node'
6921 *
6922 * Returns the name found and update @test, @type and @prefix appropriately
6923 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006924static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006925xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6926 xmlXPathTypeVal *type, const xmlChar **prefix,
6927 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006928 int blanks;
6929
6930 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6931 STRANGE;
6932 return(NULL);
6933 }
6934 *type = 0;
6935 *test = 0;
6936 *prefix = NULL;
6937 SKIP_BLANKS;
6938
6939 if ((name == NULL) && (CUR == '*')) {
6940 /*
6941 * All elements
6942 */
6943 NEXT;
6944 *test = NODE_TEST_ALL;
6945 return(NULL);
6946 }
6947
6948 if (name == NULL)
6949 name = xmlXPathParseNCName(ctxt);
6950 if (name == NULL) {
6951 XP_ERROR0(XPATH_EXPR_ERROR);
6952 }
6953
6954 blanks = IS_BLANK(CUR);
6955 SKIP_BLANKS;
6956 if (CUR == '(') {
6957 NEXT;
6958 /*
6959 * NodeType or PI search
6960 */
6961 if (xmlStrEqual(name, BAD_CAST "comment"))
6962 *type = NODE_TYPE_COMMENT;
6963 else if (xmlStrEqual(name, BAD_CAST "node"))
6964 *type = NODE_TYPE_NODE;
6965 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6966 *type = NODE_TYPE_PI;
6967 else if (xmlStrEqual(name, BAD_CAST "text"))
6968 *type = NODE_TYPE_TEXT;
6969 else {
6970 if (name != NULL)
6971 xmlFree(name);
6972 XP_ERROR0(XPATH_EXPR_ERROR);
6973 }
6974
6975 *test = NODE_TEST_TYPE;
6976
6977 SKIP_BLANKS;
6978 if (*type == NODE_TYPE_PI) {
6979 /*
6980 * Specific case: search a PI by name.
6981 */
Owen Taylor3473f882001-02-23 17:55:21 +00006982 if (name != NULL)
6983 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006984 name = NULL;
6985 if (CUR != ')') {
6986 name = xmlXPathParseLiteral(ctxt);
6987 CHECK_ERROR 0;
6988 SKIP_BLANKS;
6989 }
Owen Taylor3473f882001-02-23 17:55:21 +00006990 }
6991 if (CUR != ')') {
6992 if (name != NULL)
6993 xmlFree(name);
6994 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6995 }
6996 NEXT;
6997 return(name);
6998 }
6999 *test = NODE_TEST_NAME;
7000 if ((!blanks) && (CUR == ':')) {
7001 NEXT;
7002
7003 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007004 * Since currently the parser context don't have a
7005 * namespace list associated:
7006 * The namespace name for this prefix can be computed
7007 * only at evaluation time. The compilation is done
7008 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007009 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007010#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007011 *prefix = xmlXPathNsLookup(ctxt->context, name);
7012 if (name != NULL)
7013 xmlFree(name);
7014 if (*prefix == NULL) {
7015 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7016 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007017#else
7018 *prefix = name;
7019#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007020
7021 if (CUR == '*') {
7022 /*
7023 * All elements
7024 */
7025 NEXT;
7026 *test = NODE_TEST_ALL;
7027 return(NULL);
7028 }
7029
7030 name = xmlXPathParseNCName(ctxt);
7031 if (name == NULL) {
7032 XP_ERROR0(XPATH_EXPR_ERROR);
7033 }
7034 }
7035 return(name);
7036}
7037
7038/**
7039 * xmlXPathIsAxisName:
7040 * @name: a preparsed name token
7041 *
7042 * [6] AxisName ::= 'ancestor'
7043 * | 'ancestor-or-self'
7044 * | 'attribute'
7045 * | 'child'
7046 * | 'descendant'
7047 * | 'descendant-or-self'
7048 * | 'following'
7049 * | 'following-sibling'
7050 * | 'namespace'
7051 * | 'parent'
7052 * | 'preceding'
7053 * | 'preceding-sibling'
7054 * | 'self'
7055 *
7056 * Returns the axis or 0
7057 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007058static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007059xmlXPathIsAxisName(const xmlChar *name) {
7060 xmlXPathAxisVal ret = 0;
7061 switch (name[0]) {
7062 case 'a':
7063 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7064 ret = AXIS_ANCESTOR;
7065 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7066 ret = AXIS_ANCESTOR_OR_SELF;
7067 if (xmlStrEqual(name, BAD_CAST "attribute"))
7068 ret = AXIS_ATTRIBUTE;
7069 break;
7070 case 'c':
7071 if (xmlStrEqual(name, BAD_CAST "child"))
7072 ret = AXIS_CHILD;
7073 break;
7074 case 'd':
7075 if (xmlStrEqual(name, BAD_CAST "descendant"))
7076 ret = AXIS_DESCENDANT;
7077 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7078 ret = AXIS_DESCENDANT_OR_SELF;
7079 break;
7080 case 'f':
7081 if (xmlStrEqual(name, BAD_CAST "following"))
7082 ret = AXIS_FOLLOWING;
7083 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7084 ret = AXIS_FOLLOWING_SIBLING;
7085 break;
7086 case 'n':
7087 if (xmlStrEqual(name, BAD_CAST "namespace"))
7088 ret = AXIS_NAMESPACE;
7089 break;
7090 case 'p':
7091 if (xmlStrEqual(name, BAD_CAST "parent"))
7092 ret = AXIS_PARENT;
7093 if (xmlStrEqual(name, BAD_CAST "preceding"))
7094 ret = AXIS_PRECEDING;
7095 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7096 ret = AXIS_PRECEDING_SIBLING;
7097 break;
7098 case 's':
7099 if (xmlStrEqual(name, BAD_CAST "self"))
7100 ret = AXIS_SELF;
7101 break;
7102 }
7103 return(ret);
7104}
7105
7106/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007107 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007108 * @ctxt: the XPath Parser context
7109 *
7110 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7111 * | AbbreviatedStep
7112 *
7113 * [12] AbbreviatedStep ::= '.' | '..'
7114 *
7115 * [5] AxisSpecifier ::= AxisName '::'
7116 * | AbbreviatedAxisSpecifier
7117 *
7118 * [13] AbbreviatedAxisSpecifier ::= '@'?
7119 *
7120 * Modified for XPtr range support as:
7121 *
7122 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7123 * | AbbreviatedStep
7124 * | 'range-to' '(' Expr ')' Predicate*
7125 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007126 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007127 * A location step of . is short for self::node(). This is
7128 * particularly useful in conjunction with //. For example, the
7129 * location path .//para is short for
7130 * self::node()/descendant-or-self::node()/child::para
7131 * and so will select all para descendant elements of the context
7132 * node.
7133 * Similarly, a location step of .. is short for parent::node().
7134 * For example, ../title is short for parent::node()/child::title
7135 * and so will select the title children of the parent of the context
7136 * node.
7137 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007138static void
7139xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007140#ifdef LIBXML_XPTR_ENABLED
7141 int rangeto = 0;
7142 int op2 = -1;
7143#endif
7144
Owen Taylor3473f882001-02-23 17:55:21 +00007145 SKIP_BLANKS;
7146 if ((CUR == '.') && (NXT(1) == '.')) {
7147 SKIP(2);
7148 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007149 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7150 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007151 } else if (CUR == '.') {
7152 NEXT;
7153 SKIP_BLANKS;
7154 } else {
7155 xmlChar *name = NULL;
7156 const xmlChar *prefix = NULL;
7157 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007158 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007159 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007160 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007161
7162 /*
7163 * The modification needed for XPointer change to the production
7164 */
7165#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007166 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007167 name = xmlXPathParseNCName(ctxt);
7168 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007169 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007170 xmlFree(name);
7171 SKIP_BLANKS;
7172 if (CUR != '(') {
7173 XP_ERROR(XPATH_EXPR_ERROR);
7174 }
7175 NEXT;
7176 SKIP_BLANKS;
7177
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007178 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007179 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007180 CHECK_ERROR;
7181
7182 SKIP_BLANKS;
7183 if (CUR != ')') {
7184 XP_ERROR(XPATH_EXPR_ERROR);
7185 }
7186 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007187 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007188 goto eval_predicates;
7189 }
7190 }
7191#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007192 if (CUR == '*') {
7193 axis = AXIS_CHILD;
7194 } else {
7195 if (name == NULL)
7196 name = xmlXPathParseNCName(ctxt);
7197 if (name != NULL) {
7198 axis = xmlXPathIsAxisName(name);
7199 if (axis != 0) {
7200 SKIP_BLANKS;
7201 if ((CUR == ':') && (NXT(1) == ':')) {
7202 SKIP(2);
7203 xmlFree(name);
7204 name = NULL;
7205 } else {
7206 /* an element name can conflict with an axis one :-\ */
7207 axis = AXIS_CHILD;
7208 }
Owen Taylor3473f882001-02-23 17:55:21 +00007209 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007210 axis = AXIS_CHILD;
7211 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007212 } else if (CUR == '@') {
7213 NEXT;
7214 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007215 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007216 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007217 }
Owen Taylor3473f882001-02-23 17:55:21 +00007218 }
7219
7220 CHECK_ERROR;
7221
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007222 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007223 if (test == 0)
7224 return;
7225
7226#ifdef DEBUG_STEP
7227 xmlGenericError(xmlGenericErrorContext,
7228 "Basis : computing new set\n");
7229#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007230
Owen Taylor3473f882001-02-23 17:55:21 +00007231#ifdef DEBUG_STEP
7232 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007233 if (ctxt->value == NULL)
7234 xmlGenericError(xmlGenericErrorContext, "no value\n");
7235 else if (ctxt->value->nodesetval == NULL)
7236 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7237 else
7238 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007239#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007240
7241eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007242 op1 = ctxt->comp->last;
7243 ctxt->comp->last = -1;
7244
Owen Taylor3473f882001-02-23 17:55:21 +00007245 SKIP_BLANKS;
7246 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007247 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007248 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007249
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007250#ifdef LIBXML_XPTR_ENABLED
7251 if (rangeto) {
7252 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7253 } else
7254#endif
7255 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7256 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007257
Owen Taylor3473f882001-02-23 17:55:21 +00007258 }
7259#ifdef DEBUG_STEP
7260 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007261 if (ctxt->value == NULL)
7262 xmlGenericError(xmlGenericErrorContext, "no value\n");
7263 else if (ctxt->value->nodesetval == NULL)
7264 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7265 else
7266 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7267 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007268#endif
7269}
7270
7271/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007272 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007273 * @ctxt: the XPath Parser context
7274 *
7275 * [3] RelativeLocationPath ::= Step
7276 * | RelativeLocationPath '/' Step
7277 * | AbbreviatedRelativeLocationPath
7278 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7279 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007280 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007281 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007282static void
Owen Taylor3473f882001-02-23 17:55:21 +00007283#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007284xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007285#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007286xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007287#endif
7288(xmlXPathParserContextPtr ctxt) {
7289 SKIP_BLANKS;
7290 if ((CUR == '/') && (NXT(1) == '/')) {
7291 SKIP(2);
7292 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007293 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7294 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007295 } else if (CUR == '/') {
7296 NEXT;
7297 SKIP_BLANKS;
7298 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007299 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007300 SKIP_BLANKS;
7301 while (CUR == '/') {
7302 if ((CUR == '/') && (NXT(1) == '/')) {
7303 SKIP(2);
7304 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007305 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007306 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007307 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007308 } else if (CUR == '/') {
7309 NEXT;
7310 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007311 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007312 }
7313 SKIP_BLANKS;
7314 }
7315}
7316
7317/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007318 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007319 * @ctxt: the XPath Parser context
7320 *
7321 * [1] LocationPath ::= RelativeLocationPath
7322 * | AbsoluteLocationPath
7323 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7324 * | AbbreviatedAbsoluteLocationPath
7325 * [10] AbbreviatedAbsoluteLocationPath ::=
7326 * '//' RelativeLocationPath
7327 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007328 * Compile a location path
7329 *
Owen Taylor3473f882001-02-23 17:55:21 +00007330 * // is short for /descendant-or-self::node()/. For example,
7331 * //para is short for /descendant-or-self::node()/child::para and
7332 * so will select any para element in the document (even a para element
7333 * that is a document element will be selected by //para since the
7334 * document element node is a child of the root node); div//para is
7335 * short for div/descendant-or-self::node()/child::para and so will
7336 * select all para descendants of div children.
7337 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007338static void
7339xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007340 SKIP_BLANKS;
7341 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007342 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007343 } else {
7344 while (CUR == '/') {
7345 if ((CUR == '/') && (NXT(1) == '/')) {
7346 SKIP(2);
7347 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007348 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7349 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007350 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007351 } else if (CUR == '/') {
7352 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007353 SKIP_BLANKS;
7354 if ((CUR != 0 ) &&
7355 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7356 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007357 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007358 }
7359 }
7360 }
7361}
7362
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007363/************************************************************************
7364 * *
7365 * XPath precompiled expression evaluation *
7366 * *
7367 ************************************************************************/
7368
Daniel Veillardf06307e2001-07-03 10:35:50 +00007369static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007370xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7371
7372/**
7373 * xmlXPathNodeCollectAndTest:
7374 * @ctxt: the XPath Parser context
7375 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007376 * @first: pointer to the first element in document order
7377 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007378 *
7379 * This is the function implementing a step: based on the current list
7380 * of nodes, it builds up a new list, looking at all nodes under that
7381 * axis and selecting them it also do the predicate filtering
7382 *
7383 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007384 *
7385 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007386 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007387static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007388xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007389 xmlXPathStepOpPtr op,
7390 xmlNodePtr * first, xmlNodePtr * last)
7391{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007392 xmlXPathAxisVal axis = op->value;
7393 xmlXPathTestVal test = op->value2;
7394 xmlXPathTypeVal type = op->value3;
7395 const xmlChar *prefix = op->value4;
7396 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007397 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007398
7399#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007400 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007401#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007402 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007403 xmlNodeSetPtr ret, list;
7404 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007405 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007406 xmlNodePtr cur = NULL;
7407 xmlXPathObjectPtr obj;
7408 xmlNodeSetPtr nodelist;
7409 xmlNodePtr tmp;
7410
Daniel Veillardf06307e2001-07-03 10:35:50 +00007411 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007412 obj = valuePop(ctxt);
7413 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007414 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007415 URI = xmlXPathNsLookup(ctxt->context, prefix);
7416 if (URI == NULL)
7417 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00007418 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007419#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007420 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007421#endif
7422 switch (axis) {
7423 case AXIS_ANCESTOR:
7424#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007425 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007426#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007427 first = NULL;
7428 next = xmlXPathNextAncestor;
7429 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007430 case AXIS_ANCESTOR_OR_SELF:
7431#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007432 xmlGenericError(xmlGenericErrorContext,
7433 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007434#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007435 first = NULL;
7436 next = xmlXPathNextAncestorOrSelf;
7437 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007438 case AXIS_ATTRIBUTE:
7439#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007440 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007441#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007442 first = NULL;
7443 last = NULL;
7444 next = xmlXPathNextAttribute;
7445 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007446 case AXIS_CHILD:
7447#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007448 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007449#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007450 last = NULL;
7451 next = xmlXPathNextChild;
7452 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007453 case AXIS_DESCENDANT:
7454#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007455 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007456#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007457 last = NULL;
7458 next = xmlXPathNextDescendant;
7459 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007460 case AXIS_DESCENDANT_OR_SELF:
7461#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007462 xmlGenericError(xmlGenericErrorContext,
7463 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007464#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007465 last = NULL;
7466 next = xmlXPathNextDescendantOrSelf;
7467 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007468 case AXIS_FOLLOWING:
7469#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007470 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007471#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007472 last = NULL;
7473 next = xmlXPathNextFollowing;
7474 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007475 case AXIS_FOLLOWING_SIBLING:
7476#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007477 xmlGenericError(xmlGenericErrorContext,
7478 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007479#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007480 last = NULL;
7481 next = xmlXPathNextFollowingSibling;
7482 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007483 case AXIS_NAMESPACE:
7484#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007485 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007486#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007487 first = NULL;
7488 last = NULL;
7489 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
7490 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007491 case AXIS_PARENT:
7492#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007493 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007494#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007495 first = NULL;
7496 next = xmlXPathNextParent;
7497 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007498 case AXIS_PRECEDING:
7499#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007500 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007501#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007502 first = NULL;
7503 next = xmlXPathNextPrecedingInternal;
7504 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007505 case AXIS_PRECEDING_SIBLING:
7506#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007507 xmlGenericError(xmlGenericErrorContext,
7508 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007509#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007510 first = NULL;
7511 next = xmlXPathNextPrecedingSibling;
7512 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007513 case AXIS_SELF:
7514#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007515 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007516#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007517 first = NULL;
7518 last = NULL;
7519 next = xmlXPathNextSelf;
7520 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007521 }
7522 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00007523 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007524
7525 nodelist = obj->nodesetval;
7526 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007527 xmlXPathFreeObject(obj);
7528 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7529 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007530 }
7531 addNode = xmlXPathNodeSetAddUnique;
7532 ret = NULL;
7533#ifdef DEBUG_STEP
7534 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007535 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007536 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007537 case NODE_TEST_NONE:
7538 xmlGenericError(xmlGenericErrorContext,
7539 " searching for none !!!\n");
7540 break;
7541 case NODE_TEST_TYPE:
7542 xmlGenericError(xmlGenericErrorContext,
7543 " searching for type %d\n", type);
7544 break;
7545 case NODE_TEST_PI:
7546 xmlGenericError(xmlGenericErrorContext,
7547 " searching for PI !!!\n");
7548 break;
7549 case NODE_TEST_ALL:
7550 xmlGenericError(xmlGenericErrorContext,
7551 " searching for *\n");
7552 break;
7553 case NODE_TEST_NS:
7554 xmlGenericError(xmlGenericErrorContext,
7555 " searching for namespace %s\n",
7556 prefix);
7557 break;
7558 case NODE_TEST_NAME:
7559 xmlGenericError(xmlGenericErrorContext,
7560 " searching for name %s\n", name);
7561 if (prefix != NULL)
7562 xmlGenericError(xmlGenericErrorContext,
7563 " with namespace %s\n", prefix);
7564 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007565 }
7566 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7567#endif
7568 /*
7569 * 2.3 Node Tests
7570 * - For the attribute axis, the principal node type is attribute.
7571 * - For the namespace axis, the principal node type is namespace.
7572 * - For other axes, the principal node type is element.
7573 *
7574 * A node test * is true for any node of the
7575 * principal node type. For example, child::* willi
7576 * select all element children of the context node
7577 */
7578 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007579 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007580 ctxt->context->node = nodelist->nodeTab[i];
7581
Daniel Veillardf06307e2001-07-03 10:35:50 +00007582 cur = NULL;
7583 list = xmlXPathNodeSetCreate(NULL);
7584 do {
7585 cur = next(ctxt, cur);
7586 if (cur == NULL)
7587 break;
7588 if ((first != NULL) && (*first == cur))
7589 break;
7590 if (((t % 256) == 0) &&
7591 (first != NULL) && (*first != NULL) &&
7592 (xmlXPathCmpNodes(*first, cur) >= 0))
7593 break;
7594 if ((last != NULL) && (*last == cur))
7595 break;
7596 if (((t % 256) == 0) &&
7597 (last != NULL) && (*last != NULL) &&
7598 (xmlXPathCmpNodes(cur, *last) >= 0))
7599 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007600 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007601#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007602 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7603#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007604 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007605 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007606 ctxt->context->node = tmp;
7607 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007608 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007609 if ((cur->type == type) ||
7610 ((type == NODE_TYPE_NODE) &&
7611 ((cur->type == XML_DOCUMENT_NODE) ||
7612 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7613 (cur->type == XML_ELEMENT_NODE) ||
7614 (cur->type == XML_PI_NODE) ||
7615 (cur->type == XML_COMMENT_NODE) ||
7616 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00007617 (cur->type == XML_TEXT_NODE))) ||
7618 ((type == NODE_TYPE_TEXT) &&
7619 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007620#ifdef DEBUG_STEP
7621 n++;
7622#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007623 addNode(list, cur);
7624 }
7625 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007626 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007627 if (cur->type == XML_PI_NODE) {
7628 if ((name != NULL) &&
7629 (!xmlStrEqual(name, cur->name)))
7630 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007631#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007632 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007633#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007634 addNode(list, cur);
7635 }
7636 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007637 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007638 if (axis == AXIS_ATTRIBUTE) {
7639 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007640#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007641 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007642#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007643 addNode(list, cur);
7644 }
7645 } else if (axis == AXIS_NAMESPACE) {
7646 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007647#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007648 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007649#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007650 addNode(list, cur);
7651 }
7652 } else {
7653 if (cur->type == XML_ELEMENT_NODE) {
7654 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007655#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007656 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007657#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007658 addNode(list, cur);
7659 } else if ((cur->ns != NULL) &&
7660 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007661#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007662 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007663#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007664 addNode(list, cur);
7665 }
7666 }
7667 }
7668 break;
7669 case NODE_TEST_NS:{
7670 TODO;
7671 break;
7672 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007673 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007674 switch (cur->type) {
7675 case XML_ELEMENT_NODE:
7676 if (xmlStrEqual(name, cur->name)) {
7677 if (prefix == NULL) {
7678 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007679#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007680 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007681#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007682 addNode(list, cur);
7683 }
7684 } else {
7685 if ((cur->ns != NULL) &&
7686 (xmlStrEqual(URI,
7687 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007688#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007689 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007690#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007691 addNode(list, cur);
7692 }
7693 }
7694 }
7695 break;
7696 case XML_ATTRIBUTE_NODE:{
7697 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007698
Daniel Veillardf06307e2001-07-03 10:35:50 +00007699 if (xmlStrEqual(name, attr->name)) {
7700 if (prefix == NULL) {
7701 if ((attr->ns == NULL) ||
7702 (attr->ns->prefix == NULL)) {
7703#ifdef DEBUG_STEP
7704 n++;
7705#endif
7706 addNode(list,
7707 (xmlNodePtr) attr);
7708 }
7709 } else {
7710 if ((attr->ns != NULL) &&
7711 (xmlStrEqual(URI,
7712 attr->ns->
7713 href))) {
7714#ifdef DEBUG_STEP
7715 n++;
7716#endif
7717 addNode(list,
7718 (xmlNodePtr) attr);
7719 }
7720 }
7721 }
7722 break;
7723 }
7724 case XML_NAMESPACE_DECL:
7725 if (cur->type == XML_NAMESPACE_DECL) {
7726 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007727
Daniel Veillardf06307e2001-07-03 10:35:50 +00007728 if ((ns->prefix != NULL) && (name != NULL)
7729 && (xmlStrEqual(ns->prefix, name))) {
7730#ifdef DEBUG_STEP
7731 n++;
7732#endif
7733 addNode(list, cur);
7734 }
7735 }
7736 break;
7737 default:
7738 break;
7739 }
7740 break;
7741 break;
7742 }
7743 } while (cur != NULL);
7744
7745 /*
7746 * If there is some predicate filtering do it now
7747 */
7748 if (op->ch2 != -1) {
7749 xmlXPathObjectPtr obj2;
7750
7751 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7752 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7753 CHECK_TYPE0(XPATH_NODESET);
7754 obj2 = valuePop(ctxt);
7755 list = obj2->nodesetval;
7756 obj2->nodesetval = NULL;
7757 xmlXPathFreeObject(obj2);
7758 }
7759 if (ret == NULL) {
7760 ret = list;
7761 } else {
7762 ret = xmlXPathNodeSetMerge(ret, list);
7763 xmlXPathFreeNodeSet(list);
7764 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007765 }
7766 ctxt->context->node = tmp;
7767#ifdef DEBUG_STEP
7768 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007769 "\nExamined %d nodes, found %d nodes at that step\n",
7770 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007771#endif
7772 xmlXPathFreeObject(obj);
7773 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +00007774 return(t);
7775}
7776
7777/**
7778 * xmlXPathNodeCollectAndTestNth:
7779 * @ctxt: the XPath Parser context
7780 * @op: the XPath precompiled step operation
7781 * @indx: the index to collect
7782 * @first: pointer to the first element in document order
7783 * @last: pointer to the last element in document order
7784 *
7785 * This is the function implementing a step: based on the current list
7786 * of nodes, it builds up a new list, looking at all nodes under that
7787 * axis and selecting them it also do the predicate filtering
7788 *
7789 * Pushes the new NodeSet resulting from the search.
7790 * Returns the number of node traversed
7791 */
7792static int
7793xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
7794 xmlXPathStepOpPtr op, int indx,
7795 xmlNodePtr * first, xmlNodePtr * last)
7796{
7797 xmlXPathAxisVal axis = op->value;
7798 xmlXPathTestVal test = op->value2;
7799 xmlXPathTypeVal type = op->value3;
7800 const xmlChar *prefix = op->value4;
7801 const xmlChar *name = op->value5;
7802 const xmlChar *URI = NULL;
7803 int n = 0, t = 0;
7804
7805 int i;
7806 xmlNodeSetPtr list;
7807 xmlXPathTraversalFunction next = NULL;
7808 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
7809 xmlNodePtr cur = NULL;
7810 xmlXPathObjectPtr obj;
7811 xmlNodeSetPtr nodelist;
7812 xmlNodePtr tmp;
7813
7814 CHECK_TYPE0(XPATH_NODESET);
7815 obj = valuePop(ctxt);
7816 addNode = xmlXPathNodeSetAdd;
7817 if (prefix != NULL) {
7818 URI = xmlXPathNsLookup(ctxt->context, prefix);
7819 if (URI == NULL)
7820 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7821 }
7822#ifdef DEBUG_STEP_NTH
7823 xmlGenericError(xmlGenericErrorContext, "new step : ");
7824 if (first != NULL) {
7825 if (*first != NULL)
7826 xmlGenericError(xmlGenericErrorContext, "first = %s ",
7827 (*first)->name);
7828 else
7829 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
7830 }
7831 if (last != NULL) {
7832 if (*last != NULL)
7833 xmlGenericError(xmlGenericErrorContext, "last = %s ",
7834 (*last)->name);
7835 else
7836 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
7837 }
7838#endif
7839 switch (axis) {
7840 case AXIS_ANCESTOR:
7841#ifdef DEBUG_STEP_NTH
7842 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
7843#endif
7844 first = NULL;
7845 next = xmlXPathNextAncestor;
7846 break;
7847 case AXIS_ANCESTOR_OR_SELF:
7848#ifdef DEBUG_STEP_NTH
7849 xmlGenericError(xmlGenericErrorContext,
7850 "axis 'ancestors-or-self' ");
7851#endif
7852 first = NULL;
7853 next = xmlXPathNextAncestorOrSelf;
7854 break;
7855 case AXIS_ATTRIBUTE:
7856#ifdef DEBUG_STEP_NTH
7857 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
7858#endif
7859 first = NULL;
7860 last = NULL;
7861 next = xmlXPathNextAttribute;
7862 break;
7863 case AXIS_CHILD:
7864#ifdef DEBUG_STEP_NTH
7865 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
7866#endif
7867 last = NULL;
7868 next = xmlXPathNextChild;
7869 break;
7870 case AXIS_DESCENDANT:
7871#ifdef DEBUG_STEP_NTH
7872 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
7873#endif
7874 last = NULL;
7875 next = xmlXPathNextDescendant;
7876 break;
7877 case AXIS_DESCENDANT_OR_SELF:
7878#ifdef DEBUG_STEP_NTH
7879 xmlGenericError(xmlGenericErrorContext,
7880 "axis 'descendant-or-self' ");
7881#endif
7882 last = NULL;
7883 next = xmlXPathNextDescendantOrSelf;
7884 break;
7885 case AXIS_FOLLOWING:
7886#ifdef DEBUG_STEP_NTH
7887 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
7888#endif
7889 last = NULL;
7890 next = xmlXPathNextFollowing;
7891 break;
7892 case AXIS_FOLLOWING_SIBLING:
7893#ifdef DEBUG_STEP_NTH
7894 xmlGenericError(xmlGenericErrorContext,
7895 "axis 'following-siblings' ");
7896#endif
7897 last = NULL;
7898 next = xmlXPathNextFollowingSibling;
7899 break;
7900 case AXIS_NAMESPACE:
7901#ifdef DEBUG_STEP_NTH
7902 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
7903#endif
7904 last = NULL;
7905 first = NULL;
7906 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
7907 break;
7908 case AXIS_PARENT:
7909#ifdef DEBUG_STEP_NTH
7910 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
7911#endif
7912 first = NULL;
7913 next = xmlXPathNextParent;
7914 break;
7915 case AXIS_PRECEDING:
7916#ifdef DEBUG_STEP_NTH
7917 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
7918#endif
7919 first = NULL;
7920 next = xmlXPathNextPrecedingInternal;
7921 break;
7922 case AXIS_PRECEDING_SIBLING:
7923#ifdef DEBUG_STEP_NTH
7924 xmlGenericError(xmlGenericErrorContext,
7925 "axis 'preceding-sibling' ");
7926#endif
7927 first = NULL;
7928 next = xmlXPathNextPrecedingSibling;
7929 break;
7930 case AXIS_SELF:
7931#ifdef DEBUG_STEP_NTH
7932 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
7933#endif
7934 first = NULL;
7935 last = NULL;
7936 next = xmlXPathNextSelf;
7937 break;
7938 }
7939 if (next == NULL)
7940 return(0);
7941
7942 nodelist = obj->nodesetval;
7943 if (nodelist == NULL) {
7944 xmlXPathFreeObject(obj);
7945 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7946 return(0);
7947 }
7948 addNode = xmlXPathNodeSetAddUnique;
7949#ifdef DEBUG_STEP_NTH
7950 xmlGenericError(xmlGenericErrorContext,
7951 " context contains %d nodes\n", nodelist->nodeNr);
7952 switch (test) {
7953 case NODE_TEST_NONE:
7954 xmlGenericError(xmlGenericErrorContext,
7955 " searching for none !!!\n");
7956 break;
7957 case NODE_TEST_TYPE:
7958 xmlGenericError(xmlGenericErrorContext,
7959 " searching for type %d\n", type);
7960 break;
7961 case NODE_TEST_PI:
7962 xmlGenericError(xmlGenericErrorContext,
7963 " searching for PI !!!\n");
7964 break;
7965 case NODE_TEST_ALL:
7966 xmlGenericError(xmlGenericErrorContext,
7967 " searching for *\n");
7968 break;
7969 case NODE_TEST_NS:
7970 xmlGenericError(xmlGenericErrorContext,
7971 " searching for namespace %s\n",
7972 prefix);
7973 break;
7974 case NODE_TEST_NAME:
7975 xmlGenericError(xmlGenericErrorContext,
7976 " searching for name %s\n", name);
7977 if (prefix != NULL)
7978 xmlGenericError(xmlGenericErrorContext,
7979 " with namespace %s\n", prefix);
7980 break;
7981 }
7982 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7983#endif
7984 /*
7985 * 2.3 Node Tests
7986 * - For the attribute axis, the principal node type is attribute.
7987 * - For the namespace axis, the principal node type is namespace.
7988 * - For other axes, the principal node type is element.
7989 *
7990 * A node test * is true for any node of the
7991 * principal node type. For example, child::* willi
7992 * select all element children of the context node
7993 */
7994 tmp = ctxt->context->node;
7995 list = xmlXPathNodeSetCreate(NULL);
7996 for (i = 0; i < nodelist->nodeNr; i++) {
7997 ctxt->context->node = nodelist->nodeTab[i];
7998
7999 cur = NULL;
8000 n = 0;
8001 do {
8002 cur = next(ctxt, cur);
8003 if (cur == NULL)
8004 break;
8005 if ((first != NULL) && (*first == cur))
8006 break;
8007 if (((t % 256) == 0) &&
8008 (first != NULL) && (*first != NULL) &&
8009 (xmlXPathCmpNodes(*first, cur) >= 0))
8010 break;
8011 if ((last != NULL) && (*last == cur))
8012 break;
8013 if (((t % 256) == 0) &&
8014 (last != NULL) && (*last != NULL) &&
8015 (xmlXPathCmpNodes(cur, *last) >= 0))
8016 break;
8017 t++;
8018 switch (test) {
8019 case NODE_TEST_NONE:
8020 ctxt->context->node = tmp;
8021 STRANGE return(0);
8022 case NODE_TEST_TYPE:
8023 if ((cur->type == type) ||
8024 ((type == NODE_TYPE_NODE) &&
8025 ((cur->type == XML_DOCUMENT_NODE) ||
8026 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8027 (cur->type == XML_ELEMENT_NODE) ||
8028 (cur->type == XML_PI_NODE) ||
8029 (cur->type == XML_COMMENT_NODE) ||
8030 (cur->type == XML_CDATA_SECTION_NODE) ||
8031 (cur->type == XML_TEXT_NODE)))) {
8032 n++;
8033 if (n == indx)
8034 addNode(list, cur);
8035 }
8036 break;
8037 case NODE_TEST_PI:
8038 if (cur->type == XML_PI_NODE) {
8039 if ((name != NULL) &&
8040 (!xmlStrEqual(name, cur->name)))
8041 break;
8042 n++;
8043 if (n == indx)
8044 addNode(list, cur);
8045 }
8046 break;
8047 case NODE_TEST_ALL:
8048 if (axis == AXIS_ATTRIBUTE) {
8049 if (cur->type == XML_ATTRIBUTE_NODE) {
8050 n++;
8051 if (n == indx)
8052 addNode(list, cur);
8053 }
8054 } else if (axis == AXIS_NAMESPACE) {
8055 if (cur->type == XML_NAMESPACE_DECL) {
8056 n++;
8057 if (n == indx)
8058 addNode(list, cur);
8059 }
8060 } else {
8061 if (cur->type == XML_ELEMENT_NODE) {
8062 if (prefix == NULL) {
8063 n++;
8064 if (n == indx)
8065 addNode(list, cur);
8066 } else if ((cur->ns != NULL) &&
8067 (xmlStrEqual(URI, cur->ns->href))) {
8068 n++;
8069 if (n == indx)
8070 addNode(list, cur);
8071 }
8072 }
8073 }
8074 break;
8075 case NODE_TEST_NS:{
8076 TODO;
8077 break;
8078 }
8079 case NODE_TEST_NAME:
8080 switch (cur->type) {
8081 case XML_ELEMENT_NODE:
8082 if (xmlStrEqual(name, cur->name)) {
8083 if (prefix == NULL) {
8084 if (cur->ns == NULL) {
8085 n++;
8086 if (n == indx)
8087 addNode(list, cur);
8088 }
8089 } else {
8090 if ((cur->ns != NULL) &&
8091 (xmlStrEqual(URI,
8092 cur->ns->href))) {
8093 n++;
8094 if (n == indx)
8095 addNode(list, cur);
8096 }
8097 }
8098 }
8099 break;
8100 case XML_ATTRIBUTE_NODE:{
8101 xmlAttrPtr attr = (xmlAttrPtr) cur;
8102
8103 if (xmlStrEqual(name, attr->name)) {
8104 if (prefix == NULL) {
8105 if ((attr->ns == NULL) ||
8106 (attr->ns->prefix == NULL)) {
8107 n++;
8108 if (n == indx)
8109 addNode(list, cur);
8110 }
8111 } else {
8112 if ((attr->ns != NULL) &&
8113 (xmlStrEqual(URI,
8114 attr->ns->
8115 href))) {
8116 n++;
8117 if (n == indx)
8118 addNode(list, cur);
8119 }
8120 }
8121 }
8122 break;
8123 }
8124 case XML_NAMESPACE_DECL:
8125 if (cur->type == XML_NAMESPACE_DECL) {
8126 xmlNsPtr ns = (xmlNsPtr) cur;
8127
8128 if ((ns->prefix != NULL) && (name != NULL)
8129 && (xmlStrEqual(ns->prefix, name))) {
8130 n++;
8131 if (n == indx)
8132 addNode(list, cur);
8133 }
8134 }
8135 break;
8136 default:
8137 break;
8138 }
8139 break;
8140 break;
8141 }
8142 } while (n < indx);
8143 }
8144 ctxt->context->node = tmp;
8145#ifdef DEBUG_STEP_NTH
8146 xmlGenericError(xmlGenericErrorContext,
8147 "\nExamined %d nodes, found %d nodes at that step\n",
8148 t, list->nodeNr);
8149#endif
8150 xmlXPathFreeObject(obj);
8151 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8152 return(t);
8153}
8154
8155/**
8156 * xmlXPathCompOpEvalFirst:
8157 * @ctxt: the XPath parser context with the compiled expression
8158 * @op: an XPath compiled operation
8159 * @first: the first elem found so far
8160 *
8161 * Evaluate the Precompiled XPath operation searching only the first
8162 * element in document order
8163 *
8164 * Returns the number of examined objects.
8165 */
8166static int
8167xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8168 xmlXPathStepOpPtr op, xmlNodePtr * first)
8169{
8170 int total = 0, cur;
8171 xmlXPathCompExprPtr comp;
8172 xmlXPathObjectPtr arg1, arg2;
8173
8174 comp = ctxt->comp;
8175 switch (op->op) {
8176 case XPATH_OP_END:
8177 return (0);
8178 case XPATH_OP_UNION:
8179 total =
8180 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8181 first);
8182 if ((ctxt->value != NULL)
8183 && (ctxt->value->type == XPATH_NODESET)
8184 && (ctxt->value->nodesetval != NULL)
8185 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8186 /*
8187 * limit tree traversing to first node in the result
8188 */
8189 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8190 *first = ctxt->value->nodesetval->nodeTab[0];
8191 }
8192 cur =
8193 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8194 first);
8195 CHECK_TYPE0(XPATH_NODESET);
8196 arg2 = valuePop(ctxt);
8197
8198 CHECK_TYPE0(XPATH_NODESET);
8199 arg1 = valuePop(ctxt);
8200
8201 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8202 arg2->nodesetval);
8203 valuePush(ctxt, arg1);
8204 xmlXPathFreeObject(arg2);
8205 /* optimizer */
8206 if (total > cur)
8207 xmlXPathCompSwap(op);
8208 return (total + cur);
8209 case XPATH_OP_ROOT:
8210 xmlXPathRoot(ctxt);
8211 return (0);
8212 case XPATH_OP_NODE:
8213 if (op->ch1 != -1)
8214 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8215 if (op->ch2 != -1)
8216 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8217 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8218 return (total);
8219 case XPATH_OP_RESET:
8220 if (op->ch1 != -1)
8221 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8222 if (op->ch2 != -1)
8223 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8224 ctxt->context->node = NULL;
8225 return (total);
8226 case XPATH_OP_COLLECT:{
8227 if (op->ch1 == -1)
8228 return (total);
8229
8230 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8231
8232 /*
8233 * Optimization for [n] selection where n is a number
8234 */
8235 if ((op->ch2 != -1) &&
8236 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8237 (comp->steps[op->ch2].ch1 == -1) &&
8238 (comp->steps[op->ch2].ch2 != -1) &&
8239 (comp->steps[comp->steps[op->ch2].ch2].op ==
8240 XPATH_OP_VALUE)) {
8241 xmlXPathObjectPtr val;
8242
8243 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8244 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8245 int indx = (int) val->floatval;
8246
8247 if (val->floatval == (float) indx) {
8248 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8249 first, NULL);
8250 return (total);
8251 }
8252 }
8253 }
8254 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8255 return (total);
8256 }
8257 case XPATH_OP_VALUE:
8258 valuePush(ctxt,
8259 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8260 return (0);
8261 case XPATH_OP_SORT:
8262 if (op->ch1 != -1)
8263 total +=
8264 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8265 first);
8266 if ((ctxt->value != NULL)
8267 && (ctxt->value->type == XPATH_NODESET)
8268 && (ctxt->value->nodesetval != NULL))
8269 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8270 return (total);
8271 default:
8272 return (xmlXPathCompOpEval(ctxt, op));
8273 }
8274}
8275
8276/**
8277 * xmlXPathCompOpEvalLast:
8278 * @ctxt: the XPath parser context with the compiled expression
8279 * @op: an XPath compiled operation
8280 * @last: the last elem found so far
8281 *
8282 * Evaluate the Precompiled XPath operation searching only the last
8283 * element in document order
8284 *
8285 * Returns the number of node traversed
8286 */
8287static int
8288xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8289 xmlNodePtr * last)
8290{
8291 int total = 0, cur;
8292 xmlXPathCompExprPtr comp;
8293 xmlXPathObjectPtr arg1, arg2;
8294
8295 comp = ctxt->comp;
8296 switch (op->op) {
8297 case XPATH_OP_END:
8298 return (0);
8299 case XPATH_OP_UNION:
8300 total =
8301 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8302 if ((ctxt->value != NULL)
8303 && (ctxt->value->type == XPATH_NODESET)
8304 && (ctxt->value->nodesetval != NULL)
8305 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8306 /*
8307 * limit tree traversing to first node in the result
8308 */
8309 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8310 *last =
8311 ctxt->value->nodesetval->nodeTab[ctxt->value->
8312 nodesetval->nodeNr -
8313 1];
8314 }
8315 cur =
8316 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8317 if ((ctxt->value != NULL)
8318 && (ctxt->value->type == XPATH_NODESET)
8319 && (ctxt->value->nodesetval != NULL)
8320 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8321 }
8322 CHECK_TYPE0(XPATH_NODESET);
8323 arg2 = valuePop(ctxt);
8324
8325 CHECK_TYPE0(XPATH_NODESET);
8326 arg1 = valuePop(ctxt);
8327
8328 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8329 arg2->nodesetval);
8330 valuePush(ctxt, arg1);
8331 xmlXPathFreeObject(arg2);
8332 /* optimizer */
8333 if (total > cur)
8334 xmlXPathCompSwap(op);
8335 return (total + cur);
8336 case XPATH_OP_ROOT:
8337 xmlXPathRoot(ctxt);
8338 return (0);
8339 case XPATH_OP_NODE:
8340 if (op->ch1 != -1)
8341 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8342 if (op->ch2 != -1)
8343 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8344 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8345 return (total);
8346 case XPATH_OP_RESET:
8347 if (op->ch1 != -1)
8348 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8349 if (op->ch2 != -1)
8350 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8351 ctxt->context->node = NULL;
8352 return (total);
8353 case XPATH_OP_COLLECT:{
8354 if (op->ch1 == -1)
8355 return (0);
8356
8357 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8358
8359 /*
8360 * Optimization for [n] selection where n is a number
8361 */
8362 if ((op->ch2 != -1) &&
8363 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8364 (comp->steps[op->ch2].ch1 == -1) &&
8365 (comp->steps[op->ch2].ch2 != -1) &&
8366 (comp->steps[comp->steps[op->ch2].ch2].op ==
8367 XPATH_OP_VALUE)) {
8368 xmlXPathObjectPtr val;
8369
8370 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8371 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8372 int indx = (int) val->floatval;
8373
8374 if (val->floatval == (float) indx) {
8375 total +=
8376 xmlXPathNodeCollectAndTestNth(ctxt, op,
8377 indx, NULL,
8378 last);
8379 return (total);
8380 }
8381 }
8382 }
8383 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8384 return (total);
8385 }
8386 case XPATH_OP_VALUE:
8387 valuePush(ctxt,
8388 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8389 return (0);
8390 case XPATH_OP_SORT:
8391 if (op->ch1 != -1)
8392 total +=
8393 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8394 last);
8395 if ((ctxt->value != NULL)
8396 && (ctxt->value->type == XPATH_NODESET)
8397 && (ctxt->value->nodesetval != NULL))
8398 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8399 return (total);
8400 default:
8401 return (xmlXPathCompOpEval(ctxt, op));
8402 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008403}
8404
Owen Taylor3473f882001-02-23 17:55:21 +00008405/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008406 * xmlXPathCompOpEval:
8407 * @ctxt: the XPath parser context with the compiled expression
8408 * @op: an XPath compiled operation
8409 *
8410 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008411 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008412 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008413static int
8414xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
8415{
8416 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008417 int equal, ret;
8418 xmlXPathCompExprPtr comp;
8419 xmlXPathObjectPtr arg1, arg2;
8420
8421 comp = ctxt->comp;
8422 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008423 case XPATH_OP_END:
8424 return (0);
8425 case XPATH_OP_AND:
8426 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8427 xmlXPathBooleanFunction(ctxt, 1);
8428 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
8429 return (total);
8430 arg2 = valuePop(ctxt);
8431 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8432 xmlXPathBooleanFunction(ctxt, 1);
8433 arg1 = valuePop(ctxt);
8434 arg1->boolval &= arg2->boolval;
8435 valuePush(ctxt, arg1);
8436 xmlXPathFreeObject(arg2);
8437 return (total);
8438 case XPATH_OP_OR:
8439 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8440 xmlXPathBooleanFunction(ctxt, 1);
8441 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
8442 return (total);
8443 arg2 = valuePop(ctxt);
8444 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8445 xmlXPathBooleanFunction(ctxt, 1);
8446 arg1 = valuePop(ctxt);
8447 arg1->boolval |= arg2->boolval;
8448 valuePush(ctxt, arg1);
8449 xmlXPathFreeObject(arg2);
8450 return (total);
8451 case XPATH_OP_EQUAL:
8452 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8453 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8454 equal = xmlXPathEqualValues(ctxt);
8455 if (op->value)
8456 valuePush(ctxt, xmlXPathNewBoolean(equal));
8457 else
8458 valuePush(ctxt, xmlXPathNewBoolean(!equal));
8459 return (total);
8460 case XPATH_OP_CMP:
8461 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8462 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8463 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
8464 valuePush(ctxt, xmlXPathNewBoolean(ret));
8465 return (total);
8466 case XPATH_OP_PLUS:
8467 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8468 if (op->ch2 != -1)
8469 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8470 if (op->value == 0)
8471 xmlXPathSubValues(ctxt);
8472 else if (op->value == 1)
8473 xmlXPathAddValues(ctxt);
8474 else if (op->value == 2)
8475 xmlXPathValueFlipSign(ctxt);
8476 else if (op->value == 3) {
8477 CAST_TO_NUMBER;
8478 CHECK_TYPE0(XPATH_NUMBER);
8479 }
8480 return (total);
8481 case XPATH_OP_MULT:
8482 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8483 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8484 if (op->value == 0)
8485 xmlXPathMultValues(ctxt);
8486 else if (op->value == 1)
8487 xmlXPathDivValues(ctxt);
8488 else if (op->value == 2)
8489 xmlXPathModValues(ctxt);
8490 return (total);
8491 case XPATH_OP_UNION:
8492 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8493 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8494 CHECK_TYPE0(XPATH_NODESET);
8495 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008496
Daniel Veillardf06307e2001-07-03 10:35:50 +00008497 CHECK_TYPE0(XPATH_NODESET);
8498 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008499
Daniel Veillardf06307e2001-07-03 10:35:50 +00008500 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8501 arg2->nodesetval);
8502 valuePush(ctxt, arg1);
8503 xmlXPathFreeObject(arg2);
8504 return (total);
8505 case XPATH_OP_ROOT:
8506 xmlXPathRoot(ctxt);
8507 return (total);
8508 case XPATH_OP_NODE:
8509 if (op->ch1 != -1)
8510 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8511 if (op->ch2 != -1)
8512 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8513 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8514 return (total);
8515 case XPATH_OP_RESET:
8516 if (op->ch1 != -1)
8517 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8518 if (op->ch2 != -1)
8519 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8520 ctxt->context->node = NULL;
8521 return (total);
8522 case XPATH_OP_COLLECT:{
8523 if (op->ch1 == -1)
8524 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008525
Daniel Veillardf06307e2001-07-03 10:35:50 +00008526 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008527
Daniel Veillardf06307e2001-07-03 10:35:50 +00008528 /*
8529 * Optimization for [n] selection where n is a number
8530 */
8531 if ((op->ch2 != -1) &&
8532 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8533 (comp->steps[op->ch2].ch1 == -1) &&
8534 (comp->steps[op->ch2].ch2 != -1) &&
8535 (comp->steps[comp->steps[op->ch2].ch2].op ==
8536 XPATH_OP_VALUE)) {
8537 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00008538
Daniel Veillardf06307e2001-07-03 10:35:50 +00008539 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8540 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8541 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008542
Daniel Veillardf06307e2001-07-03 10:35:50 +00008543 if (val->floatval == (float) indx) {
8544 total +=
8545 xmlXPathNodeCollectAndTestNth(ctxt, op,
8546 indx, NULL,
8547 NULL);
8548 return (total);
8549 }
8550 }
8551 }
8552 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
8553 return (total);
8554 }
8555 case XPATH_OP_VALUE:
8556 valuePush(ctxt,
8557 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8558 return (total);
8559 case XPATH_OP_VARIABLE:{
8560 if (op->ch1 != -1)
8561 total +=
8562 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8563 if (op->value5 == NULL)
8564 valuePush(ctxt,
8565 xmlXPathVariableLookup(ctxt->context,
8566 op->value4));
8567 else {
8568 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008569
Daniel Veillardf06307e2001-07-03 10:35:50 +00008570 URI = xmlXPathNsLookup(ctxt->context, op->value5);
8571 if (URI == NULL) {
8572 xmlGenericError(xmlGenericErrorContext,
8573 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
8574 op->value4, op->value5);
8575 return (total);
8576 }
8577 valuePush(ctxt,
8578 xmlXPathVariableLookupNS(ctxt->context,
8579 op->value4, URI));
8580 }
8581 return (total);
8582 }
8583 case XPATH_OP_FUNCTION:{
8584 xmlXPathFunction func;
8585 const xmlChar *oldFunc, *oldFuncURI;
8586
8587 if (op->ch1 != -1)
8588 total +=
8589 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8590 if (op->cache != NULL)
8591 func = (xmlXPathFunction) op->cache;
8592 else {
8593 const xmlChar *URI = NULL;
8594
8595 if (op->value5 == NULL)
8596 func =
8597 xmlXPathFunctionLookup(ctxt->context,
8598 op->value4);
8599 else {
8600 URI = xmlXPathNsLookup(ctxt->context, op->value5);
8601 if (URI == NULL) {
8602 xmlGenericError(xmlGenericErrorContext,
8603 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
8604 op->value4, op->value5);
8605 return (total);
8606 }
8607 func = xmlXPathFunctionLookupNS(ctxt->context,
8608 op->value4, URI);
8609 }
8610 if (func == NULL) {
8611 xmlGenericError(xmlGenericErrorContext,
8612 "xmlXPathRunEval: function %s not found\n",
8613 op->value4);
8614 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
8615 return (total);
8616 }
8617 op->cache = (void *) func;
8618 op->cacheURI = (void *) URI;
8619 }
8620 oldFunc = ctxt->context->function;
8621 oldFuncURI = ctxt->context->functionURI;
8622 ctxt->context->function = op->value4;
8623 ctxt->context->functionURI = op->cacheURI;
8624 func(ctxt, op->value);
8625 ctxt->context->function = oldFunc;
8626 ctxt->context->functionURI = oldFuncURI;
8627 return (total);
8628 }
8629 case XPATH_OP_ARG:
8630 if (op->ch1 != -1)
8631 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8632 if (op->ch2 != -1)
8633 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8634 return (total);
8635 case XPATH_OP_PREDICATE:
8636 case XPATH_OP_FILTER:{
8637 xmlXPathObjectPtr res;
8638 xmlXPathObjectPtr obj, tmp;
8639 xmlNodeSetPtr newset = NULL;
8640 xmlNodeSetPtr oldset;
8641 xmlNodePtr oldnode;
8642 int i;
8643
8644 /*
8645 * Optimization for ()[1] selection i.e. the first elem
8646 */
8647 if ((op->ch1 != -1) && (op->ch2 != -1) &&
8648 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
8649 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
8650 xmlXPathObjectPtr val;
8651
8652 val = comp->steps[op->ch2].value4;
8653 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
8654 (val->floatval == 1.0)) {
8655 xmlNodePtr first = NULL;
8656
8657 total +=
8658 xmlXPathCompOpEvalFirst(ctxt,
8659 &comp->steps[op->ch1],
8660 &first);
8661 /*
8662 * The nodeset should be in document order,
8663 * Keep only the first value
8664 */
8665 if ((ctxt->value != NULL) &&
8666 (ctxt->value->type == XPATH_NODESET) &&
8667 (ctxt->value->nodesetval != NULL) &&
8668 (ctxt->value->nodesetval->nodeNr > 1))
8669 ctxt->value->nodesetval->nodeNr = 1;
8670 return (total);
8671 }
8672 }
8673 /*
8674 * Optimization for ()[last()] selection i.e. the last elem
8675 */
8676 if ((op->ch1 != -1) && (op->ch2 != -1) &&
8677 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
8678 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
8679 int f = comp->steps[op->ch2].ch1;
8680
8681 if ((f != -1) &&
8682 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
8683 (comp->steps[f].value5 == NULL) &&
8684 (comp->steps[f].value == 0) &&
8685 (comp->steps[f].value4 != NULL) &&
8686 (xmlStrEqual
8687 (comp->steps[f].value4, BAD_CAST "last"))) {
8688 xmlNodePtr last = NULL;
8689
8690 total +=
8691 xmlXPathCompOpEvalLast(ctxt,
8692 &comp->steps[op->ch1],
8693 &last);
8694 /*
8695 * The nodeset should be in document order,
8696 * Keep only the last value
8697 */
8698 if ((ctxt->value != NULL) &&
8699 (ctxt->value->type == XPATH_NODESET) &&
8700 (ctxt->value->nodesetval != NULL) &&
8701 (ctxt->value->nodesetval->nodeTab != NULL) &&
8702 (ctxt->value->nodesetval->nodeNr > 1)) {
8703 ctxt->value->nodesetval->nodeTab[0] =
8704 ctxt->value->nodesetval->nodeTab[ctxt->
8705 value->
8706 nodesetval->
8707 nodeNr -
8708 1];
8709 ctxt->value->nodesetval->nodeNr = 1;
8710 }
8711 return (total);
8712 }
8713 }
8714
8715 if (op->ch1 != -1)
8716 total +=
8717 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8718 if (op->ch2 == -1)
8719 return (total);
8720 if (ctxt->value == NULL)
8721 return (total);
8722
8723 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008724
8725#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00008726 /*
8727 * Hum are we filtering the result of an XPointer expression
8728 */
8729 if (ctxt->value->type == XPATH_LOCATIONSET) {
8730 xmlLocationSetPtr newlocset = NULL;
8731 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008732
Daniel Veillardf06307e2001-07-03 10:35:50 +00008733 /*
8734 * Extract the old locset, and then evaluate the result of the
8735 * expression for all the element in the locset. use it to grow
8736 * up a new locset.
8737 */
8738 CHECK_TYPE0(XPATH_LOCATIONSET);
8739 obj = valuePop(ctxt);
8740 oldlocset = obj->user;
8741 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008742
Daniel Veillardf06307e2001-07-03 10:35:50 +00008743 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
8744 ctxt->context->contextSize = 0;
8745 ctxt->context->proximityPosition = 0;
8746 if (op->ch2 != -1)
8747 total +=
8748 xmlXPathCompOpEval(ctxt,
8749 &comp->steps[op->ch2]);
8750 res = valuePop(ctxt);
8751 if (res != NULL)
8752 xmlXPathFreeObject(res);
8753 valuePush(ctxt, obj);
8754 CHECK_ERROR0;
8755 return (total);
8756 }
8757 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008758
Daniel Veillardf06307e2001-07-03 10:35:50 +00008759 for (i = 0; i < oldlocset->locNr; i++) {
8760 /*
8761 * Run the evaluation with a node list made of a
8762 * single item in the nodelocset.
8763 */
8764 ctxt->context->node = oldlocset->locTab[i]->user;
8765 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8766 valuePush(ctxt, tmp);
8767 ctxt->context->contextSize = oldlocset->locNr;
8768 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008769
Daniel Veillardf06307e2001-07-03 10:35:50 +00008770 if (op->ch2 != -1)
8771 total +=
8772 xmlXPathCompOpEval(ctxt,
8773 &comp->steps[op->ch2]);
8774 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008775
Daniel Veillardf06307e2001-07-03 10:35:50 +00008776 /*
8777 * The result of the evaluation need to be tested to
8778 * decided whether the filter succeeded or not
8779 */
8780 res = valuePop(ctxt);
8781 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
8782 xmlXPtrLocationSetAdd(newlocset,
8783 xmlXPathObjectCopy
8784 (oldlocset->locTab[i]));
8785 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008786
Daniel Veillardf06307e2001-07-03 10:35:50 +00008787 /*
8788 * Cleanup
8789 */
8790 if (res != NULL)
8791 xmlXPathFreeObject(res);
8792 if (ctxt->value == tmp) {
8793 res = valuePop(ctxt);
8794 xmlXPathFreeObject(res);
8795 }
8796
8797 ctxt->context->node = NULL;
8798 }
8799
8800 /*
8801 * The result is used as the new evaluation locset.
8802 */
8803 xmlXPathFreeObject(obj);
8804 ctxt->context->node = NULL;
8805 ctxt->context->contextSize = -1;
8806 ctxt->context->proximityPosition = -1;
8807 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
8808 ctxt->context->node = oldnode;
8809 return (total);
8810 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008811#endif /* LIBXML_XPTR_ENABLED */
8812
Daniel Veillardf06307e2001-07-03 10:35:50 +00008813 /*
8814 * Extract the old set, and then evaluate the result of the
8815 * expression for all the element in the set. use it to grow
8816 * up a new set.
8817 */
8818 CHECK_TYPE0(XPATH_NODESET);
8819 obj = valuePop(ctxt);
8820 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00008821
Daniel Veillardf06307e2001-07-03 10:35:50 +00008822 oldnode = ctxt->context->node;
8823 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008824
Daniel Veillardf06307e2001-07-03 10:35:50 +00008825 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
8826 ctxt->context->contextSize = 0;
8827 ctxt->context->proximityPosition = 0;
8828 if (op->ch2 != -1)
8829 total +=
8830 xmlXPathCompOpEval(ctxt,
8831 &comp->steps[op->ch2]);
8832 res = valuePop(ctxt);
8833 if (res != NULL)
8834 xmlXPathFreeObject(res);
8835 valuePush(ctxt, obj);
8836 ctxt->context->node = oldnode;
8837 CHECK_ERROR0;
8838 } else {
8839 /*
8840 * Initialize the new set.
8841 */
8842 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008843
Daniel Veillardf06307e2001-07-03 10:35:50 +00008844 for (i = 0; i < oldset->nodeNr; i++) {
8845 /*
8846 * Run the evaluation with a node list made of
8847 * a single item in the nodeset.
8848 */
8849 ctxt->context->node = oldset->nodeTab[i];
8850 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8851 valuePush(ctxt, tmp);
8852 ctxt->context->contextSize = oldset->nodeNr;
8853 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008854
Daniel Veillardf06307e2001-07-03 10:35:50 +00008855 if (op->ch2 != -1)
8856 total +=
8857 xmlXPathCompOpEval(ctxt,
8858 &comp->steps[op->ch2]);
8859 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008860
Daniel Veillardf06307e2001-07-03 10:35:50 +00008861 /*
8862 * The result of the evaluation need to be tested to
8863 * decided whether the filter succeeded or not
8864 */
8865 res = valuePop(ctxt);
8866 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
8867 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
8868 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008869
Daniel Veillardf06307e2001-07-03 10:35:50 +00008870 /*
8871 * Cleanup
8872 */
8873 if (res != NULL)
8874 xmlXPathFreeObject(res);
8875 if (ctxt->value == tmp) {
8876 res = valuePop(ctxt);
8877 xmlXPathFreeObject(res);
8878 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008879
Daniel Veillardf06307e2001-07-03 10:35:50 +00008880 ctxt->context->node = NULL;
8881 }
8882
8883 /*
8884 * The result is used as the new evaluation set.
8885 */
8886 xmlXPathFreeObject(obj);
8887 ctxt->context->node = NULL;
8888 ctxt->context->contextSize = -1;
8889 ctxt->context->proximityPosition = -1;
8890 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
8891 }
8892 ctxt->context->node = oldnode;
8893 return (total);
8894 }
8895 case XPATH_OP_SORT:
8896 if (op->ch1 != -1)
8897 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8898 if ((ctxt->value != NULL) &&
8899 (ctxt->value->type == XPATH_NODESET) &&
8900 (ctxt->value->nodesetval != NULL))
8901 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8902 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008903#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00008904 case XPATH_OP_RANGETO:{
8905 xmlXPathObjectPtr range;
8906 xmlXPathObjectPtr res, obj;
8907 xmlXPathObjectPtr tmp;
8908 xmlLocationSetPtr newset = NULL;
8909 xmlNodeSetPtr oldset;
8910 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008911
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 if (op->ch1 != -1)
8913 total +=
8914 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8915 if (op->ch2 == -1)
8916 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008917
Daniel Veillardf06307e2001-07-03 10:35:50 +00008918 CHECK_TYPE0(XPATH_NODESET);
8919 obj = valuePop(ctxt);
8920 oldset = obj->nodesetval;
8921 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008922
Daniel Veillardf06307e2001-07-03 10:35:50 +00008923 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008924
Daniel Veillardf06307e2001-07-03 10:35:50 +00008925 if (oldset != NULL) {
8926 for (i = 0; i < oldset->nodeNr; i++) {
8927 /*
8928 * Run the evaluation with a node list made of a single item
8929 * in the nodeset.
8930 */
8931 ctxt->context->node = oldset->nodeTab[i];
8932 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8933 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008934
Daniel Veillardf06307e2001-07-03 10:35:50 +00008935 if (op->ch2 != -1)
8936 total +=
8937 xmlXPathCompOpEval(ctxt,
8938 &comp->steps[op->ch2]);
8939 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008940
Daniel Veillardf06307e2001-07-03 10:35:50 +00008941 /*
8942 * The result of the evaluation need to be tested to
8943 * decided whether the filter succeeded or not
8944 */
8945 res = valuePop(ctxt);
8946 range =
8947 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
8948 res);
8949 if (range != NULL) {
8950 xmlXPtrLocationSetAdd(newset, range);
8951 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008952
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 /*
8954 * Cleanup
8955 */
8956 if (res != NULL)
8957 xmlXPathFreeObject(res);
8958 if (ctxt->value == tmp) {
8959 res = valuePop(ctxt);
8960 xmlXPathFreeObject(res);
8961 }
8962
8963 ctxt->context->node = NULL;
8964 }
8965 }
8966
8967 /*
8968 * The result is used as the new evaluation set.
8969 */
8970 xmlXPathFreeObject(obj);
8971 ctxt->context->node = NULL;
8972 ctxt->context->contextSize = -1;
8973 ctxt->context->proximityPosition = -1;
8974 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
8975 return (total);
8976 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008977#endif /* LIBXML_XPTR_ENABLED */
8978 }
8979 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 "XPath: unknown precompiled operation %d\n", op->op);
8981 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008982}
8983
8984/**
8985 * xmlXPathRunEval:
8986 * @ctxt: the XPath parser context with the compiled expression
8987 *
8988 * Evaluate the Precompiled XPath expression in the given context.
8989 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008990static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008991xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
8992 xmlXPathCompExprPtr comp;
8993
8994 if ((ctxt == NULL) || (ctxt->comp == NULL))
8995 return;
8996
8997 if (ctxt->valueTab == NULL) {
8998 /* Allocate the value stack */
8999 ctxt->valueTab = (xmlXPathObjectPtr *)
9000 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9001 if (ctxt->valueTab == NULL) {
9002 xmlFree(ctxt);
9003 xmlGenericError(xmlGenericErrorContext,
9004 "xmlXPathRunEval: out of memory\n");
9005 return;
9006 }
9007 ctxt->valueNr = 0;
9008 ctxt->valueMax = 10;
9009 ctxt->value = NULL;
9010 }
9011 comp = ctxt->comp;
9012 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9013}
9014
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009015/************************************************************************
9016 * *
9017 * Public interfaces *
9018 * *
9019 ************************************************************************/
9020
9021/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009022 * xmlXPathEvalPredicate:
9023 * @ctxt: the XPath context
9024 * @res: the Predicate Expression evaluation result
9025 *
9026 * Evaluate a predicate result for the current node.
9027 * A PredicateExpr is evaluated by evaluating the Expr and converting
9028 * the result to a boolean. If the result is a number, the result will
9029 * be converted to true if the number is equal to the position of the
9030 * context node in the context node list (as returned by the position
9031 * function) and will be converted to false otherwise; if the result
9032 * is not a number, then the result will be converted as if by a call
9033 * to the boolean function.
9034 *
9035 * Return 1 if predicate is true, 0 otherwise
9036 */
9037int
9038xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9039 if (res == NULL) return(0);
9040 switch (res->type) {
9041 case XPATH_BOOLEAN:
9042 return(res->boolval);
9043 case XPATH_NUMBER:
9044 return(res->floatval == ctxt->proximityPosition);
9045 case XPATH_NODESET:
9046 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009047 if (res->nodesetval == NULL)
9048 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009049 return(res->nodesetval->nodeNr != 0);
9050 case XPATH_STRING:
9051 return((res->stringval != NULL) &&
9052 (xmlStrlen(res->stringval) != 0));
9053 default:
9054 STRANGE
9055 }
9056 return(0);
9057}
9058
9059/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009060 * xmlXPathEvaluatePredicateResult:
9061 * @ctxt: the XPath Parser context
9062 * @res: the Predicate Expression evaluation result
9063 *
9064 * Evaluate a predicate result for the current node.
9065 * A PredicateExpr is evaluated by evaluating the Expr and converting
9066 * the result to a boolean. If the result is a number, the result will
9067 * be converted to true if the number is equal to the position of the
9068 * context node in the context node list (as returned by the position
9069 * function) and will be converted to false otherwise; if the result
9070 * is not a number, then the result will be converted as if by a call
9071 * to the boolean function.
9072 *
9073 * Return 1 if predicate is true, 0 otherwise
9074 */
9075int
9076xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9077 xmlXPathObjectPtr res) {
9078 if (res == NULL) return(0);
9079 switch (res->type) {
9080 case XPATH_BOOLEAN:
9081 return(res->boolval);
9082 case XPATH_NUMBER:
9083 return(res->floatval == ctxt->context->proximityPosition);
9084 case XPATH_NODESET:
9085 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009086 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009087 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009088 return(res->nodesetval->nodeNr != 0);
9089 case XPATH_STRING:
9090 return((res->stringval != NULL) &&
9091 (xmlStrlen(res->stringval) != 0));
9092 default:
9093 STRANGE
9094 }
9095 return(0);
9096}
9097
9098/**
9099 * xmlXPathCompile:
9100 * @str: the XPath expression
9101 *
9102 * Compile an XPath expression
9103 *
9104 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9105 * the caller has to free the object.
9106 */
9107xmlXPathCompExprPtr
9108xmlXPathCompile(const xmlChar *str) {
9109 xmlXPathParserContextPtr ctxt;
9110 xmlXPathCompExprPtr comp;
9111
9112 xmlXPathInit();
9113
9114 ctxt = xmlXPathNewParserContext(str, NULL);
9115 xmlXPathCompileExpr(ctxt);
9116
Daniel Veillard40af6492001-04-22 08:50:55 +00009117 if (*ctxt->cur != 0) {
9118 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9119 comp = NULL;
9120 } else {
9121 comp = ctxt->comp;
9122 ctxt->comp = NULL;
9123 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009124 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125#ifdef DEBUG_EVAL_COUNTS
9126 if (comp != NULL) {
9127 comp->string = xmlStrdup(str);
9128 comp->nb = 0;
9129 }
9130#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009131 return(comp);
9132}
9133
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009134/**
9135 * xmlXPathCompiledEval:
9136 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009137 * @ctx: the XPath context
9138 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009139 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009140 *
9141 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9142 * the caller has to free the object.
9143 */
9144xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009145xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009146 xmlXPathParserContextPtr ctxt;
9147 xmlXPathObjectPtr res, tmp, init = NULL;
9148 int stack = 0;
9149
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009150 if ((comp == NULL) || (ctx == NULL))
9151 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009152 xmlXPathInit();
9153
9154 CHECK_CONTEXT(ctx)
9155
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156#ifdef DEBUG_EVAL_COUNTS
9157 comp->nb++;
9158 if ((comp->string != NULL) && (comp->nb > 100)) {
9159 fprintf(stderr, "100 x %s\n", comp->string);
9160 comp->nb = 0;
9161 }
9162#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009163 ctxt = xmlXPathCompParserContext(comp, ctx);
9164 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009165
9166 if (ctxt->value == NULL) {
9167 xmlGenericError(xmlGenericErrorContext,
9168 "xmlXPathEval: evaluation failed\n");
9169 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009170 } else {
9171 res = valuePop(ctxt);
9172 }
9173
Daniel Veillardf06307e2001-07-03 10:35:50 +00009174
Owen Taylor3473f882001-02-23 17:55:21 +00009175 do {
9176 tmp = valuePop(ctxt);
9177 if (tmp != NULL) {
9178 if (tmp != init)
9179 stack++;
9180 xmlXPathFreeObject(tmp);
9181 }
9182 } while (tmp != NULL);
9183 if ((stack != 0) && (res != NULL)) {
9184 xmlGenericError(xmlGenericErrorContext,
9185 "xmlXPathEval: %d object left on the stack\n",
9186 stack);
9187 }
9188 if (ctxt->error != XPATH_EXPRESSION_OK) {
9189 xmlXPathFreeObject(res);
9190 res = NULL;
9191 }
9192
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009193
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009194 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009195 xmlXPathFreeParserContext(ctxt);
9196 return(res);
9197}
9198
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009199/**
9200 * xmlXPathEvalExpr:
9201 * @ctxt: the XPath Parser context
9202 *
9203 * Parse and evaluate an XPath expression in the given context,
9204 * then push the result on the context stack
9205 */
9206void
9207xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9208 xmlXPathCompileExpr(ctxt);
9209 xmlXPathRunEval(ctxt);
9210}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009211
9212/**
9213 * xmlXPathEval:
9214 * @str: the XPath expression
9215 * @ctx: the XPath context
9216 *
9217 * Evaluate the XPath Location Path in the given context.
9218 *
9219 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9220 * the caller has to free the object.
9221 */
9222xmlXPathObjectPtr
9223xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9224 xmlXPathParserContextPtr ctxt;
9225 xmlXPathObjectPtr res, tmp, init = NULL;
9226 int stack = 0;
9227
9228 xmlXPathInit();
9229
9230 CHECK_CONTEXT(ctx)
9231
9232 ctxt = xmlXPathNewParserContext(str, ctx);
9233 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009234
9235 if (ctxt->value == NULL) {
9236 xmlGenericError(xmlGenericErrorContext,
9237 "xmlXPathEval: evaluation failed\n");
9238 res = NULL;
9239 } else if (*ctxt->cur != 0) {
9240 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9241 res = NULL;
9242 } else {
9243 res = valuePop(ctxt);
9244 }
9245
9246 do {
9247 tmp = valuePop(ctxt);
9248 if (tmp != NULL) {
9249 if (tmp != init)
9250 stack++;
9251 xmlXPathFreeObject(tmp);
9252 }
9253 } while (tmp != NULL);
9254 if ((stack != 0) && (res != NULL)) {
9255 xmlGenericError(xmlGenericErrorContext,
9256 "xmlXPathEval: %d object left on the stack\n",
9257 stack);
9258 }
9259 if (ctxt->error != XPATH_EXPRESSION_OK) {
9260 xmlXPathFreeObject(res);
9261 res = NULL;
9262 }
9263
Owen Taylor3473f882001-02-23 17:55:21 +00009264 xmlXPathFreeParserContext(ctxt);
9265 return(res);
9266}
9267
9268/**
9269 * xmlXPathEvalExpression:
9270 * @str: the XPath expression
9271 * @ctxt: the XPath context
9272 *
9273 * Evaluate the XPath expression in the given context.
9274 *
9275 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9276 * the caller has to free the object.
9277 */
9278xmlXPathObjectPtr
9279xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9280 xmlXPathParserContextPtr pctxt;
9281 xmlXPathObjectPtr res, tmp;
9282 int stack = 0;
9283
9284 xmlXPathInit();
9285
9286 CHECK_CONTEXT(ctxt)
9287
9288 pctxt = xmlXPathNewParserContext(str, ctxt);
9289 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009290
9291 if (*pctxt->cur != 0) {
9292 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9293 res = NULL;
9294 } else {
9295 res = valuePop(pctxt);
9296 }
9297 do {
9298 tmp = valuePop(pctxt);
9299 if (tmp != NULL) {
9300 xmlXPathFreeObject(tmp);
9301 stack++;
9302 }
9303 } while (tmp != NULL);
9304 if ((stack != 0) && (res != NULL)) {
9305 xmlGenericError(xmlGenericErrorContext,
9306 "xmlXPathEvalExpression: %d object left on the stack\n",
9307 stack);
9308 }
9309 xmlXPathFreeParserContext(pctxt);
9310 return(res);
9311}
9312
9313/**
9314 * xmlXPathRegisterAllFunctions:
9315 * @ctxt: the XPath context
9316 *
9317 * Registers all default XPath functions in this context
9318 */
9319void
9320xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9321{
9322 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9323 xmlXPathBooleanFunction);
9324 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9325 xmlXPathCeilingFunction);
9326 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9327 xmlXPathCountFunction);
9328 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9329 xmlXPathConcatFunction);
9330 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9331 xmlXPathContainsFunction);
9332 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9333 xmlXPathIdFunction);
9334 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9335 xmlXPathFalseFunction);
9336 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9337 xmlXPathFloorFunction);
9338 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9339 xmlXPathLastFunction);
9340 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9341 xmlXPathLangFunction);
9342 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9343 xmlXPathLocalNameFunction);
9344 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9345 xmlXPathNotFunction);
9346 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9347 xmlXPathNameFunction);
9348 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9349 xmlXPathNamespaceURIFunction);
9350 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9351 xmlXPathNormalizeFunction);
9352 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9353 xmlXPathNumberFunction);
9354 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9355 xmlXPathPositionFunction);
9356 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9357 xmlXPathRoundFunction);
9358 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9359 xmlXPathStringFunction);
9360 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9361 xmlXPathStringLengthFunction);
9362 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9363 xmlXPathStartsWithFunction);
9364 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9365 xmlXPathSubstringFunction);
9366 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9367 xmlXPathSubstringBeforeFunction);
9368 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9369 xmlXPathSubstringAfterFunction);
9370 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9371 xmlXPathSumFunction);
9372 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9373 xmlXPathTrueFunction);
9374 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9375 xmlXPathTranslateFunction);
9376}
9377
9378#endif /* LIBXML_XPATH_ENABLED */