blob: 8e5ed330b247ea0f611bc10e2055115a245ff1c3 [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) ||
7617 (cur->type == XML_TEXT_NODE)))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007618#ifdef DEBUG_STEP
7619 n++;
7620#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007621 addNode(list, cur);
7622 }
7623 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007624 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007625 if (cur->type == XML_PI_NODE) {
7626 if ((name != NULL) &&
7627 (!xmlStrEqual(name, cur->name)))
7628 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007629#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007630 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007631#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007632 addNode(list, cur);
7633 }
7634 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007635 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007636 if (axis == AXIS_ATTRIBUTE) {
7637 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007638#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007639 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007640#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007641 addNode(list, cur);
7642 }
7643 } else if (axis == AXIS_NAMESPACE) {
7644 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007645#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007646 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007647#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007648 addNode(list, cur);
7649 }
7650 } else {
7651 if (cur->type == XML_ELEMENT_NODE) {
7652 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007653#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007654 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007655#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007656 addNode(list, cur);
7657 } else if ((cur->ns != NULL) &&
7658 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007659#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007660 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007661#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007662 addNode(list, cur);
7663 }
7664 }
7665 }
7666 break;
7667 case NODE_TEST_NS:{
7668 TODO;
7669 break;
7670 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007671 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007672 switch (cur->type) {
7673 case XML_ELEMENT_NODE:
7674 if (xmlStrEqual(name, cur->name)) {
7675 if (prefix == NULL) {
7676 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007677#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007678 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007679#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007680 addNode(list, cur);
7681 }
7682 } else {
7683 if ((cur->ns != NULL) &&
7684 (xmlStrEqual(URI,
7685 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007686#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007687 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007688#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007689 addNode(list, cur);
7690 }
7691 }
7692 }
7693 break;
7694 case XML_ATTRIBUTE_NODE:{
7695 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007696
Daniel Veillardf06307e2001-07-03 10:35:50 +00007697 if (xmlStrEqual(name, attr->name)) {
7698 if (prefix == NULL) {
7699 if ((attr->ns == NULL) ||
7700 (attr->ns->prefix == NULL)) {
7701#ifdef DEBUG_STEP
7702 n++;
7703#endif
7704 addNode(list,
7705 (xmlNodePtr) attr);
7706 }
7707 } else {
7708 if ((attr->ns != NULL) &&
7709 (xmlStrEqual(URI,
7710 attr->ns->
7711 href))) {
7712#ifdef DEBUG_STEP
7713 n++;
7714#endif
7715 addNode(list,
7716 (xmlNodePtr) attr);
7717 }
7718 }
7719 }
7720 break;
7721 }
7722 case XML_NAMESPACE_DECL:
7723 if (cur->type == XML_NAMESPACE_DECL) {
7724 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007725
Daniel Veillardf06307e2001-07-03 10:35:50 +00007726 if ((ns->prefix != NULL) && (name != NULL)
7727 && (xmlStrEqual(ns->prefix, name))) {
7728#ifdef DEBUG_STEP
7729 n++;
7730#endif
7731 addNode(list, cur);
7732 }
7733 }
7734 break;
7735 default:
7736 break;
7737 }
7738 break;
7739 break;
7740 }
7741 } while (cur != NULL);
7742
7743 /*
7744 * If there is some predicate filtering do it now
7745 */
7746 if (op->ch2 != -1) {
7747 xmlXPathObjectPtr obj2;
7748
7749 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7750 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7751 CHECK_TYPE0(XPATH_NODESET);
7752 obj2 = valuePop(ctxt);
7753 list = obj2->nodesetval;
7754 obj2->nodesetval = NULL;
7755 xmlXPathFreeObject(obj2);
7756 }
7757 if (ret == NULL) {
7758 ret = list;
7759 } else {
7760 ret = xmlXPathNodeSetMerge(ret, list);
7761 xmlXPathFreeNodeSet(list);
7762 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007763 }
7764 ctxt->context->node = tmp;
7765#ifdef DEBUG_STEP
7766 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007767 "\nExamined %d nodes, found %d nodes at that step\n",
7768 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007769#endif
7770 xmlXPathFreeObject(obj);
7771 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +00007772 return(t);
7773}
7774
7775/**
7776 * xmlXPathNodeCollectAndTestNth:
7777 * @ctxt: the XPath Parser context
7778 * @op: the XPath precompiled step operation
7779 * @indx: the index to collect
7780 * @first: pointer to the first element in document order
7781 * @last: pointer to the last element in document order
7782 *
7783 * This is the function implementing a step: based on the current list
7784 * of nodes, it builds up a new list, looking at all nodes under that
7785 * axis and selecting them it also do the predicate filtering
7786 *
7787 * Pushes the new NodeSet resulting from the search.
7788 * Returns the number of node traversed
7789 */
7790static int
7791xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
7792 xmlXPathStepOpPtr op, int indx,
7793 xmlNodePtr * first, xmlNodePtr * last)
7794{
7795 xmlXPathAxisVal axis = op->value;
7796 xmlXPathTestVal test = op->value2;
7797 xmlXPathTypeVal type = op->value3;
7798 const xmlChar *prefix = op->value4;
7799 const xmlChar *name = op->value5;
7800 const xmlChar *URI = NULL;
7801 int n = 0, t = 0;
7802
7803 int i;
7804 xmlNodeSetPtr list;
7805 xmlXPathTraversalFunction next = NULL;
7806 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
7807 xmlNodePtr cur = NULL;
7808 xmlXPathObjectPtr obj;
7809 xmlNodeSetPtr nodelist;
7810 xmlNodePtr tmp;
7811
7812 CHECK_TYPE0(XPATH_NODESET);
7813 obj = valuePop(ctxt);
7814 addNode = xmlXPathNodeSetAdd;
7815 if (prefix != NULL) {
7816 URI = xmlXPathNsLookup(ctxt->context, prefix);
7817 if (URI == NULL)
7818 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7819 }
7820#ifdef DEBUG_STEP_NTH
7821 xmlGenericError(xmlGenericErrorContext, "new step : ");
7822 if (first != NULL) {
7823 if (*first != NULL)
7824 xmlGenericError(xmlGenericErrorContext, "first = %s ",
7825 (*first)->name);
7826 else
7827 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
7828 }
7829 if (last != NULL) {
7830 if (*last != NULL)
7831 xmlGenericError(xmlGenericErrorContext, "last = %s ",
7832 (*last)->name);
7833 else
7834 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
7835 }
7836#endif
7837 switch (axis) {
7838 case AXIS_ANCESTOR:
7839#ifdef DEBUG_STEP_NTH
7840 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
7841#endif
7842 first = NULL;
7843 next = xmlXPathNextAncestor;
7844 break;
7845 case AXIS_ANCESTOR_OR_SELF:
7846#ifdef DEBUG_STEP_NTH
7847 xmlGenericError(xmlGenericErrorContext,
7848 "axis 'ancestors-or-self' ");
7849#endif
7850 first = NULL;
7851 next = xmlXPathNextAncestorOrSelf;
7852 break;
7853 case AXIS_ATTRIBUTE:
7854#ifdef DEBUG_STEP_NTH
7855 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
7856#endif
7857 first = NULL;
7858 last = NULL;
7859 next = xmlXPathNextAttribute;
7860 break;
7861 case AXIS_CHILD:
7862#ifdef DEBUG_STEP_NTH
7863 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
7864#endif
7865 last = NULL;
7866 next = xmlXPathNextChild;
7867 break;
7868 case AXIS_DESCENDANT:
7869#ifdef DEBUG_STEP_NTH
7870 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
7871#endif
7872 last = NULL;
7873 next = xmlXPathNextDescendant;
7874 break;
7875 case AXIS_DESCENDANT_OR_SELF:
7876#ifdef DEBUG_STEP_NTH
7877 xmlGenericError(xmlGenericErrorContext,
7878 "axis 'descendant-or-self' ");
7879#endif
7880 last = NULL;
7881 next = xmlXPathNextDescendantOrSelf;
7882 break;
7883 case AXIS_FOLLOWING:
7884#ifdef DEBUG_STEP_NTH
7885 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
7886#endif
7887 last = NULL;
7888 next = xmlXPathNextFollowing;
7889 break;
7890 case AXIS_FOLLOWING_SIBLING:
7891#ifdef DEBUG_STEP_NTH
7892 xmlGenericError(xmlGenericErrorContext,
7893 "axis 'following-siblings' ");
7894#endif
7895 last = NULL;
7896 next = xmlXPathNextFollowingSibling;
7897 break;
7898 case AXIS_NAMESPACE:
7899#ifdef DEBUG_STEP_NTH
7900 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
7901#endif
7902 last = NULL;
7903 first = NULL;
7904 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
7905 break;
7906 case AXIS_PARENT:
7907#ifdef DEBUG_STEP_NTH
7908 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
7909#endif
7910 first = NULL;
7911 next = xmlXPathNextParent;
7912 break;
7913 case AXIS_PRECEDING:
7914#ifdef DEBUG_STEP_NTH
7915 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
7916#endif
7917 first = NULL;
7918 next = xmlXPathNextPrecedingInternal;
7919 break;
7920 case AXIS_PRECEDING_SIBLING:
7921#ifdef DEBUG_STEP_NTH
7922 xmlGenericError(xmlGenericErrorContext,
7923 "axis 'preceding-sibling' ");
7924#endif
7925 first = NULL;
7926 next = xmlXPathNextPrecedingSibling;
7927 break;
7928 case AXIS_SELF:
7929#ifdef DEBUG_STEP_NTH
7930 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
7931#endif
7932 first = NULL;
7933 last = NULL;
7934 next = xmlXPathNextSelf;
7935 break;
7936 }
7937 if (next == NULL)
7938 return(0);
7939
7940 nodelist = obj->nodesetval;
7941 if (nodelist == NULL) {
7942 xmlXPathFreeObject(obj);
7943 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7944 return(0);
7945 }
7946 addNode = xmlXPathNodeSetAddUnique;
7947#ifdef DEBUG_STEP_NTH
7948 xmlGenericError(xmlGenericErrorContext,
7949 " context contains %d nodes\n", nodelist->nodeNr);
7950 switch (test) {
7951 case NODE_TEST_NONE:
7952 xmlGenericError(xmlGenericErrorContext,
7953 " searching for none !!!\n");
7954 break;
7955 case NODE_TEST_TYPE:
7956 xmlGenericError(xmlGenericErrorContext,
7957 " searching for type %d\n", type);
7958 break;
7959 case NODE_TEST_PI:
7960 xmlGenericError(xmlGenericErrorContext,
7961 " searching for PI !!!\n");
7962 break;
7963 case NODE_TEST_ALL:
7964 xmlGenericError(xmlGenericErrorContext,
7965 " searching for *\n");
7966 break;
7967 case NODE_TEST_NS:
7968 xmlGenericError(xmlGenericErrorContext,
7969 " searching for namespace %s\n",
7970 prefix);
7971 break;
7972 case NODE_TEST_NAME:
7973 xmlGenericError(xmlGenericErrorContext,
7974 " searching for name %s\n", name);
7975 if (prefix != NULL)
7976 xmlGenericError(xmlGenericErrorContext,
7977 " with namespace %s\n", prefix);
7978 break;
7979 }
7980 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7981#endif
7982 /*
7983 * 2.3 Node Tests
7984 * - For the attribute axis, the principal node type is attribute.
7985 * - For the namespace axis, the principal node type is namespace.
7986 * - For other axes, the principal node type is element.
7987 *
7988 * A node test * is true for any node of the
7989 * principal node type. For example, child::* willi
7990 * select all element children of the context node
7991 */
7992 tmp = ctxt->context->node;
7993 list = xmlXPathNodeSetCreate(NULL);
7994 for (i = 0; i < nodelist->nodeNr; i++) {
7995 ctxt->context->node = nodelist->nodeTab[i];
7996
7997 cur = NULL;
7998 n = 0;
7999 do {
8000 cur = next(ctxt, cur);
8001 if (cur == NULL)
8002 break;
8003 if ((first != NULL) && (*first == cur))
8004 break;
8005 if (((t % 256) == 0) &&
8006 (first != NULL) && (*first != NULL) &&
8007 (xmlXPathCmpNodes(*first, cur) >= 0))
8008 break;
8009 if ((last != NULL) && (*last == cur))
8010 break;
8011 if (((t % 256) == 0) &&
8012 (last != NULL) && (*last != NULL) &&
8013 (xmlXPathCmpNodes(cur, *last) >= 0))
8014 break;
8015 t++;
8016 switch (test) {
8017 case NODE_TEST_NONE:
8018 ctxt->context->node = tmp;
8019 STRANGE return(0);
8020 case NODE_TEST_TYPE:
8021 if ((cur->type == type) ||
8022 ((type == NODE_TYPE_NODE) &&
8023 ((cur->type == XML_DOCUMENT_NODE) ||
8024 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8025 (cur->type == XML_ELEMENT_NODE) ||
8026 (cur->type == XML_PI_NODE) ||
8027 (cur->type == XML_COMMENT_NODE) ||
8028 (cur->type == XML_CDATA_SECTION_NODE) ||
8029 (cur->type == XML_TEXT_NODE)))) {
8030 n++;
8031 if (n == indx)
8032 addNode(list, cur);
8033 }
8034 break;
8035 case NODE_TEST_PI:
8036 if (cur->type == XML_PI_NODE) {
8037 if ((name != NULL) &&
8038 (!xmlStrEqual(name, cur->name)))
8039 break;
8040 n++;
8041 if (n == indx)
8042 addNode(list, cur);
8043 }
8044 break;
8045 case NODE_TEST_ALL:
8046 if (axis == AXIS_ATTRIBUTE) {
8047 if (cur->type == XML_ATTRIBUTE_NODE) {
8048 n++;
8049 if (n == indx)
8050 addNode(list, cur);
8051 }
8052 } else if (axis == AXIS_NAMESPACE) {
8053 if (cur->type == XML_NAMESPACE_DECL) {
8054 n++;
8055 if (n == indx)
8056 addNode(list, cur);
8057 }
8058 } else {
8059 if (cur->type == XML_ELEMENT_NODE) {
8060 if (prefix == NULL) {
8061 n++;
8062 if (n == indx)
8063 addNode(list, cur);
8064 } else if ((cur->ns != NULL) &&
8065 (xmlStrEqual(URI, cur->ns->href))) {
8066 n++;
8067 if (n == indx)
8068 addNode(list, cur);
8069 }
8070 }
8071 }
8072 break;
8073 case NODE_TEST_NS:{
8074 TODO;
8075 break;
8076 }
8077 case NODE_TEST_NAME:
8078 switch (cur->type) {
8079 case XML_ELEMENT_NODE:
8080 if (xmlStrEqual(name, cur->name)) {
8081 if (prefix == NULL) {
8082 if (cur->ns == NULL) {
8083 n++;
8084 if (n == indx)
8085 addNode(list, cur);
8086 }
8087 } else {
8088 if ((cur->ns != NULL) &&
8089 (xmlStrEqual(URI,
8090 cur->ns->href))) {
8091 n++;
8092 if (n == indx)
8093 addNode(list, cur);
8094 }
8095 }
8096 }
8097 break;
8098 case XML_ATTRIBUTE_NODE:{
8099 xmlAttrPtr attr = (xmlAttrPtr) cur;
8100
8101 if (xmlStrEqual(name, attr->name)) {
8102 if (prefix == NULL) {
8103 if ((attr->ns == NULL) ||
8104 (attr->ns->prefix == NULL)) {
8105 n++;
8106 if (n == indx)
8107 addNode(list, cur);
8108 }
8109 } else {
8110 if ((attr->ns != NULL) &&
8111 (xmlStrEqual(URI,
8112 attr->ns->
8113 href))) {
8114 n++;
8115 if (n == indx)
8116 addNode(list, cur);
8117 }
8118 }
8119 }
8120 break;
8121 }
8122 case XML_NAMESPACE_DECL:
8123 if (cur->type == XML_NAMESPACE_DECL) {
8124 xmlNsPtr ns = (xmlNsPtr) cur;
8125
8126 if ((ns->prefix != NULL) && (name != NULL)
8127 && (xmlStrEqual(ns->prefix, name))) {
8128 n++;
8129 if (n == indx)
8130 addNode(list, cur);
8131 }
8132 }
8133 break;
8134 default:
8135 break;
8136 }
8137 break;
8138 break;
8139 }
8140 } while (n < indx);
8141 }
8142 ctxt->context->node = tmp;
8143#ifdef DEBUG_STEP_NTH
8144 xmlGenericError(xmlGenericErrorContext,
8145 "\nExamined %d nodes, found %d nodes at that step\n",
8146 t, list->nodeNr);
8147#endif
8148 xmlXPathFreeObject(obj);
8149 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8150 return(t);
8151}
8152
8153/**
8154 * xmlXPathCompOpEvalFirst:
8155 * @ctxt: the XPath parser context with the compiled expression
8156 * @op: an XPath compiled operation
8157 * @first: the first elem found so far
8158 *
8159 * Evaluate the Precompiled XPath operation searching only the first
8160 * element in document order
8161 *
8162 * Returns the number of examined objects.
8163 */
8164static int
8165xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8166 xmlXPathStepOpPtr op, xmlNodePtr * first)
8167{
8168 int total = 0, cur;
8169 xmlXPathCompExprPtr comp;
8170 xmlXPathObjectPtr arg1, arg2;
8171
8172 comp = ctxt->comp;
8173 switch (op->op) {
8174 case XPATH_OP_END:
8175 return (0);
8176 case XPATH_OP_UNION:
8177 total =
8178 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8179 first);
8180 if ((ctxt->value != NULL)
8181 && (ctxt->value->type == XPATH_NODESET)
8182 && (ctxt->value->nodesetval != NULL)
8183 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8184 /*
8185 * limit tree traversing to first node in the result
8186 */
8187 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8188 *first = ctxt->value->nodesetval->nodeTab[0];
8189 }
8190 cur =
8191 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8192 first);
8193 CHECK_TYPE0(XPATH_NODESET);
8194 arg2 = valuePop(ctxt);
8195
8196 CHECK_TYPE0(XPATH_NODESET);
8197 arg1 = valuePop(ctxt);
8198
8199 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8200 arg2->nodesetval);
8201 valuePush(ctxt, arg1);
8202 xmlXPathFreeObject(arg2);
8203 /* optimizer */
8204 if (total > cur)
8205 xmlXPathCompSwap(op);
8206 return (total + cur);
8207 case XPATH_OP_ROOT:
8208 xmlXPathRoot(ctxt);
8209 return (0);
8210 case XPATH_OP_NODE:
8211 if (op->ch1 != -1)
8212 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8213 if (op->ch2 != -1)
8214 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8215 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8216 return (total);
8217 case XPATH_OP_RESET:
8218 if (op->ch1 != -1)
8219 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8220 if (op->ch2 != -1)
8221 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8222 ctxt->context->node = NULL;
8223 return (total);
8224 case XPATH_OP_COLLECT:{
8225 if (op->ch1 == -1)
8226 return (total);
8227
8228 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8229
8230 /*
8231 * Optimization for [n] selection where n is a number
8232 */
8233 if ((op->ch2 != -1) &&
8234 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8235 (comp->steps[op->ch2].ch1 == -1) &&
8236 (comp->steps[op->ch2].ch2 != -1) &&
8237 (comp->steps[comp->steps[op->ch2].ch2].op ==
8238 XPATH_OP_VALUE)) {
8239 xmlXPathObjectPtr val;
8240
8241 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8242 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8243 int indx = (int) val->floatval;
8244
8245 if (val->floatval == (float) indx) {
8246 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8247 first, NULL);
8248 return (total);
8249 }
8250 }
8251 }
8252 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8253 return (total);
8254 }
8255 case XPATH_OP_VALUE:
8256 valuePush(ctxt,
8257 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8258 return (0);
8259 case XPATH_OP_SORT:
8260 if (op->ch1 != -1)
8261 total +=
8262 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8263 first);
8264 if ((ctxt->value != NULL)
8265 && (ctxt->value->type == XPATH_NODESET)
8266 && (ctxt->value->nodesetval != NULL))
8267 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8268 return (total);
8269 default:
8270 return (xmlXPathCompOpEval(ctxt, op));
8271 }
8272}
8273
8274/**
8275 * xmlXPathCompOpEvalLast:
8276 * @ctxt: the XPath parser context with the compiled expression
8277 * @op: an XPath compiled operation
8278 * @last: the last elem found so far
8279 *
8280 * Evaluate the Precompiled XPath operation searching only the last
8281 * element in document order
8282 *
8283 * Returns the number of node traversed
8284 */
8285static int
8286xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8287 xmlNodePtr * last)
8288{
8289 int total = 0, cur;
8290 xmlXPathCompExprPtr comp;
8291 xmlXPathObjectPtr arg1, arg2;
8292
8293 comp = ctxt->comp;
8294 switch (op->op) {
8295 case XPATH_OP_END:
8296 return (0);
8297 case XPATH_OP_UNION:
8298 total =
8299 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8300 if ((ctxt->value != NULL)
8301 && (ctxt->value->type == XPATH_NODESET)
8302 && (ctxt->value->nodesetval != NULL)
8303 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8304 /*
8305 * limit tree traversing to first node in the result
8306 */
8307 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8308 *last =
8309 ctxt->value->nodesetval->nodeTab[ctxt->value->
8310 nodesetval->nodeNr -
8311 1];
8312 }
8313 cur =
8314 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8315 if ((ctxt->value != NULL)
8316 && (ctxt->value->type == XPATH_NODESET)
8317 && (ctxt->value->nodesetval != NULL)
8318 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8319 }
8320 CHECK_TYPE0(XPATH_NODESET);
8321 arg2 = valuePop(ctxt);
8322
8323 CHECK_TYPE0(XPATH_NODESET);
8324 arg1 = valuePop(ctxt);
8325
8326 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8327 arg2->nodesetval);
8328 valuePush(ctxt, arg1);
8329 xmlXPathFreeObject(arg2);
8330 /* optimizer */
8331 if (total > cur)
8332 xmlXPathCompSwap(op);
8333 return (total + cur);
8334 case XPATH_OP_ROOT:
8335 xmlXPathRoot(ctxt);
8336 return (0);
8337 case XPATH_OP_NODE:
8338 if (op->ch1 != -1)
8339 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8340 if (op->ch2 != -1)
8341 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8342 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8343 return (total);
8344 case XPATH_OP_RESET:
8345 if (op->ch1 != -1)
8346 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8347 if (op->ch2 != -1)
8348 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8349 ctxt->context->node = NULL;
8350 return (total);
8351 case XPATH_OP_COLLECT:{
8352 if (op->ch1 == -1)
8353 return (0);
8354
8355 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8356
8357 /*
8358 * Optimization for [n] selection where n is a number
8359 */
8360 if ((op->ch2 != -1) &&
8361 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8362 (comp->steps[op->ch2].ch1 == -1) &&
8363 (comp->steps[op->ch2].ch2 != -1) &&
8364 (comp->steps[comp->steps[op->ch2].ch2].op ==
8365 XPATH_OP_VALUE)) {
8366 xmlXPathObjectPtr val;
8367
8368 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8369 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8370 int indx = (int) val->floatval;
8371
8372 if (val->floatval == (float) indx) {
8373 total +=
8374 xmlXPathNodeCollectAndTestNth(ctxt, op,
8375 indx, NULL,
8376 last);
8377 return (total);
8378 }
8379 }
8380 }
8381 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8382 return (total);
8383 }
8384 case XPATH_OP_VALUE:
8385 valuePush(ctxt,
8386 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8387 return (0);
8388 case XPATH_OP_SORT:
8389 if (op->ch1 != -1)
8390 total +=
8391 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8392 last);
8393 if ((ctxt->value != NULL)
8394 && (ctxt->value->type == XPATH_NODESET)
8395 && (ctxt->value->nodesetval != NULL))
8396 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8397 return (total);
8398 default:
8399 return (xmlXPathCompOpEval(ctxt, op));
8400 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008401}
8402
Owen Taylor3473f882001-02-23 17:55:21 +00008403/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008404 * xmlXPathCompOpEval:
8405 * @ctxt: the XPath parser context with the compiled expression
8406 * @op: an XPath compiled operation
8407 *
8408 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008409 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008410 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008411static int
8412xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
8413{
8414 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008415 int equal, ret;
8416 xmlXPathCompExprPtr comp;
8417 xmlXPathObjectPtr arg1, arg2;
8418
8419 comp = ctxt->comp;
8420 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008421 case XPATH_OP_END:
8422 return (0);
8423 case XPATH_OP_AND:
8424 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8425 xmlXPathBooleanFunction(ctxt, 1);
8426 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
8427 return (total);
8428 arg2 = valuePop(ctxt);
8429 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8430 xmlXPathBooleanFunction(ctxt, 1);
8431 arg1 = valuePop(ctxt);
8432 arg1->boolval &= arg2->boolval;
8433 valuePush(ctxt, arg1);
8434 xmlXPathFreeObject(arg2);
8435 return (total);
8436 case XPATH_OP_OR:
8437 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8438 xmlXPathBooleanFunction(ctxt, 1);
8439 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
8440 return (total);
8441 arg2 = valuePop(ctxt);
8442 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8443 xmlXPathBooleanFunction(ctxt, 1);
8444 arg1 = valuePop(ctxt);
8445 arg1->boolval |= arg2->boolval;
8446 valuePush(ctxt, arg1);
8447 xmlXPathFreeObject(arg2);
8448 return (total);
8449 case XPATH_OP_EQUAL:
8450 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8451 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8452 equal = xmlXPathEqualValues(ctxt);
8453 if (op->value)
8454 valuePush(ctxt, xmlXPathNewBoolean(equal));
8455 else
8456 valuePush(ctxt, xmlXPathNewBoolean(!equal));
8457 return (total);
8458 case XPATH_OP_CMP:
8459 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8460 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8461 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
8462 valuePush(ctxt, xmlXPathNewBoolean(ret));
8463 return (total);
8464 case XPATH_OP_PLUS:
8465 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8466 if (op->ch2 != -1)
8467 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8468 if (op->value == 0)
8469 xmlXPathSubValues(ctxt);
8470 else if (op->value == 1)
8471 xmlXPathAddValues(ctxt);
8472 else if (op->value == 2)
8473 xmlXPathValueFlipSign(ctxt);
8474 else if (op->value == 3) {
8475 CAST_TO_NUMBER;
8476 CHECK_TYPE0(XPATH_NUMBER);
8477 }
8478 return (total);
8479 case XPATH_OP_MULT:
8480 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8481 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8482 if (op->value == 0)
8483 xmlXPathMultValues(ctxt);
8484 else if (op->value == 1)
8485 xmlXPathDivValues(ctxt);
8486 else if (op->value == 2)
8487 xmlXPathModValues(ctxt);
8488 return (total);
8489 case XPATH_OP_UNION:
8490 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8491 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8492 CHECK_TYPE0(XPATH_NODESET);
8493 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008494
Daniel Veillardf06307e2001-07-03 10:35:50 +00008495 CHECK_TYPE0(XPATH_NODESET);
8496 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008497
Daniel Veillardf06307e2001-07-03 10:35:50 +00008498 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8499 arg2->nodesetval);
8500 valuePush(ctxt, arg1);
8501 xmlXPathFreeObject(arg2);
8502 return (total);
8503 case XPATH_OP_ROOT:
8504 xmlXPathRoot(ctxt);
8505 return (total);
8506 case XPATH_OP_NODE:
8507 if (op->ch1 != -1)
8508 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8509 if (op->ch2 != -1)
8510 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8511 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8512 return (total);
8513 case XPATH_OP_RESET:
8514 if (op->ch1 != -1)
8515 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8516 if (op->ch2 != -1)
8517 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8518 ctxt->context->node = NULL;
8519 return (total);
8520 case XPATH_OP_COLLECT:{
8521 if (op->ch1 == -1)
8522 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008523
Daniel Veillardf06307e2001-07-03 10:35:50 +00008524 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008525
Daniel Veillardf06307e2001-07-03 10:35:50 +00008526 /*
8527 * Optimization for [n] selection where n is a number
8528 */
8529 if ((op->ch2 != -1) &&
8530 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8531 (comp->steps[op->ch2].ch1 == -1) &&
8532 (comp->steps[op->ch2].ch2 != -1) &&
8533 (comp->steps[comp->steps[op->ch2].ch2].op ==
8534 XPATH_OP_VALUE)) {
8535 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00008536
Daniel Veillardf06307e2001-07-03 10:35:50 +00008537 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8538 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8539 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008540
Daniel Veillardf06307e2001-07-03 10:35:50 +00008541 if (val->floatval == (float) indx) {
8542 total +=
8543 xmlXPathNodeCollectAndTestNth(ctxt, op,
8544 indx, NULL,
8545 NULL);
8546 return (total);
8547 }
8548 }
8549 }
8550 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
8551 return (total);
8552 }
8553 case XPATH_OP_VALUE:
8554 valuePush(ctxt,
8555 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8556 return (total);
8557 case XPATH_OP_VARIABLE:{
8558 if (op->ch1 != -1)
8559 total +=
8560 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8561 if (op->value5 == NULL)
8562 valuePush(ctxt,
8563 xmlXPathVariableLookup(ctxt->context,
8564 op->value4));
8565 else {
8566 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008567
Daniel Veillardf06307e2001-07-03 10:35:50 +00008568 URI = xmlXPathNsLookup(ctxt->context, op->value5);
8569 if (URI == NULL) {
8570 xmlGenericError(xmlGenericErrorContext,
8571 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
8572 op->value4, op->value5);
8573 return (total);
8574 }
8575 valuePush(ctxt,
8576 xmlXPathVariableLookupNS(ctxt->context,
8577 op->value4, URI));
8578 }
8579 return (total);
8580 }
8581 case XPATH_OP_FUNCTION:{
8582 xmlXPathFunction func;
8583 const xmlChar *oldFunc, *oldFuncURI;
8584
8585 if (op->ch1 != -1)
8586 total +=
8587 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8588 if (op->cache != NULL)
8589 func = (xmlXPathFunction) op->cache;
8590 else {
8591 const xmlChar *URI = NULL;
8592
8593 if (op->value5 == NULL)
8594 func =
8595 xmlXPathFunctionLookup(ctxt->context,
8596 op->value4);
8597 else {
8598 URI = xmlXPathNsLookup(ctxt->context, op->value5);
8599 if (URI == NULL) {
8600 xmlGenericError(xmlGenericErrorContext,
8601 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
8602 op->value4, op->value5);
8603 return (total);
8604 }
8605 func = xmlXPathFunctionLookupNS(ctxt->context,
8606 op->value4, URI);
8607 }
8608 if (func == NULL) {
8609 xmlGenericError(xmlGenericErrorContext,
8610 "xmlXPathRunEval: function %s not found\n",
8611 op->value4);
8612 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
8613 return (total);
8614 }
8615 op->cache = (void *) func;
8616 op->cacheURI = (void *) URI;
8617 }
8618 oldFunc = ctxt->context->function;
8619 oldFuncURI = ctxt->context->functionURI;
8620 ctxt->context->function = op->value4;
8621 ctxt->context->functionURI = op->cacheURI;
8622 func(ctxt, op->value);
8623 ctxt->context->function = oldFunc;
8624 ctxt->context->functionURI = oldFuncURI;
8625 return (total);
8626 }
8627 case XPATH_OP_ARG:
8628 if (op->ch1 != -1)
8629 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8630 if (op->ch2 != -1)
8631 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8632 return (total);
8633 case XPATH_OP_PREDICATE:
8634 case XPATH_OP_FILTER:{
8635 xmlXPathObjectPtr res;
8636 xmlXPathObjectPtr obj, tmp;
8637 xmlNodeSetPtr newset = NULL;
8638 xmlNodeSetPtr oldset;
8639 xmlNodePtr oldnode;
8640 int i;
8641
8642 /*
8643 * Optimization for ()[1] selection i.e. the first elem
8644 */
8645 if ((op->ch1 != -1) && (op->ch2 != -1) &&
8646 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
8647 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
8648 xmlXPathObjectPtr val;
8649
8650 val = comp->steps[op->ch2].value4;
8651 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
8652 (val->floatval == 1.0)) {
8653 xmlNodePtr first = NULL;
8654
8655 total +=
8656 xmlXPathCompOpEvalFirst(ctxt,
8657 &comp->steps[op->ch1],
8658 &first);
8659 /*
8660 * The nodeset should be in document order,
8661 * Keep only the first value
8662 */
8663 if ((ctxt->value != NULL) &&
8664 (ctxt->value->type == XPATH_NODESET) &&
8665 (ctxt->value->nodesetval != NULL) &&
8666 (ctxt->value->nodesetval->nodeNr > 1))
8667 ctxt->value->nodesetval->nodeNr = 1;
8668 return (total);
8669 }
8670 }
8671 /*
8672 * Optimization for ()[last()] selection i.e. the last elem
8673 */
8674 if ((op->ch1 != -1) && (op->ch2 != -1) &&
8675 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
8676 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
8677 int f = comp->steps[op->ch2].ch1;
8678
8679 if ((f != -1) &&
8680 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
8681 (comp->steps[f].value5 == NULL) &&
8682 (comp->steps[f].value == 0) &&
8683 (comp->steps[f].value4 != NULL) &&
8684 (xmlStrEqual
8685 (comp->steps[f].value4, BAD_CAST "last"))) {
8686 xmlNodePtr last = NULL;
8687
8688 total +=
8689 xmlXPathCompOpEvalLast(ctxt,
8690 &comp->steps[op->ch1],
8691 &last);
8692 /*
8693 * The nodeset should be in document order,
8694 * Keep only the last value
8695 */
8696 if ((ctxt->value != NULL) &&
8697 (ctxt->value->type == XPATH_NODESET) &&
8698 (ctxt->value->nodesetval != NULL) &&
8699 (ctxt->value->nodesetval->nodeTab != NULL) &&
8700 (ctxt->value->nodesetval->nodeNr > 1)) {
8701 ctxt->value->nodesetval->nodeTab[0] =
8702 ctxt->value->nodesetval->nodeTab[ctxt->
8703 value->
8704 nodesetval->
8705 nodeNr -
8706 1];
8707 ctxt->value->nodesetval->nodeNr = 1;
8708 }
8709 return (total);
8710 }
8711 }
8712
8713 if (op->ch1 != -1)
8714 total +=
8715 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8716 if (op->ch2 == -1)
8717 return (total);
8718 if (ctxt->value == NULL)
8719 return (total);
8720
8721 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008722
8723#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00008724 /*
8725 * Hum are we filtering the result of an XPointer expression
8726 */
8727 if (ctxt->value->type == XPATH_LOCATIONSET) {
8728 xmlLocationSetPtr newlocset = NULL;
8729 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008730
Daniel Veillardf06307e2001-07-03 10:35:50 +00008731 /*
8732 * Extract the old locset, and then evaluate the result of the
8733 * expression for all the element in the locset. use it to grow
8734 * up a new locset.
8735 */
8736 CHECK_TYPE0(XPATH_LOCATIONSET);
8737 obj = valuePop(ctxt);
8738 oldlocset = obj->user;
8739 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008740
Daniel Veillardf06307e2001-07-03 10:35:50 +00008741 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
8742 ctxt->context->contextSize = 0;
8743 ctxt->context->proximityPosition = 0;
8744 if (op->ch2 != -1)
8745 total +=
8746 xmlXPathCompOpEval(ctxt,
8747 &comp->steps[op->ch2]);
8748 res = valuePop(ctxt);
8749 if (res != NULL)
8750 xmlXPathFreeObject(res);
8751 valuePush(ctxt, obj);
8752 CHECK_ERROR0;
8753 return (total);
8754 }
8755 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008756
Daniel Veillardf06307e2001-07-03 10:35:50 +00008757 for (i = 0; i < oldlocset->locNr; i++) {
8758 /*
8759 * Run the evaluation with a node list made of a
8760 * single item in the nodelocset.
8761 */
8762 ctxt->context->node = oldlocset->locTab[i]->user;
8763 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8764 valuePush(ctxt, tmp);
8765 ctxt->context->contextSize = oldlocset->locNr;
8766 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008767
Daniel Veillardf06307e2001-07-03 10:35:50 +00008768 if (op->ch2 != -1)
8769 total +=
8770 xmlXPathCompOpEval(ctxt,
8771 &comp->steps[op->ch2]);
8772 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008773
Daniel Veillardf06307e2001-07-03 10:35:50 +00008774 /*
8775 * The result of the evaluation need to be tested to
8776 * decided whether the filter succeeded or not
8777 */
8778 res = valuePop(ctxt);
8779 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
8780 xmlXPtrLocationSetAdd(newlocset,
8781 xmlXPathObjectCopy
8782 (oldlocset->locTab[i]));
8783 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008784
Daniel Veillardf06307e2001-07-03 10:35:50 +00008785 /*
8786 * Cleanup
8787 */
8788 if (res != NULL)
8789 xmlXPathFreeObject(res);
8790 if (ctxt->value == tmp) {
8791 res = valuePop(ctxt);
8792 xmlXPathFreeObject(res);
8793 }
8794
8795 ctxt->context->node = NULL;
8796 }
8797
8798 /*
8799 * The result is used as the new evaluation locset.
8800 */
8801 xmlXPathFreeObject(obj);
8802 ctxt->context->node = NULL;
8803 ctxt->context->contextSize = -1;
8804 ctxt->context->proximityPosition = -1;
8805 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
8806 ctxt->context->node = oldnode;
8807 return (total);
8808 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008809#endif /* LIBXML_XPTR_ENABLED */
8810
Daniel Veillardf06307e2001-07-03 10:35:50 +00008811 /*
8812 * Extract the old set, and then evaluate the result of the
8813 * expression for all the element in the set. use it to grow
8814 * up a new set.
8815 */
8816 CHECK_TYPE0(XPATH_NODESET);
8817 obj = valuePop(ctxt);
8818 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00008819
Daniel Veillardf06307e2001-07-03 10:35:50 +00008820 oldnode = ctxt->context->node;
8821 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008822
Daniel Veillardf06307e2001-07-03 10:35:50 +00008823 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
8824 ctxt->context->contextSize = 0;
8825 ctxt->context->proximityPosition = 0;
8826 if (op->ch2 != -1)
8827 total +=
8828 xmlXPathCompOpEval(ctxt,
8829 &comp->steps[op->ch2]);
8830 res = valuePop(ctxt);
8831 if (res != NULL)
8832 xmlXPathFreeObject(res);
8833 valuePush(ctxt, obj);
8834 ctxt->context->node = oldnode;
8835 CHECK_ERROR0;
8836 } else {
8837 /*
8838 * Initialize the new set.
8839 */
8840 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008841
Daniel Veillardf06307e2001-07-03 10:35:50 +00008842 for (i = 0; i < oldset->nodeNr; i++) {
8843 /*
8844 * Run the evaluation with a node list made of
8845 * a single item in the nodeset.
8846 */
8847 ctxt->context->node = oldset->nodeTab[i];
8848 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8849 valuePush(ctxt, tmp);
8850 ctxt->context->contextSize = oldset->nodeNr;
8851 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008852
Daniel Veillardf06307e2001-07-03 10:35:50 +00008853 if (op->ch2 != -1)
8854 total +=
8855 xmlXPathCompOpEval(ctxt,
8856 &comp->steps[op->ch2]);
8857 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008858
Daniel Veillardf06307e2001-07-03 10:35:50 +00008859 /*
8860 * The result of the evaluation need to be tested to
8861 * decided whether the filter succeeded or not
8862 */
8863 res = valuePop(ctxt);
8864 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
8865 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
8866 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008867
Daniel Veillardf06307e2001-07-03 10:35:50 +00008868 /*
8869 * Cleanup
8870 */
8871 if (res != NULL)
8872 xmlXPathFreeObject(res);
8873 if (ctxt->value == tmp) {
8874 res = valuePop(ctxt);
8875 xmlXPathFreeObject(res);
8876 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008877
Daniel Veillardf06307e2001-07-03 10:35:50 +00008878 ctxt->context->node = NULL;
8879 }
8880
8881 /*
8882 * The result is used as the new evaluation set.
8883 */
8884 xmlXPathFreeObject(obj);
8885 ctxt->context->node = NULL;
8886 ctxt->context->contextSize = -1;
8887 ctxt->context->proximityPosition = -1;
8888 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
8889 }
8890 ctxt->context->node = oldnode;
8891 return (total);
8892 }
8893 case XPATH_OP_SORT:
8894 if (op->ch1 != -1)
8895 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8896 if ((ctxt->value != NULL) &&
8897 (ctxt->value->type == XPATH_NODESET) &&
8898 (ctxt->value->nodesetval != NULL))
8899 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8900 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008901#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 case XPATH_OP_RANGETO:{
8903 xmlXPathObjectPtr range;
8904 xmlXPathObjectPtr res, obj;
8905 xmlXPathObjectPtr tmp;
8906 xmlLocationSetPtr newset = NULL;
8907 xmlNodeSetPtr oldset;
8908 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008909
Daniel Veillardf06307e2001-07-03 10:35:50 +00008910 if (op->ch1 != -1)
8911 total +=
8912 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8913 if (op->ch2 == -1)
8914 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008915
Daniel Veillardf06307e2001-07-03 10:35:50 +00008916 CHECK_TYPE0(XPATH_NODESET);
8917 obj = valuePop(ctxt);
8918 oldset = obj->nodesetval;
8919 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008920
Daniel Veillardf06307e2001-07-03 10:35:50 +00008921 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008922
Daniel Veillardf06307e2001-07-03 10:35:50 +00008923 if (oldset != NULL) {
8924 for (i = 0; i < oldset->nodeNr; i++) {
8925 /*
8926 * Run the evaluation with a node list made of a single item
8927 * in the nodeset.
8928 */
8929 ctxt->context->node = oldset->nodeTab[i];
8930 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8931 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008932
Daniel Veillardf06307e2001-07-03 10:35:50 +00008933 if (op->ch2 != -1)
8934 total +=
8935 xmlXPathCompOpEval(ctxt,
8936 &comp->steps[op->ch2]);
8937 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008938
Daniel Veillardf06307e2001-07-03 10:35:50 +00008939 /*
8940 * The result of the evaluation need to be tested to
8941 * decided whether the filter succeeded or not
8942 */
8943 res = valuePop(ctxt);
8944 range =
8945 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
8946 res);
8947 if (range != NULL) {
8948 xmlXPtrLocationSetAdd(newset, range);
8949 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008950
Daniel Veillardf06307e2001-07-03 10:35:50 +00008951 /*
8952 * Cleanup
8953 */
8954 if (res != NULL)
8955 xmlXPathFreeObject(res);
8956 if (ctxt->value == tmp) {
8957 res = valuePop(ctxt);
8958 xmlXPathFreeObject(res);
8959 }
8960
8961 ctxt->context->node = NULL;
8962 }
8963 }
8964
8965 /*
8966 * The result is used as the new evaluation set.
8967 */
8968 xmlXPathFreeObject(obj);
8969 ctxt->context->node = NULL;
8970 ctxt->context->contextSize = -1;
8971 ctxt->context->proximityPosition = -1;
8972 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
8973 return (total);
8974 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008975#endif /* LIBXML_XPTR_ENABLED */
8976 }
8977 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008978 "XPath: unknown precompiled operation %d\n", op->op);
8979 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008980}
8981
8982/**
8983 * xmlXPathRunEval:
8984 * @ctxt: the XPath parser context with the compiled expression
8985 *
8986 * Evaluate the Precompiled XPath expression in the given context.
8987 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008988static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008989xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
8990 xmlXPathCompExprPtr comp;
8991
8992 if ((ctxt == NULL) || (ctxt->comp == NULL))
8993 return;
8994
8995 if (ctxt->valueTab == NULL) {
8996 /* Allocate the value stack */
8997 ctxt->valueTab = (xmlXPathObjectPtr *)
8998 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
8999 if (ctxt->valueTab == NULL) {
9000 xmlFree(ctxt);
9001 xmlGenericError(xmlGenericErrorContext,
9002 "xmlXPathRunEval: out of memory\n");
9003 return;
9004 }
9005 ctxt->valueNr = 0;
9006 ctxt->valueMax = 10;
9007 ctxt->value = NULL;
9008 }
9009 comp = ctxt->comp;
9010 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9011}
9012
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009013/************************************************************************
9014 * *
9015 * Public interfaces *
9016 * *
9017 ************************************************************************/
9018
9019/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009020 * xmlXPathEvalPredicate:
9021 * @ctxt: the XPath context
9022 * @res: the Predicate Expression evaluation result
9023 *
9024 * Evaluate a predicate result for the current node.
9025 * A PredicateExpr is evaluated by evaluating the Expr and converting
9026 * the result to a boolean. If the result is a number, the result will
9027 * be converted to true if the number is equal to the position of the
9028 * context node in the context node list (as returned by the position
9029 * function) and will be converted to false otherwise; if the result
9030 * is not a number, then the result will be converted as if by a call
9031 * to the boolean function.
9032 *
9033 * Return 1 if predicate is true, 0 otherwise
9034 */
9035int
9036xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9037 if (res == NULL) return(0);
9038 switch (res->type) {
9039 case XPATH_BOOLEAN:
9040 return(res->boolval);
9041 case XPATH_NUMBER:
9042 return(res->floatval == ctxt->proximityPosition);
9043 case XPATH_NODESET:
9044 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009045 if (res->nodesetval == NULL)
9046 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009047 return(res->nodesetval->nodeNr != 0);
9048 case XPATH_STRING:
9049 return((res->stringval != NULL) &&
9050 (xmlStrlen(res->stringval) != 0));
9051 default:
9052 STRANGE
9053 }
9054 return(0);
9055}
9056
9057/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009058 * xmlXPathEvaluatePredicateResult:
9059 * @ctxt: the XPath Parser context
9060 * @res: the Predicate Expression evaluation result
9061 *
9062 * Evaluate a predicate result for the current node.
9063 * A PredicateExpr is evaluated by evaluating the Expr and converting
9064 * the result to a boolean. If the result is a number, the result will
9065 * be converted to true if the number is equal to the position of the
9066 * context node in the context node list (as returned by the position
9067 * function) and will be converted to false otherwise; if the result
9068 * is not a number, then the result will be converted as if by a call
9069 * to the boolean function.
9070 *
9071 * Return 1 if predicate is true, 0 otherwise
9072 */
9073int
9074xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9075 xmlXPathObjectPtr res) {
9076 if (res == NULL) return(0);
9077 switch (res->type) {
9078 case XPATH_BOOLEAN:
9079 return(res->boolval);
9080 case XPATH_NUMBER:
9081 return(res->floatval == ctxt->context->proximityPosition);
9082 case XPATH_NODESET:
9083 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009084 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009085 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009086 return(res->nodesetval->nodeNr != 0);
9087 case XPATH_STRING:
9088 return((res->stringval != NULL) &&
9089 (xmlStrlen(res->stringval) != 0));
9090 default:
9091 STRANGE
9092 }
9093 return(0);
9094}
9095
9096/**
9097 * xmlXPathCompile:
9098 * @str: the XPath expression
9099 *
9100 * Compile an XPath expression
9101 *
9102 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9103 * the caller has to free the object.
9104 */
9105xmlXPathCompExprPtr
9106xmlXPathCompile(const xmlChar *str) {
9107 xmlXPathParserContextPtr ctxt;
9108 xmlXPathCompExprPtr comp;
9109
9110 xmlXPathInit();
9111
9112 ctxt = xmlXPathNewParserContext(str, NULL);
9113 xmlXPathCompileExpr(ctxt);
9114
Daniel Veillard40af6492001-04-22 08:50:55 +00009115 if (*ctxt->cur != 0) {
9116 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9117 comp = NULL;
9118 } else {
9119 comp = ctxt->comp;
9120 ctxt->comp = NULL;
9121 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009122 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123#ifdef DEBUG_EVAL_COUNTS
9124 if (comp != NULL) {
9125 comp->string = xmlStrdup(str);
9126 comp->nb = 0;
9127 }
9128#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009129 return(comp);
9130}
9131
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009132/**
9133 * xmlXPathCompiledEval:
9134 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009135 * @ctx: the XPath context
9136 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009137 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009138 *
9139 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9140 * the caller has to free the object.
9141 */
9142xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009143xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009144 xmlXPathParserContextPtr ctxt;
9145 xmlXPathObjectPtr res, tmp, init = NULL;
9146 int stack = 0;
9147
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009148 if ((comp == NULL) || (ctx == NULL))
9149 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009150 xmlXPathInit();
9151
9152 CHECK_CONTEXT(ctx)
9153
Daniel Veillardf06307e2001-07-03 10:35:50 +00009154#ifdef DEBUG_EVAL_COUNTS
9155 comp->nb++;
9156 if ((comp->string != NULL) && (comp->nb > 100)) {
9157 fprintf(stderr, "100 x %s\n", comp->string);
9158 comp->nb = 0;
9159 }
9160#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009161 ctxt = xmlXPathCompParserContext(comp, ctx);
9162 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009163
9164 if (ctxt->value == NULL) {
9165 xmlGenericError(xmlGenericErrorContext,
9166 "xmlXPathEval: evaluation failed\n");
9167 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009168 } else {
9169 res = valuePop(ctxt);
9170 }
9171
Daniel Veillardf06307e2001-07-03 10:35:50 +00009172
Owen Taylor3473f882001-02-23 17:55:21 +00009173 do {
9174 tmp = valuePop(ctxt);
9175 if (tmp != NULL) {
9176 if (tmp != init)
9177 stack++;
9178 xmlXPathFreeObject(tmp);
9179 }
9180 } while (tmp != NULL);
9181 if ((stack != 0) && (res != NULL)) {
9182 xmlGenericError(xmlGenericErrorContext,
9183 "xmlXPathEval: %d object left on the stack\n",
9184 stack);
9185 }
9186 if (ctxt->error != XPATH_EXPRESSION_OK) {
9187 xmlXPathFreeObject(res);
9188 res = NULL;
9189 }
9190
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009191
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009192 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009193 xmlXPathFreeParserContext(ctxt);
9194 return(res);
9195}
9196
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009197/**
9198 * xmlXPathEvalExpr:
9199 * @ctxt: the XPath Parser context
9200 *
9201 * Parse and evaluate an XPath expression in the given context,
9202 * then push the result on the context stack
9203 */
9204void
9205xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9206 xmlXPathCompileExpr(ctxt);
9207 xmlXPathRunEval(ctxt);
9208}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009209
9210/**
9211 * xmlXPathEval:
9212 * @str: the XPath expression
9213 * @ctx: the XPath context
9214 *
9215 * Evaluate the XPath Location Path in the given context.
9216 *
9217 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9218 * the caller has to free the object.
9219 */
9220xmlXPathObjectPtr
9221xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9222 xmlXPathParserContextPtr ctxt;
9223 xmlXPathObjectPtr res, tmp, init = NULL;
9224 int stack = 0;
9225
9226 xmlXPathInit();
9227
9228 CHECK_CONTEXT(ctx)
9229
9230 ctxt = xmlXPathNewParserContext(str, ctx);
9231 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009232
9233 if (ctxt->value == NULL) {
9234 xmlGenericError(xmlGenericErrorContext,
9235 "xmlXPathEval: evaluation failed\n");
9236 res = NULL;
9237 } else if (*ctxt->cur != 0) {
9238 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9239 res = NULL;
9240 } else {
9241 res = valuePop(ctxt);
9242 }
9243
9244 do {
9245 tmp = valuePop(ctxt);
9246 if (tmp != NULL) {
9247 if (tmp != init)
9248 stack++;
9249 xmlXPathFreeObject(tmp);
9250 }
9251 } while (tmp != NULL);
9252 if ((stack != 0) && (res != NULL)) {
9253 xmlGenericError(xmlGenericErrorContext,
9254 "xmlXPathEval: %d object left on the stack\n",
9255 stack);
9256 }
9257 if (ctxt->error != XPATH_EXPRESSION_OK) {
9258 xmlXPathFreeObject(res);
9259 res = NULL;
9260 }
9261
Owen Taylor3473f882001-02-23 17:55:21 +00009262 xmlXPathFreeParserContext(ctxt);
9263 return(res);
9264}
9265
9266/**
9267 * xmlXPathEvalExpression:
9268 * @str: the XPath expression
9269 * @ctxt: the XPath context
9270 *
9271 * Evaluate the XPath expression in the given context.
9272 *
9273 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9274 * the caller has to free the object.
9275 */
9276xmlXPathObjectPtr
9277xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9278 xmlXPathParserContextPtr pctxt;
9279 xmlXPathObjectPtr res, tmp;
9280 int stack = 0;
9281
9282 xmlXPathInit();
9283
9284 CHECK_CONTEXT(ctxt)
9285
9286 pctxt = xmlXPathNewParserContext(str, ctxt);
9287 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009288
9289 if (*pctxt->cur != 0) {
9290 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9291 res = NULL;
9292 } else {
9293 res = valuePop(pctxt);
9294 }
9295 do {
9296 tmp = valuePop(pctxt);
9297 if (tmp != NULL) {
9298 xmlXPathFreeObject(tmp);
9299 stack++;
9300 }
9301 } while (tmp != NULL);
9302 if ((stack != 0) && (res != NULL)) {
9303 xmlGenericError(xmlGenericErrorContext,
9304 "xmlXPathEvalExpression: %d object left on the stack\n",
9305 stack);
9306 }
9307 xmlXPathFreeParserContext(pctxt);
9308 return(res);
9309}
9310
9311/**
9312 * xmlXPathRegisterAllFunctions:
9313 * @ctxt: the XPath context
9314 *
9315 * Registers all default XPath functions in this context
9316 */
9317void
9318xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9319{
9320 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9321 xmlXPathBooleanFunction);
9322 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9323 xmlXPathCeilingFunction);
9324 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9325 xmlXPathCountFunction);
9326 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9327 xmlXPathConcatFunction);
9328 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9329 xmlXPathContainsFunction);
9330 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9331 xmlXPathIdFunction);
9332 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9333 xmlXPathFalseFunction);
9334 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9335 xmlXPathFloorFunction);
9336 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9337 xmlXPathLastFunction);
9338 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9339 xmlXPathLangFunction);
9340 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9341 xmlXPathLocalNameFunction);
9342 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9343 xmlXPathNotFunction);
9344 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9345 xmlXPathNameFunction);
9346 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9347 xmlXPathNamespaceURIFunction);
9348 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9349 xmlXPathNormalizeFunction);
9350 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9351 xmlXPathNumberFunction);
9352 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9353 xmlXPathPositionFunction);
9354 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9355 xmlXPathRoundFunction);
9356 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9357 xmlXPathStringFunction);
9358 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9359 xmlXPathStringLengthFunction);
9360 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9361 xmlXPathStartsWithFunction);
9362 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9363 xmlXPathSubstringFunction);
9364 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9365 xmlXPathSubstringBeforeFunction);
9366 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9367 xmlXPathSubstringAfterFunction);
9368 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9369 xmlXPathSumFunction);
9370 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9371 xmlXPathTrueFunction);
9372 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9373 xmlXPathTranslateFunction);
9374}
9375
9376#endif /* LIBXML_XPATH_ENABLED */