blob: b795affd1194b50945d0549cd05101f9da54d47a [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 *
1907 * Returns the value or NULL if not found
1908 */
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
1931 * variable value.
1932 *
1933 * Returns the value or NULL if not found
1934 */
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
1954 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1955}
1956
1957/**
1958 * xmlXPathRegisteredVariablesCleanup:
1959 * @ctxt: the XPath context
1960 *
1961 * Cleanup the XPath context data associated to registered variables
1962 */
1963void
1964xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1965 if (ctxt == NULL)
1966 return;
1967
Daniel Veillard76d66f42001-05-16 21:05:17 +00001968 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00001969 ctxt->varHash = NULL;
1970}
1971
1972/**
1973 * xmlXPathRegisterNs:
1974 * @ctxt: the XPath context
1975 * @prefix: the namespace prefix
1976 * @ns_uri: the namespace name
1977 *
1978 * Register a new namespace. If @ns_uri is NULL it unregisters
1979 * the namespace
1980 *
1981 * Returns 0 in case of success, -1 in case of error
1982 */
1983int
1984xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1985 const xmlChar *ns_uri) {
1986 if (ctxt == NULL)
1987 return(-1);
1988 if (prefix == NULL)
1989 return(-1);
1990
1991 if (ctxt->nsHash == NULL)
1992 ctxt->nsHash = xmlHashCreate(10);
1993 if (ctxt->nsHash == NULL)
1994 return(-1);
1995 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1996 (xmlHashDeallocator)xmlFree));
1997}
1998
1999/**
2000 * xmlXPathNsLookup:
2001 * @ctxt: the XPath context
2002 * @prefix: the namespace prefix value
2003 *
2004 * Search in the namespace declaration array of the context for the given
2005 * namespace name associated to the given prefix
2006 *
2007 * Returns the value or NULL if not found
2008 */
2009const xmlChar *
2010xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2011 if (ctxt == NULL)
2012 return(NULL);
2013 if (prefix == NULL)
2014 return(NULL);
2015
2016#ifdef XML_XML_NAMESPACE
2017 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2018 return(XML_XML_NAMESPACE);
2019#endif
2020
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002021 if (ctxt->namespaces != NULL) {
2022 int i;
2023
2024 for (i = 0;i < ctxt->nsNr;i++) {
2025 if ((ctxt->namespaces[i] != NULL) &&
2026 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2027 return(ctxt->namespaces[i]->href);
2028 }
2029 }
Owen Taylor3473f882001-02-23 17:55:21 +00002030
2031 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2032}
2033
2034/**
2035 * xmlXPathRegisteredVariablesCleanup:
2036 * @ctxt: the XPath context
2037 *
2038 * Cleanup the XPath context data associated to registered variables
2039 */
2040void
2041xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2042 if (ctxt == NULL)
2043 return;
2044
2045 xmlHashFree(ctxt->nsHash, NULL);
2046 ctxt->nsHash = NULL;
2047}
2048
2049/************************************************************************
2050 * *
2051 * Routines to handle Values *
2052 * *
2053 ************************************************************************/
2054
2055/* Allocations are terrible, one need to optimize all this !!! */
2056
2057/**
2058 * xmlXPathNewFloat:
2059 * @val: the double value
2060 *
2061 * Create a new xmlXPathObjectPtr of type double and of value @val
2062 *
2063 * Returns the newly created object.
2064 */
2065xmlXPathObjectPtr
2066xmlXPathNewFloat(double val) {
2067 xmlXPathObjectPtr ret;
2068
2069 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2070 if (ret == NULL) {
2071 xmlGenericError(xmlGenericErrorContext,
2072 "xmlXPathNewFloat: out of memory\n");
2073 return(NULL);
2074 }
2075 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2076 ret->type = XPATH_NUMBER;
2077 ret->floatval = val;
2078 return(ret);
2079}
2080
2081/**
2082 * xmlXPathNewBoolean:
2083 * @val: the boolean value
2084 *
2085 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2086 *
2087 * Returns the newly created object.
2088 */
2089xmlXPathObjectPtr
2090xmlXPathNewBoolean(int val) {
2091 xmlXPathObjectPtr ret;
2092
2093 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2094 if (ret == NULL) {
2095 xmlGenericError(xmlGenericErrorContext,
2096 "xmlXPathNewBoolean: out of memory\n");
2097 return(NULL);
2098 }
2099 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2100 ret->type = XPATH_BOOLEAN;
2101 ret->boolval = (val != 0);
2102 return(ret);
2103}
2104
2105/**
2106 * xmlXPathNewString:
2107 * @val: the xmlChar * value
2108 *
2109 * Create a new xmlXPathObjectPtr of type string and of value @val
2110 *
2111 * Returns the newly created object.
2112 */
2113xmlXPathObjectPtr
2114xmlXPathNewString(const xmlChar *val) {
2115 xmlXPathObjectPtr ret;
2116
2117 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2118 if (ret == NULL) {
2119 xmlGenericError(xmlGenericErrorContext,
2120 "xmlXPathNewString: out of memory\n");
2121 return(NULL);
2122 }
2123 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2124 ret->type = XPATH_STRING;
2125 if (val != NULL)
2126 ret->stringval = xmlStrdup(val);
2127 else
2128 ret->stringval = xmlStrdup((const xmlChar *)"");
2129 return(ret);
2130}
2131
2132/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002133 * xmlXPathWrapString:
2134 * @val: the xmlChar * value
2135 *
2136 * Wraps the @val string into an XPath object.
2137 *
2138 * Returns the newly created object.
2139 */
2140xmlXPathObjectPtr
2141xmlXPathWrapString (xmlChar *val) {
2142 xmlXPathObjectPtr ret;
2143
2144 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2145 if (ret == NULL) {
2146 xmlGenericError(xmlGenericErrorContext,
2147 "xmlXPathWrapString: out of memory\n");
2148 return(NULL);
2149 }
2150 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2151 ret->type = XPATH_STRING;
2152 ret->stringval = val;
2153 return(ret);
2154}
2155
2156/**
Owen Taylor3473f882001-02-23 17:55:21 +00002157 * xmlXPathNewCString:
2158 * @val: the char * value
2159 *
2160 * Create a new xmlXPathObjectPtr of type string and of value @val
2161 *
2162 * Returns the newly created object.
2163 */
2164xmlXPathObjectPtr
2165xmlXPathNewCString(const char *val) {
2166 xmlXPathObjectPtr ret;
2167
2168 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2169 if (ret == NULL) {
2170 xmlGenericError(xmlGenericErrorContext,
2171 "xmlXPathNewCString: out of memory\n");
2172 return(NULL);
2173 }
2174 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2175 ret->type = XPATH_STRING;
2176 ret->stringval = xmlStrdup(BAD_CAST val);
2177 return(ret);
2178}
2179
2180/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002181 * xmlXPathWrapCString:
2182 * @val: the char * value
2183 *
2184 * Wraps a string into an XPath object.
2185 *
2186 * Returns the newly created object.
2187 */
2188xmlXPathObjectPtr
2189xmlXPathWrapCString (char * val) {
2190 return(xmlXPathWrapString((xmlChar *)(val)));
2191}
2192
2193/**
Owen Taylor3473f882001-02-23 17:55:21 +00002194 * xmlXPathObjectCopy:
2195 * @val: the original object
2196 *
2197 * allocate a new copy of a given object
2198 *
2199 * Returns the newly created object.
2200 */
2201xmlXPathObjectPtr
2202xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2203 xmlXPathObjectPtr ret;
2204
2205 if (val == NULL)
2206 return(NULL);
2207
2208 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2209 if (ret == NULL) {
2210 xmlGenericError(xmlGenericErrorContext,
2211 "xmlXPathObjectCopy: out of memory\n");
2212 return(NULL);
2213 }
2214 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2215 switch (val->type) {
2216 case XPATH_BOOLEAN:
2217 case XPATH_NUMBER:
2218 case XPATH_POINT:
2219 case XPATH_RANGE:
2220 break;
2221 case XPATH_STRING:
2222 ret->stringval = xmlStrdup(val->stringval);
2223 break;
2224 case XPATH_XSLT_TREE:
2225 if ((val->nodesetval != NULL) &&
2226 (val->nodesetval->nodeTab != NULL))
2227 ret->nodesetval = xmlXPathNodeSetCreate(
2228 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2229 else
2230 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2231 break;
2232 case XPATH_NODESET:
2233 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2234 break;
2235 case XPATH_LOCATIONSET:
2236#ifdef LIBXML_XPTR_ENABLED
2237 {
2238 xmlLocationSetPtr loc = val->user;
2239 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2240 break;
2241 }
2242#endif
2243 case XPATH_UNDEFINED:
2244 case XPATH_USERS:
2245 xmlGenericError(xmlGenericErrorContext,
2246 "xmlXPathObjectCopy: unsupported type %d\n",
2247 val->type);
2248 break;
2249 }
2250 return(ret);
2251}
2252
2253/**
2254 * xmlXPathFreeObject:
2255 * @obj: the object to free
2256 *
2257 * Free up an xmlXPathObjectPtr object.
2258 */
2259void
2260xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2261 if (obj == NULL) return;
2262 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002263 if (obj->boolval) {
2264 obj->type = XPATH_XSLT_TREE;
2265 if (obj->nodesetval != NULL)
2266 xmlXPathFreeValueTree(obj->nodesetval);
2267 } else {
2268 if (obj->nodesetval != NULL)
2269 xmlXPathFreeNodeSet(obj->nodesetval);
2270 }
Owen Taylor3473f882001-02-23 17:55:21 +00002271#ifdef LIBXML_XPTR_ENABLED
2272 } else if (obj->type == XPATH_LOCATIONSET) {
2273 if (obj->user != NULL)
2274 xmlXPtrFreeLocationSet(obj->user);
2275#endif
2276 } else if (obj->type == XPATH_STRING) {
2277 if (obj->stringval != NULL)
2278 xmlFree(obj->stringval);
2279 } else if (obj->type == XPATH_XSLT_TREE) {
2280 if (obj->nodesetval != NULL)
2281 xmlXPathFreeValueTree(obj->nodesetval);
2282 }
2283
Owen Taylor3473f882001-02-23 17:55:21 +00002284 xmlFree(obj);
2285}
2286
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002287
2288/************************************************************************
2289 * *
2290 * Type Casting Routines *
2291 * *
2292 ************************************************************************/
2293
2294/**
2295 * xmlXPathCastBooleanToString:
2296 * @val: a boolean
2297 *
2298 * Converts a boolean to its string value.
2299 *
2300 * Returns a newly allocated string.
2301 */
2302xmlChar *
2303xmlXPathCastBooleanToString (int val) {
2304 xmlChar *ret;
2305 if (val)
2306 ret = xmlStrdup((const xmlChar *) "true");
2307 else
2308 ret = xmlStrdup((const xmlChar *) "false");
2309 return(ret);
2310}
2311
2312/**
2313 * xmlXPathCastNumberToString:
2314 * @val: a number
2315 *
2316 * Converts a number to its string value.
2317 *
2318 * Returns a newly allocated string.
2319 */
2320xmlChar *
2321xmlXPathCastNumberToString (double val) {
2322 xmlChar *ret;
2323 switch (isinf(val)) {
2324 case 1:
2325 ret = xmlStrdup((const xmlChar *) "+Infinity");
2326 break;
2327 case -1:
2328 ret = xmlStrdup((const xmlChar *) "-Infinity");
2329 break;
2330 default:
2331 if (isnan(val)) {
2332 ret = xmlStrdup((const xmlChar *) "NaN");
2333 } else {
2334 /* could be improved */
2335 char buf[100];
2336 xmlXPathFormatNumber(val, buf, 100);
2337 ret = xmlStrdup((const xmlChar *) buf);
2338 }
2339 }
2340 return(ret);
2341}
2342
2343/**
2344 * xmlXPathCastNodeToString:
2345 * @node: a node
2346 *
2347 * Converts a node to its string value.
2348 *
2349 * Returns a newly allocated string.
2350 */
2351xmlChar *
2352xmlXPathCastNodeToString (xmlNodePtr node) {
2353 return(xmlNodeGetContent(node));
2354}
2355
2356/**
2357 * xmlXPathCastNodeSetToString:
2358 * @ns: a node-set
2359 *
2360 * Converts a node-set to its string value.
2361 *
2362 * Returns a newly allocated string.
2363 */
2364xmlChar *
2365xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2366 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2367 return(xmlStrdup((const xmlChar *) ""));
2368
2369 xmlXPathNodeSetSort(ns);
2370 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2371}
2372
2373/**
2374 * xmlXPathCastToString:
2375 * @val: an XPath object
2376 *
2377 * Converts an existing object to its string() equivalent
2378 *
2379 * Returns the string value of the object, NULL in case of error.
2380 * A new string is allocated only if needed (val isn't a
2381 * string object).
2382 */
2383xmlChar *
2384xmlXPathCastToString(xmlXPathObjectPtr val) {
2385 xmlChar *ret = NULL;
2386
2387 if (val == NULL)
2388 return(xmlStrdup((const xmlChar *) ""));
2389 switch (val->type) {
2390 case XPATH_UNDEFINED:
2391#ifdef DEBUG_EXPR
2392 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2393#endif
2394 ret = xmlStrdup((const xmlChar *) "");
2395 break;
2396 case XPATH_XSLT_TREE:
2397 case XPATH_NODESET:
2398 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2399 break;
2400 case XPATH_STRING:
2401 return(val->stringval);
2402 case XPATH_BOOLEAN:
2403 ret = xmlXPathCastBooleanToString(val->boolval);
2404 break;
2405 case XPATH_NUMBER: {
2406 ret = xmlXPathCastNumberToString(val->floatval);
2407 break;
2408 }
2409 case XPATH_USERS:
2410 case XPATH_POINT:
2411 case XPATH_RANGE:
2412 case XPATH_LOCATIONSET:
2413 TODO
2414 ret = xmlStrdup((const xmlChar *) "");
2415 break;
2416 }
2417 return(ret);
2418}
2419
2420/**
2421 * xmlXPathConvertString:
2422 * @val: an XPath object
2423 *
2424 * Converts an existing object to its string() equivalent
2425 *
2426 * Returns the new object, the old one is freed (or the operation
2427 * is done directly on @val)
2428 */
2429xmlXPathObjectPtr
2430xmlXPathConvertString(xmlXPathObjectPtr val) {
2431 xmlChar *res = NULL;
2432
2433 if (val == NULL)
2434 return(xmlXPathNewCString(""));
2435
2436 switch (val->type) {
2437 case XPATH_UNDEFINED:
2438#ifdef DEBUG_EXPR
2439 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2440#endif
2441 break;
2442 case XPATH_XSLT_TREE:
2443 case XPATH_NODESET:
2444 res = xmlXPathCastNodeSetToString(val->nodesetval);
2445 break;
2446 case XPATH_STRING:
2447 return(val);
2448 case XPATH_BOOLEAN:
2449 res = xmlXPathCastBooleanToString(val->boolval);
2450 break;
2451 case XPATH_NUMBER:
2452 res = xmlXPathCastNumberToString(val->floatval);
2453 break;
2454 case XPATH_USERS:
2455 case XPATH_POINT:
2456 case XPATH_RANGE:
2457 case XPATH_LOCATIONSET:
2458 TODO;
2459 break;
2460 }
2461 xmlXPathFreeObject(val);
2462 if (res == NULL)
2463 return(xmlXPathNewCString(""));
2464 return(xmlXPathWrapString(res));
2465}
2466
2467/**
2468 * xmlXPathCastBooleanToNumber:
2469 * @val: a boolean
2470 *
2471 * Converts a boolean to its number value
2472 *
2473 * Returns the number value
2474 */
2475double
2476xmlXPathCastBooleanToNumber(int val) {
2477 if (val)
2478 return(1.0);
2479 return(0.0);
2480}
2481
2482/**
2483 * xmlXPathCastStringToNumber:
2484 * @val: a string
2485 *
2486 * Converts a string to its number value
2487 *
2488 * Returns the number value
2489 */
2490double
2491xmlXPathCastStringToNumber(const xmlChar * val) {
2492 return(xmlXPathStringEvalNumber(val));
2493}
2494
2495/**
2496 * xmlXPathCastNodeToNumber:
2497 * @node: a node
2498 *
2499 * Converts a node to its number value
2500 *
2501 * Returns the number value
2502 */
2503double
2504xmlXPathCastNodeToNumber (xmlNodePtr node) {
2505 xmlChar *strval;
2506 double ret;
2507
2508 if (node == NULL)
2509 return(xmlXPathNAN);
2510 strval = xmlXPathCastNodeToString(node);
2511 if (strval == NULL)
2512 return(xmlXPathNAN);
2513 ret = xmlXPathCastStringToNumber(strval);
2514 xmlFree(strval);
2515
2516 return(ret);
2517}
2518
2519/**
2520 * xmlXPathCastNodeSetToNumber:
2521 * @ns: a node-set
2522 *
2523 * Converts a node-set to its number value
2524 *
2525 * Returns the number value
2526 */
2527double
2528xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
2529 xmlChar *str;
2530 double ret;
2531
2532 if (ns == NULL)
2533 return(xmlXPathNAN);
2534 str = xmlXPathCastNodeSetToString(ns);
2535 ret = xmlXPathCastStringToNumber(str);
2536 xmlFree(str);
2537 return(ret);
2538}
2539
2540/**
2541 * xmlXPathCastToNumber:
2542 * @val: an XPath object
2543 *
2544 * Converts an XPath object to its number value
2545 *
2546 * Returns the number value
2547 */
2548double
2549xmlXPathCastToNumber(xmlXPathObjectPtr val) {
2550 double ret = 0.0;
2551
2552 if (val == NULL)
2553 return(xmlXPathNAN);
2554 switch (val->type) {
2555 case XPATH_UNDEFINED:
2556#ifdef DEGUB_EXPR
2557 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
2558#endif
2559 ret = xmlXPathNAN;
2560 break;
2561 case XPATH_XSLT_TREE:
2562 case XPATH_NODESET:
2563 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
2564 break;
2565 case XPATH_STRING:
2566 ret = xmlXPathCastStringToNumber(val->stringval);
2567 break;
2568 case XPATH_NUMBER:
2569 ret = val->floatval;
2570 break;
2571 case XPATH_BOOLEAN:
2572 ret = xmlXPathCastBooleanToNumber(val->boolval);
2573 break;
2574 case XPATH_USERS:
2575 case XPATH_POINT:
2576 case XPATH_RANGE:
2577 case XPATH_LOCATIONSET:
2578 TODO;
2579 ret = xmlXPathNAN;
2580 break;
2581 }
2582 return(ret);
2583}
2584
2585/**
2586 * xmlXPathConvertNumber:
2587 * @val: an XPath object
2588 *
2589 * Converts an existing object to its number() equivalent
2590 *
2591 * Returns the new object, the old one is freed (or the operation
2592 * is done directly on @val)
2593 */
2594xmlXPathObjectPtr
2595xmlXPathConvertNumber(xmlXPathObjectPtr val) {
2596 xmlXPathObjectPtr ret;
2597
2598 if (val == NULL)
2599 return(xmlXPathNewFloat(0.0));
2600 if (val->type == XPATH_NUMBER)
2601 return(val);
2602 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
2603 xmlXPathFreeObject(val);
2604 return(ret);
2605}
2606
2607/**
2608 * xmlXPathCastNumberToBoolean:
2609 * @val: a number
2610 *
2611 * Converts a number to its boolean value
2612 *
2613 * Returns the boolean value
2614 */
2615int
2616xmlXPathCastNumberToBoolean (double val) {
2617 if (isnan(val) || (val == 0.0))
2618 return(0);
2619 return(1);
2620}
2621
2622/**
2623 * xmlXPathCastStringToBoolean:
2624 * @val: a string
2625 *
2626 * Converts a string to its boolean value
2627 *
2628 * Returns the boolean value
2629 */
2630int
2631xmlXPathCastStringToBoolean (const xmlChar *val) {
2632 if ((val == NULL) || (xmlStrlen(val) == 0))
2633 return(0);
2634 return(1);
2635}
2636
2637/**
2638 * xmlXPathCastNodeSetToBoolean:
2639 * @ns: a node-set
2640 *
2641 * Converts a node-set to its boolean value
2642 *
2643 * Returns the boolean value
2644 */
2645int
2646xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
2647 if ((ns == NULL) || (ns->nodeNr == 0))
2648 return(0);
2649 return(1);
2650}
2651
2652/**
2653 * xmlXpathCastToBoolean:
2654 * @val: an XPath object
2655 *
2656 * Converts an XPath object to its boolean value
2657 *
2658 * Returns the boolean value
2659 */
2660int
2661xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
2662 int ret = 0;
2663
2664 if (val == NULL)
2665 return(0);
2666 switch (val->type) {
2667 case XPATH_UNDEFINED:
2668#ifdef DEBUG_EXPR
2669 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
2670#endif
2671 ret = 0;
2672 break;
2673 case XPATH_XSLT_TREE:
2674 case XPATH_NODESET:
2675 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
2676 break;
2677 case XPATH_STRING:
2678 ret = xmlXPathCastStringToBoolean(val->stringval);
2679 break;
2680 case XPATH_NUMBER:
2681 ret = xmlXPathCastNumberToBoolean(val->floatval);
2682 break;
2683 case XPATH_BOOLEAN:
2684 ret = val->boolval;
2685 break;
2686 case XPATH_USERS:
2687 case XPATH_POINT:
2688 case XPATH_RANGE:
2689 case XPATH_LOCATIONSET:
2690 TODO;
2691 ret = 0;
2692 break;
2693 }
2694 return(ret);
2695}
2696
2697
2698/**
2699 * xmlXPathConvertBoolean:
2700 * @val: an XPath object
2701 *
2702 * Converts an existing object to its boolean() equivalent
2703 *
2704 * Returns the new object, the old one is freed (or the operation
2705 * is done directly on @val)
2706 */
2707xmlXPathObjectPtr
2708xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
2709 xmlXPathObjectPtr ret;
2710
2711 if (val == NULL)
2712 return(xmlXPathNewBoolean(0));
2713 if (val->type == XPATH_BOOLEAN)
2714 return(val);
2715 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
2716 xmlXPathFreeObject(val);
2717 return(ret);
2718}
2719
Owen Taylor3473f882001-02-23 17:55:21 +00002720/************************************************************************
2721 * *
2722 * Routines to handle XPath contexts *
2723 * *
2724 ************************************************************************/
2725
2726/**
2727 * xmlXPathNewContext:
2728 * @doc: the XML document
2729 *
2730 * Create a new xmlXPathContext
2731 *
2732 * Returns the xmlXPathContext just allocated.
2733 */
2734xmlXPathContextPtr
2735xmlXPathNewContext(xmlDocPtr doc) {
2736 xmlXPathContextPtr ret;
2737
2738 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2739 if (ret == NULL) {
2740 xmlGenericError(xmlGenericErrorContext,
2741 "xmlXPathNewContext: out of memory\n");
2742 return(NULL);
2743 }
2744 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2745 ret->doc = doc;
2746 ret->node = NULL;
2747
2748 ret->varHash = NULL;
2749
2750 ret->nb_types = 0;
2751 ret->max_types = 0;
2752 ret->types = NULL;
2753
2754 ret->funcHash = xmlHashCreate(0);
2755
2756 ret->nb_axis = 0;
2757 ret->max_axis = 0;
2758 ret->axis = NULL;
2759
2760 ret->nsHash = NULL;
2761 ret->user = NULL;
2762
2763 ret->contextSize = -1;
2764 ret->proximityPosition = -1;
2765
2766 xmlXPathRegisterAllFunctions(ret);
2767
2768 return(ret);
2769}
2770
2771/**
2772 * xmlXPathFreeContext:
2773 * @ctxt: the context to free
2774 *
2775 * Free up an xmlXPathContext
2776 */
2777void
2778xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2779 xmlXPathRegisteredNsCleanup(ctxt);
2780 xmlXPathRegisteredFuncsCleanup(ctxt);
2781 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002782 xmlFree(ctxt);
2783}
2784
2785/************************************************************************
2786 * *
2787 * Routines to handle XPath parser contexts *
2788 * *
2789 ************************************************************************/
2790
2791#define CHECK_CTXT(ctxt) \
2792 if (ctxt == NULL) { \
2793 xmlGenericError(xmlGenericErrorContext, \
2794 "%s:%d Internal error: ctxt == NULL\n", \
2795 __FILE__, __LINE__); \
2796 } \
2797
2798
2799#define CHECK_CONTEXT(ctxt) \
2800 if (ctxt == NULL) { \
2801 xmlGenericError(xmlGenericErrorContext, \
2802 "%s:%d Internal error: no context\n", \
2803 __FILE__, __LINE__); \
2804 } \
2805 else if (ctxt->doc == NULL) { \
2806 xmlGenericError(xmlGenericErrorContext, \
2807 "%s:%d Internal error: no document\n", \
2808 __FILE__, __LINE__); \
2809 } \
2810 else if (ctxt->doc->children == NULL) { \
2811 xmlGenericError(xmlGenericErrorContext, \
2812 "%s:%d Internal error: document without root\n", \
2813 __FILE__, __LINE__); \
2814 } \
2815
2816
2817/**
2818 * xmlXPathNewParserContext:
2819 * @str: the XPath expression
2820 * @ctxt: the XPath context
2821 *
2822 * Create a new xmlXPathParserContext
2823 *
2824 * Returns the xmlXPathParserContext just allocated.
2825 */
2826xmlXPathParserContextPtr
2827xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2828 xmlXPathParserContextPtr ret;
2829
2830 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2831 if (ret == NULL) {
2832 xmlGenericError(xmlGenericErrorContext,
2833 "xmlXPathNewParserContext: out of memory\n");
2834 return(NULL);
2835 }
2836 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2837 ret->cur = ret->base = str;
2838 ret->context = ctxt;
2839
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002840 ret->comp = xmlXPathNewCompExpr();
2841 if (ret->comp == NULL) {
2842 xmlFree(ret->valueTab);
2843 xmlFree(ret);
2844 return(NULL);
2845 }
2846
2847 return(ret);
2848}
2849
2850/**
2851 * xmlXPathCompParserContext:
2852 * @comp: the XPath compiled expression
2853 * @ctxt: the XPath context
2854 *
2855 * Create a new xmlXPathParserContext when processing a compiled expression
2856 *
2857 * Returns the xmlXPathParserContext just allocated.
2858 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002859static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002860xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2861 xmlXPathParserContextPtr ret;
2862
2863 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2864 if (ret == NULL) {
2865 xmlGenericError(xmlGenericErrorContext,
2866 "xmlXPathNewParserContext: out of memory\n");
2867 return(NULL);
2868 }
2869 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2870
Owen Taylor3473f882001-02-23 17:55:21 +00002871 /* Allocate the value stack */
2872 ret->valueTab = (xmlXPathObjectPtr *)
2873 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002874 if (ret->valueTab == NULL) {
2875 xmlFree(ret);
2876 xmlGenericError(xmlGenericErrorContext,
2877 "xmlXPathNewParserContext: out of memory\n");
2878 return(NULL);
2879 }
Owen Taylor3473f882001-02-23 17:55:21 +00002880 ret->valueNr = 0;
2881 ret->valueMax = 10;
2882 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002883
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002884 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002885 ret->comp = comp;
2886
Owen Taylor3473f882001-02-23 17:55:21 +00002887 return(ret);
2888}
2889
2890/**
2891 * xmlXPathFreeParserContext:
2892 * @ctxt: the context to free
2893 *
2894 * Free up an xmlXPathParserContext
2895 */
2896void
2897xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2898 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002899 xmlFree(ctxt->valueTab);
2900 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002901 if (ctxt->comp)
2902 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002903 xmlFree(ctxt);
2904}
2905
2906/************************************************************************
2907 * *
2908 * The implicit core function library *
2909 * *
2910 ************************************************************************/
2911
Owen Taylor3473f882001-02-23 17:55:21 +00002912/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00002913 * xmlXPathNodeStringHash:
2914 * @node: a node pointer
2915 *
2916 * Function computing the beginning of the string value of the node,
2917 * used to speed up comparisons
2918 *
2919 * Returns an int usable as a hash
2920 */
2921static unsigned int
2922xmlXPathNodeValHash(xmlNodePtr node) {
2923 int len = 2;
2924 const xmlChar * string = NULL;
2925 xmlNodePtr tmp = NULL;
2926 unsigned int ret = 0;
2927
2928 if (node == NULL)
2929 return(0);
2930
2931
2932 switch (node->type) {
2933 case XML_COMMENT_NODE:
2934 case XML_PI_NODE:
2935 case XML_CDATA_SECTION_NODE:
2936 case XML_TEXT_NODE:
2937 string = node->content;
2938 if (string == NULL)
2939 return(0);
2940 if (string[0] == 0)
2941 return(0);
2942 return(((unsigned int) string[0]) +
2943 (((unsigned int) string[1]) << 8));
2944 case XML_NAMESPACE_DECL:
2945 string = ((xmlNsPtr)node)->href;
2946 if (string == NULL)
2947 return(0);
2948 if (string[0] == 0)
2949 return(0);
2950 return(((unsigned int) string[0]) +
2951 (((unsigned int) string[1]) << 8));
2952 case XML_ATTRIBUTE_NODE:
2953 tmp = ((xmlAttrPtr) node)->children;
2954 break;
2955 case XML_ELEMENT_NODE:
2956 tmp = node->children;
2957 break;
2958 default:
2959 return(0);
2960 }
2961 while (tmp != NULL) {
2962 switch (tmp->type) {
2963 case XML_COMMENT_NODE:
2964 case XML_PI_NODE:
2965 case XML_CDATA_SECTION_NODE:
2966 case XML_TEXT_NODE:
2967 string = tmp->content;
2968 break;
2969 case XML_NAMESPACE_DECL:
2970 string = ((xmlNsPtr)tmp)->href;
2971 break;
2972 default:
2973 break;
2974 }
2975 if ((string != NULL) && (string[0] != 0)) {
2976 if (string[0] == 0)
2977 return(0);
2978 if (len == 1) {
2979 return(ret + (((unsigned int) string[0]) << 8));
2980 }
2981 if (string[1] == 0) {
2982 len = 1;
2983 ret = (unsigned int) string[0];
2984 } else {
2985 return(((unsigned int) string[0]) +
2986 (((unsigned int) string[1]) << 8));
2987 }
2988 }
2989 /*
2990 * Skip to next node
2991 */
2992 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
2993 if (tmp->children->type != XML_ENTITY_DECL) {
2994 tmp = tmp->children;
2995 continue;
2996 }
2997 }
2998 if (tmp == node)
2999 break;
3000
3001 if (tmp->next != NULL) {
3002 tmp = tmp->next;
3003 continue;
3004 }
3005
3006 do {
3007 tmp = tmp->parent;
3008 if (tmp == NULL)
3009 break;
3010 if (tmp == node) {
3011 tmp = NULL;
3012 break;
3013 }
3014 if (tmp->next != NULL) {
3015 tmp = tmp->next;
3016 break;
3017 }
3018 } while (tmp != NULL);
3019 }
3020 return(ret);
3021}
3022
3023/**
3024 * xmlXPathStringHash:
3025 * @string: a string
3026 *
3027 * Function computing the beginning of the string value of the node,
3028 * used to speed up comparisons
3029 *
3030 * Returns an int usable as a hash
3031 */
3032static unsigned int
3033xmlXPathStringHash(const xmlChar * string) {
3034 if (string == NULL)
3035 return((unsigned int) 0);
3036 if (string[0] == 0)
3037 return(0);
3038 return(((unsigned int) string[0]) +
3039 (((unsigned int) string[1]) << 8));
3040}
3041
3042/**
Owen Taylor3473f882001-02-23 17:55:21 +00003043 * xmlXPathCompareNodeSetFloat:
3044 * @ctxt: the XPath Parser context
3045 * @inf: less than (1) or greater than (0)
3046 * @strict: is the comparison strict
3047 * @arg: the node set
3048 * @f: the value
3049 *
3050 * Implement the compare operation between a nodeset and a number
3051 * @ns < @val (1, 1, ...
3052 * @ns <= @val (1, 0, ...
3053 * @ns > @val (0, 1, ...
3054 * @ns >= @val (0, 0, ...
3055 *
3056 * If one object to be compared is a node-set and the other is a number,
3057 * then the comparison will be true if and only if there is a node in the
3058 * node-set such that the result of performing the comparison on the number
3059 * to be compared and on the result of converting the string-value of that
3060 * node to a number using the number function is true.
3061 *
3062 * Returns 0 or 1 depending on the results of the test.
3063 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003064static int
Owen Taylor3473f882001-02-23 17:55:21 +00003065xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3066 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3067 int i, ret = 0;
3068 xmlNodeSetPtr ns;
3069 xmlChar *str2;
3070
3071 if ((f == NULL) || (arg == NULL) ||
3072 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3073 xmlXPathFreeObject(arg);
3074 xmlXPathFreeObject(f);
3075 return(0);
3076 }
3077 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003078 if (ns != NULL) {
3079 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003080 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003081 if (str2 != NULL) {
3082 valuePush(ctxt,
3083 xmlXPathNewString(str2));
3084 xmlFree(str2);
3085 xmlXPathNumberFunction(ctxt, 1);
3086 valuePush(ctxt, xmlXPathObjectCopy(f));
3087 ret = xmlXPathCompareValues(ctxt, inf, strict);
3088 if (ret)
3089 break;
3090 }
3091 }
Owen Taylor3473f882001-02-23 17:55:21 +00003092 }
3093 xmlXPathFreeObject(arg);
3094 xmlXPathFreeObject(f);
3095 return(ret);
3096}
3097
3098/**
3099 * xmlXPathCompareNodeSetString:
3100 * @ctxt: the XPath Parser context
3101 * @inf: less than (1) or greater than (0)
3102 * @strict: is the comparison strict
3103 * @arg: the node set
3104 * @s: the value
3105 *
3106 * Implement the compare operation between a nodeset and a string
3107 * @ns < @val (1, 1, ...
3108 * @ns <= @val (1, 0, ...
3109 * @ns > @val (0, 1, ...
3110 * @ns >= @val (0, 0, ...
3111 *
3112 * If one object to be compared is a node-set and the other is a string,
3113 * then the comparison will be true if and only if there is a node in
3114 * the node-set such that the result of performing the comparison on the
3115 * string-value of the node and the other string is true.
3116 *
3117 * Returns 0 or 1 depending on the results of the test.
3118 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003119static int
Owen Taylor3473f882001-02-23 17:55:21 +00003120xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3121 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3122 int i, ret = 0;
3123 xmlNodeSetPtr ns;
3124 xmlChar *str2;
3125
3126 if ((s == NULL) || (arg == NULL) ||
3127 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3128 xmlXPathFreeObject(arg);
3129 xmlXPathFreeObject(s);
3130 return(0);
3131 }
3132 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003133 if (ns != NULL) {
3134 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003135 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003136 if (str2 != NULL) {
3137 valuePush(ctxt,
3138 xmlXPathNewString(str2));
3139 xmlFree(str2);
3140 valuePush(ctxt, xmlXPathObjectCopy(s));
3141 ret = xmlXPathCompareValues(ctxt, inf, strict);
3142 if (ret)
3143 break;
3144 }
3145 }
Owen Taylor3473f882001-02-23 17:55:21 +00003146 }
3147 xmlXPathFreeObject(arg);
3148 xmlXPathFreeObject(s);
3149 return(ret);
3150}
3151
3152/**
3153 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003154 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003155 * @strict: is the comparison strict
3156 * @arg1: the fist node set object
3157 * @arg2: the second node set object
3158 *
3159 * Implement the compare operation on nodesets:
3160 *
3161 * If both objects to be compared are node-sets, then the comparison
3162 * will be true if and only if there is a node in the first node-set
3163 * and a node in the second node-set such that the result of performing
3164 * the comparison on the string-values of the two nodes is true.
3165 * ....
3166 * When neither object to be compared is a node-set and the operator
3167 * is <=, <, >= or >, then the objects are compared by converting both
3168 * objects to numbers and comparing the numbers according to IEEE 754.
3169 * ....
3170 * The number function converts its argument to a number as follows:
3171 * - a string that consists of optional whitespace followed by an
3172 * optional minus sign followed by a Number followed by whitespace
3173 * is converted to the IEEE 754 number that is nearest (according
3174 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3175 * represented by the string; any other string is converted to NaN
3176 *
3177 * Conclusion all nodes need to be converted first to their string value
3178 * and then the comparison must be done when possible
3179 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003180static int
3181xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003182 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3183 int i, j, init = 0;
3184 double val1;
3185 double *values2;
3186 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003187 xmlNodeSetPtr ns1;
3188 xmlNodeSetPtr ns2;
3189
3190 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003191 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3192 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003193 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003194 }
Owen Taylor3473f882001-02-23 17:55:21 +00003195 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003196 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3197 xmlXPathFreeObject(arg1);
3198 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003199 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003200 }
Owen Taylor3473f882001-02-23 17:55:21 +00003201
3202 ns1 = arg1->nodesetval;
3203 ns2 = arg2->nodesetval;
3204
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003205 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003206 xmlXPathFreeObject(arg1);
3207 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003208 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003209 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003210 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003211 xmlXPathFreeObject(arg1);
3212 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003213 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003214 }
Owen Taylor3473f882001-02-23 17:55:21 +00003215
3216 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3217 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003218 xmlXPathFreeObject(arg1);
3219 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003220 return(0);
3221 }
3222 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003223 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003224 if (isnan(val1))
3225 continue;
3226 for (j = 0;j < ns2->nodeNr;j++) {
3227 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003228 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003229 }
3230 if (isnan(values2[j]))
3231 continue;
3232 if (inf && strict)
3233 ret = (val1 < values2[j]);
3234 else if (inf && !strict)
3235 ret = (val1 <= values2[j]);
3236 else if (!inf && strict)
3237 ret = (val1 > values2[j]);
3238 else if (!inf && !strict)
3239 ret = (val1 >= values2[j]);
3240 if (ret)
3241 break;
3242 }
3243 if (ret)
3244 break;
3245 init = 1;
3246 }
3247 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003248 xmlXPathFreeObject(arg1);
3249 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003250 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003251}
3252
3253/**
3254 * xmlXPathCompareNodeSetValue:
3255 * @ctxt: the XPath Parser context
3256 * @inf: less than (1) or greater than (0)
3257 * @strict: is the comparison strict
3258 * @arg: the node set
3259 * @val: the value
3260 *
3261 * Implement the compare operation between a nodeset and a value
3262 * @ns < @val (1, 1, ...
3263 * @ns <= @val (1, 0, ...
3264 * @ns > @val (0, 1, ...
3265 * @ns >= @val (0, 0, ...
3266 *
3267 * If one object to be compared is a node-set and the other is a boolean,
3268 * then the comparison will be true if and only if the result of performing
3269 * the comparison on the boolean and on the result of converting
3270 * the node-set to a boolean using the boolean function is true.
3271 *
3272 * Returns 0 or 1 depending on the results of the test.
3273 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003274static int
Owen Taylor3473f882001-02-23 17:55:21 +00003275xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3276 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3277 if ((val == NULL) || (arg == NULL) ||
3278 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3279 return(0);
3280
3281 switch(val->type) {
3282 case XPATH_NUMBER:
3283 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3284 case XPATH_NODESET:
3285 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003286 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003287 case XPATH_STRING:
3288 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3289 case XPATH_BOOLEAN:
3290 valuePush(ctxt, arg);
3291 xmlXPathBooleanFunction(ctxt, 1);
3292 valuePush(ctxt, val);
3293 return(xmlXPathCompareValues(ctxt, inf, strict));
3294 default:
3295 TODO
3296 return(0);
3297 }
3298 return(0);
3299}
3300
3301/**
3302 * xmlXPathEqualNodeSetString
3303 * @arg: the nodeset object argument
3304 * @str: the string to compare to.
3305 *
3306 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3307 * If one object to be compared is a node-set and the other is a string,
3308 * then the comparison will be true if and only if there is a node in
3309 * the node-set such that the result of performing the comparison on the
3310 * string-value of the node and the other string is true.
3311 *
3312 * Returns 0 or 1 depending on the results of the test.
3313 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003314static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003315xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3316{
Owen Taylor3473f882001-02-23 17:55:21 +00003317 int i;
3318 xmlNodeSetPtr ns;
3319 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003320 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003321
3322 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003323 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3324 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003325 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003326 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003327 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003328 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003329 if (ns->nodeNr <= 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003330 return (0);
3331 for (i = 0; i < ns->nodeNr; i++) {
3332 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3333 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3334 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3335 xmlFree(str2);
3336 return (1);
3337 }
3338 if (str2 != NULL)
3339 xmlFree(str2);
3340 }
Owen Taylor3473f882001-02-23 17:55:21 +00003341 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003342 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003343}
3344
3345/**
3346 * xmlXPathEqualNodeSetFloat
3347 * @arg: the nodeset object argument
3348 * @f: the float to compare to
3349 *
3350 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3351 * If one object to be compared is a node-set and the other is a number,
3352 * then the comparison will be true if and only if there is a node in
3353 * the node-set such that the result of performing the comparison on the
3354 * number to be compared and on the result of converting the string-value
3355 * of that node to a number using the number function is true.
3356 *
3357 * Returns 0 or 1 depending on the results of the test.
3358 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003359static int
Owen Taylor3473f882001-02-23 17:55:21 +00003360xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3361 char buf[100] = "";
3362
3363 if ((arg == NULL) ||
3364 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3365 return(0);
3366
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003367 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003368 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3369}
3370
3371
3372/**
3373 * xmlXPathEqualNodeSets
3374 * @arg1: first nodeset object argument
3375 * @arg2: second nodeset object argument
3376 *
3377 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3378 * If both objects to be compared are node-sets, then the comparison
3379 * will be true if and only if there is a node in the first node-set and
3380 * a node in the second node-set such that the result of performing the
3381 * comparison on the string-values of the two nodes is true.
3382 *
3383 * (needless to say, this is a costly operation)
3384 *
3385 * Returns 0 or 1 depending on the results of the test.
3386 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003387static int
Owen Taylor3473f882001-02-23 17:55:21 +00003388xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3389 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003390 unsigned int *hashs1;
3391 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003392 xmlChar **values1;
3393 xmlChar **values2;
3394 int ret = 0;
3395 xmlNodeSetPtr ns1;
3396 xmlNodeSetPtr ns2;
3397
3398 if ((arg1 == NULL) ||
3399 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3400 return(0);
3401 if ((arg2 == NULL) ||
3402 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3403 return(0);
3404
3405 ns1 = arg1->nodesetval;
3406 ns2 = arg2->nodesetval;
3407
Daniel Veillard911f49a2001-04-07 15:39:35 +00003408 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003409 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003410 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003411 return(0);
3412
3413 /*
3414 * check if there is a node pertaining to both sets
3415 */
3416 for (i = 0;i < ns1->nodeNr;i++)
3417 for (j = 0;j < ns2->nodeNr;j++)
3418 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3419 return(1);
3420
3421 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3422 if (values1 == NULL)
3423 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003424 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3425 if (hashs1 == NULL) {
3426 xmlFree(values1);
3427 return(0);
3428 }
Owen Taylor3473f882001-02-23 17:55:21 +00003429 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3430 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3431 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003432 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003433 xmlFree(values1);
3434 return(0);
3435 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003436 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3437 if (hashs2 == NULL) {
3438 xmlFree(hashs1);
3439 xmlFree(values1);
3440 xmlFree(values2);
3441 return(0);
3442 }
Owen Taylor3473f882001-02-23 17:55:21 +00003443 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3444 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003445 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003446 for (j = 0;j < ns2->nodeNr;j++) {
3447 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003448 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
3449 if (hashs1[i] == hashs2[j]) {
3450 if (values1[i] == NULL)
3451 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3452 if (values2[j] == NULL)
3453 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3454 ret = xmlStrEqual(values1[i], values2[j]);
3455 if (ret)
3456 break;
3457 }
Owen Taylor3473f882001-02-23 17:55:21 +00003458 }
3459 if (ret)
3460 break;
3461 }
3462 for (i = 0;i < ns1->nodeNr;i++)
3463 if (values1[i] != NULL)
3464 xmlFree(values1[i]);
3465 for (j = 0;j < ns2->nodeNr;j++)
3466 if (values2[j] != NULL)
3467 xmlFree(values2[j]);
3468 xmlFree(values1);
3469 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003470 xmlFree(hashs1);
3471 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00003472 return(ret);
3473}
3474
3475/**
3476 * xmlXPathEqualValues:
3477 * @ctxt: the XPath Parser context
3478 *
3479 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3480 *
3481 * Returns 0 or 1 depending on the results of the test.
3482 */
3483int
3484xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
3485 xmlXPathObjectPtr arg1, arg2;
3486 int ret = 0;
3487
3488 arg1 = valuePop(ctxt);
3489 if (arg1 == NULL)
3490 XP_ERROR0(XPATH_INVALID_OPERAND);
3491
3492 arg2 = valuePop(ctxt);
3493 if (arg2 == NULL) {
3494 xmlXPathFreeObject(arg1);
3495 XP_ERROR0(XPATH_INVALID_OPERAND);
3496 }
3497
3498 if (arg1 == arg2) {
3499#ifdef DEBUG_EXPR
3500 xmlGenericError(xmlGenericErrorContext,
3501 "Equal: by pointer\n");
3502#endif
3503 return(1);
3504 }
3505
3506 switch (arg1->type) {
3507 case XPATH_UNDEFINED:
3508#ifdef DEBUG_EXPR
3509 xmlGenericError(xmlGenericErrorContext,
3510 "Equal: undefined\n");
3511#endif
3512 break;
3513 case XPATH_XSLT_TREE:
3514 case XPATH_NODESET:
3515 switch (arg2->type) {
3516 case XPATH_UNDEFINED:
3517#ifdef DEBUG_EXPR
3518 xmlGenericError(xmlGenericErrorContext,
3519 "Equal: undefined\n");
3520#endif
3521 break;
3522 case XPATH_XSLT_TREE:
3523 case XPATH_NODESET:
3524 ret = xmlXPathEqualNodeSets(arg1, arg2);
3525 break;
3526 case XPATH_BOOLEAN:
3527 if ((arg1->nodesetval == NULL) ||
3528 (arg1->nodesetval->nodeNr == 0)) ret = 0;
3529 else
3530 ret = 1;
3531 ret = (ret == arg2->boolval);
3532 break;
3533 case XPATH_NUMBER:
3534 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
3535 break;
3536 case XPATH_STRING:
3537 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
3538 break;
3539 case XPATH_USERS:
3540 case XPATH_POINT:
3541 case XPATH_RANGE:
3542 case XPATH_LOCATIONSET:
3543 TODO
3544 break;
3545 }
3546 break;
3547 case XPATH_BOOLEAN:
3548 switch (arg2->type) {
3549 case XPATH_UNDEFINED:
3550#ifdef DEBUG_EXPR
3551 xmlGenericError(xmlGenericErrorContext,
3552 "Equal: undefined\n");
3553#endif
3554 break;
3555 case XPATH_NODESET:
3556 case XPATH_XSLT_TREE:
3557 if ((arg2->nodesetval == NULL) ||
3558 (arg2->nodesetval->nodeNr == 0)) ret = 0;
3559 else
3560 ret = 1;
3561 break;
3562 case XPATH_BOOLEAN:
3563#ifdef DEBUG_EXPR
3564 xmlGenericError(xmlGenericErrorContext,
3565 "Equal: %d boolean %d \n",
3566 arg1->boolval, arg2->boolval);
3567#endif
3568 ret = (arg1->boolval == arg2->boolval);
3569 break;
3570 case XPATH_NUMBER:
3571 if (arg2->floatval) ret = 1;
3572 else ret = 0;
3573 ret = (arg1->boolval == ret);
3574 break;
3575 case XPATH_STRING:
3576 if ((arg2->stringval == NULL) ||
3577 (arg2->stringval[0] == 0)) ret = 0;
3578 else
3579 ret = 1;
3580 ret = (arg1->boolval == ret);
3581 break;
3582 case XPATH_USERS:
3583 case XPATH_POINT:
3584 case XPATH_RANGE:
3585 case XPATH_LOCATIONSET:
3586 TODO
3587 break;
3588 }
3589 break;
3590 case XPATH_NUMBER:
3591 switch (arg2->type) {
3592 case XPATH_UNDEFINED:
3593#ifdef DEBUG_EXPR
3594 xmlGenericError(xmlGenericErrorContext,
3595 "Equal: undefined\n");
3596#endif
3597 break;
3598 case XPATH_NODESET:
3599 case XPATH_XSLT_TREE:
3600 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
3601 break;
3602 case XPATH_BOOLEAN:
3603 if (arg1->floatval) ret = 1;
3604 else ret = 0;
3605 ret = (arg2->boolval == ret);
3606 break;
3607 case XPATH_STRING:
3608 valuePush(ctxt, arg2);
3609 xmlXPathNumberFunction(ctxt, 1);
3610 arg2 = valuePop(ctxt);
3611 /* no break on purpose */
3612 case XPATH_NUMBER:
3613 ret = (arg1->floatval == arg2->floatval);
3614 break;
3615 case XPATH_USERS:
3616 case XPATH_POINT:
3617 case XPATH_RANGE:
3618 case XPATH_LOCATIONSET:
3619 TODO
3620 break;
3621 }
3622 break;
3623 case XPATH_STRING:
3624 switch (arg2->type) {
3625 case XPATH_UNDEFINED:
3626#ifdef DEBUG_EXPR
3627 xmlGenericError(xmlGenericErrorContext,
3628 "Equal: undefined\n");
3629#endif
3630 break;
3631 case XPATH_NODESET:
3632 case XPATH_XSLT_TREE:
3633 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
3634 break;
3635 case XPATH_BOOLEAN:
3636 if ((arg1->stringval == NULL) ||
3637 (arg1->stringval[0] == 0)) ret = 0;
3638 else
3639 ret = 1;
3640 ret = (arg2->boolval == ret);
3641 break;
3642 case XPATH_STRING:
3643 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
3644 break;
3645 case XPATH_NUMBER:
3646 valuePush(ctxt, arg1);
3647 xmlXPathNumberFunction(ctxt, 1);
3648 arg1 = valuePop(ctxt);
3649 ret = (arg1->floatval == arg2->floatval);
3650 break;
3651 case XPATH_USERS:
3652 case XPATH_POINT:
3653 case XPATH_RANGE:
3654 case XPATH_LOCATIONSET:
3655 TODO
3656 break;
3657 }
3658 break;
3659 case XPATH_USERS:
3660 case XPATH_POINT:
3661 case XPATH_RANGE:
3662 case XPATH_LOCATIONSET:
3663 TODO
3664 break;
3665 }
3666 xmlXPathFreeObject(arg1);
3667 xmlXPathFreeObject(arg2);
3668 return(ret);
3669}
3670
3671
3672/**
3673 * xmlXPathCompareValues:
3674 * @ctxt: the XPath Parser context
3675 * @inf: less than (1) or greater than (0)
3676 * @strict: is the comparison strict
3677 *
3678 * Implement the compare operation on XPath objects:
3679 * @arg1 < @arg2 (1, 1, ...
3680 * @arg1 <= @arg2 (1, 0, ...
3681 * @arg1 > @arg2 (0, 1, ...
3682 * @arg1 >= @arg2 (0, 0, ...
3683 *
3684 * When neither object to be compared is a node-set and the operator is
3685 * <=, <, >=, >, then the objects are compared by converted both objects
3686 * to numbers and comparing the numbers according to IEEE 754. The <
3687 * comparison will be true if and only if the first number is less than the
3688 * second number. The <= comparison will be true if and only if the first
3689 * number is less than or equal to the second number. The > comparison
3690 * will be true if and only if the first number is greater than the second
3691 * number. The >= comparison will be true if and only if the first number
3692 * is greater than or equal to the second number.
3693 *
3694 * Returns 1 if the comparaison succeeded, 0 if it failed
3695 */
3696int
3697xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3698 int ret = 0;
3699 xmlXPathObjectPtr arg1, arg2;
3700
3701 arg2 = valuePop(ctxt);
3702 if (arg2 == NULL) {
3703 XP_ERROR0(XPATH_INVALID_OPERAND);
3704 }
3705
3706 arg1 = valuePop(ctxt);
3707 if (arg1 == NULL) {
3708 xmlXPathFreeObject(arg2);
3709 XP_ERROR0(XPATH_INVALID_OPERAND);
3710 }
3711
3712 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3713 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003714 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003715 } else {
3716 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003717 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3718 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003719 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003720 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3721 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003722 }
3723 }
3724 return(ret);
3725 }
3726
3727 if (arg1->type != XPATH_NUMBER) {
3728 valuePush(ctxt, arg1);
3729 xmlXPathNumberFunction(ctxt, 1);
3730 arg1 = valuePop(ctxt);
3731 }
3732 if (arg1->type != XPATH_NUMBER) {
3733 xmlXPathFreeObject(arg1);
3734 xmlXPathFreeObject(arg2);
3735 XP_ERROR0(XPATH_INVALID_OPERAND);
3736 }
3737 if (arg2->type != XPATH_NUMBER) {
3738 valuePush(ctxt, arg2);
3739 xmlXPathNumberFunction(ctxt, 1);
3740 arg2 = valuePop(ctxt);
3741 }
3742 if (arg2->type != XPATH_NUMBER) {
3743 xmlXPathFreeObject(arg1);
3744 xmlXPathFreeObject(arg2);
3745 XP_ERROR0(XPATH_INVALID_OPERAND);
3746 }
3747 /*
3748 * Add tests for infinity and nan
3749 * => feedback on 3.4 for Inf and NaN
3750 */
3751 if (inf && strict)
3752 ret = (arg1->floatval < arg2->floatval);
3753 else if (inf && !strict)
3754 ret = (arg1->floatval <= arg2->floatval);
3755 else if (!inf && strict)
3756 ret = (arg1->floatval > arg2->floatval);
3757 else if (!inf && !strict)
3758 ret = (arg1->floatval >= arg2->floatval);
3759 xmlXPathFreeObject(arg1);
3760 xmlXPathFreeObject(arg2);
3761 return(ret);
3762}
3763
3764/**
3765 * xmlXPathValueFlipSign:
3766 * @ctxt: the XPath Parser context
3767 *
3768 * Implement the unary - operation on an XPath object
3769 * The numeric operators convert their operands to numbers as if
3770 * by calling the number function.
3771 */
3772void
3773xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003774 CAST_TO_NUMBER;
3775 CHECK_TYPE(XPATH_NUMBER);
3776 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00003777}
3778
3779/**
3780 * xmlXPathAddValues:
3781 * @ctxt: the XPath Parser context
3782 *
3783 * Implement the add operation on XPath objects:
3784 * The numeric operators convert their operands to numbers as if
3785 * by calling the number function.
3786 */
3787void
3788xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3789 xmlXPathObjectPtr arg;
3790 double val;
3791
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003792 arg = valuePop(ctxt);
3793 if (arg == NULL)
3794 XP_ERROR(XPATH_INVALID_OPERAND);
3795 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003796 xmlXPathFreeObject(arg);
3797
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003798 CAST_TO_NUMBER;
3799 CHECK_TYPE(XPATH_NUMBER);
3800 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00003801}
3802
3803/**
3804 * xmlXPathSubValues:
3805 * @ctxt: the XPath Parser context
3806 *
3807 * Implement the substraction operation on XPath objects:
3808 * The numeric operators convert their operands to numbers as if
3809 * by calling the number function.
3810 */
3811void
3812xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3813 xmlXPathObjectPtr arg;
3814 double val;
3815
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003816 arg = valuePop(ctxt);
3817 if (arg == NULL)
3818 XP_ERROR(XPATH_INVALID_OPERAND);
3819 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003820 xmlXPathFreeObject(arg);
3821
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003822 CAST_TO_NUMBER;
3823 CHECK_TYPE(XPATH_NUMBER);
3824 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003825}
3826
3827/**
3828 * xmlXPathMultValues:
3829 * @ctxt: the XPath Parser context
3830 *
3831 * Implement the multiply operation on XPath objects:
3832 * The numeric operators convert their operands to numbers as if
3833 * by calling the number function.
3834 */
3835void
3836xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3837 xmlXPathObjectPtr arg;
3838 double val;
3839
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003840 arg = valuePop(ctxt);
3841 if (arg == NULL)
3842 XP_ERROR(XPATH_INVALID_OPERAND);
3843 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003844 xmlXPathFreeObject(arg);
3845
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003846 CAST_TO_NUMBER;
3847 CHECK_TYPE(XPATH_NUMBER);
3848 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003849}
3850
3851/**
3852 * xmlXPathDivValues:
3853 * @ctxt: the XPath Parser context
3854 *
3855 * Implement the div operation on XPath objects @arg1 / @arg2:
3856 * The numeric operators convert their operands to numbers as if
3857 * by calling the number function.
3858 */
3859void
3860xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3861 xmlXPathObjectPtr arg;
3862 double val;
3863
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003864 arg = valuePop(ctxt);
3865 if (arg == NULL)
3866 XP_ERROR(XPATH_INVALID_OPERAND);
3867 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003868 xmlXPathFreeObject(arg);
3869
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003870 CAST_TO_NUMBER;
3871 CHECK_TYPE(XPATH_NUMBER);
3872 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003873}
3874
3875/**
3876 * xmlXPathModValues:
3877 * @ctxt: the XPath Parser context
3878 *
3879 * Implement the mod operation on XPath objects: @arg1 / @arg2
3880 * The numeric operators convert their operands to numbers as if
3881 * by calling the number function.
3882 */
3883void
3884xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3885 xmlXPathObjectPtr arg;
3886 int arg1, arg2;
3887
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003888 arg = valuePop(ctxt);
3889 if (arg == NULL)
3890 XP_ERROR(XPATH_INVALID_OPERAND);
3891 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003892 xmlXPathFreeObject(arg);
3893
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003894 CAST_TO_NUMBER;
3895 CHECK_TYPE(XPATH_NUMBER);
3896 arg1 = (int) ctxt->value->floatval;
3897 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00003898}
3899
3900/************************************************************************
3901 * *
3902 * The traversal functions *
3903 * *
3904 ************************************************************************/
3905
Owen Taylor3473f882001-02-23 17:55:21 +00003906/*
3907 * A traversal function enumerates nodes along an axis.
3908 * Initially it must be called with NULL, and it indicates
3909 * termination on the axis by returning NULL.
3910 */
3911typedef xmlNodePtr (*xmlXPathTraversalFunction)
3912 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3913
3914/**
3915 * xmlXPathNextSelf:
3916 * @ctxt: the XPath Parser context
3917 * @cur: the current node in the traversal
3918 *
3919 * Traversal function for the "self" direction
3920 * The self axis contains just the context node itself
3921 *
3922 * Returns the next element following that axis
3923 */
3924xmlNodePtr
3925xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3926 if (cur == NULL)
3927 return(ctxt->context->node);
3928 return(NULL);
3929}
3930
3931/**
3932 * xmlXPathNextChild:
3933 * @ctxt: the XPath Parser context
3934 * @cur: the current node in the traversal
3935 *
3936 * Traversal function for the "child" direction
3937 * The child axis contains the children of the context node in document order.
3938 *
3939 * Returns the next element following that axis
3940 */
3941xmlNodePtr
3942xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3943 if (cur == NULL) {
3944 if (ctxt->context->node == NULL) return(NULL);
3945 switch (ctxt->context->node->type) {
3946 case XML_ELEMENT_NODE:
3947 case XML_TEXT_NODE:
3948 case XML_CDATA_SECTION_NODE:
3949 case XML_ENTITY_REF_NODE:
3950 case XML_ENTITY_NODE:
3951 case XML_PI_NODE:
3952 case XML_COMMENT_NODE:
3953 case XML_NOTATION_NODE:
3954 case XML_DTD_NODE:
3955 return(ctxt->context->node->children);
3956 case XML_DOCUMENT_NODE:
3957 case XML_DOCUMENT_TYPE_NODE:
3958 case XML_DOCUMENT_FRAG_NODE:
3959 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003960#ifdef LIBXML_DOCB_ENABLED
3961 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003962#endif
3963 return(((xmlDocPtr) ctxt->context->node)->children);
3964 case XML_ELEMENT_DECL:
3965 case XML_ATTRIBUTE_DECL:
3966 case XML_ENTITY_DECL:
3967 case XML_ATTRIBUTE_NODE:
3968 case XML_NAMESPACE_DECL:
3969 case XML_XINCLUDE_START:
3970 case XML_XINCLUDE_END:
3971 return(NULL);
3972 }
3973 return(NULL);
3974 }
3975 if ((cur->type == XML_DOCUMENT_NODE) ||
3976 (cur->type == XML_HTML_DOCUMENT_NODE))
3977 return(NULL);
3978 return(cur->next);
3979}
3980
3981/**
3982 * xmlXPathNextDescendant:
3983 * @ctxt: the XPath Parser context
3984 * @cur: the current node in the traversal
3985 *
3986 * Traversal function for the "descendant" direction
3987 * the descendant axis contains the descendants of the context node in document
3988 * order; a descendant is a child or a child of a child and so on.
3989 *
3990 * Returns the next element following that axis
3991 */
3992xmlNodePtr
3993xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3994 if (cur == NULL) {
3995 if (ctxt->context->node == NULL)
3996 return(NULL);
3997 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3998 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3999 return(NULL);
4000
4001 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4002 return(ctxt->context->doc->children);
4003 return(ctxt->context->node->children);
4004 }
4005
4006 if (cur->children != NULL)
4007 {
4008 if (cur->children->type != XML_ENTITY_DECL)
4009 return(cur->children);
4010 }
4011 if (cur->next != NULL) return(cur->next);
4012
4013 do {
4014 cur = cur->parent;
4015 if (cur == NULL) return(NULL);
4016 if (cur == ctxt->context->node) return(NULL);
4017 if (cur->next != NULL) {
4018 cur = cur->next;
4019 return(cur);
4020 }
4021 } while (cur != NULL);
4022 return(cur);
4023}
4024
4025/**
4026 * xmlXPathNextDescendantOrSelf:
4027 * @ctxt: the XPath Parser context
4028 * @cur: the current node in the traversal
4029 *
4030 * Traversal function for the "descendant-or-self" direction
4031 * the descendant-or-self axis contains the context node and the descendants
4032 * of the context node in document order; thus the context node is the first
4033 * node on the axis, and the first child of the context node is the second node
4034 * on the axis
4035 *
4036 * Returns the next element following that axis
4037 */
4038xmlNodePtr
4039xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4040 if (cur == NULL) {
4041 if (ctxt->context->node == NULL)
4042 return(NULL);
4043 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4044 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4045 return(NULL);
4046 return(ctxt->context->node);
4047 }
4048
4049 return(xmlXPathNextDescendant(ctxt, cur));
4050}
4051
4052/**
4053 * xmlXPathNextParent:
4054 * @ctxt: the XPath Parser context
4055 * @cur: the current node in the traversal
4056 *
4057 * Traversal function for the "parent" direction
4058 * The parent axis contains the parent of the context node, if there is one.
4059 *
4060 * Returns the next element following that axis
4061 */
4062xmlNodePtr
4063xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4064 /*
4065 * the parent of an attribute or namespace node is the element
4066 * to which the attribute or namespace node is attached
4067 * Namespace handling !!!
4068 */
4069 if (cur == NULL) {
4070 if (ctxt->context->node == NULL) return(NULL);
4071 switch (ctxt->context->node->type) {
4072 case XML_ELEMENT_NODE:
4073 case XML_TEXT_NODE:
4074 case XML_CDATA_SECTION_NODE:
4075 case XML_ENTITY_REF_NODE:
4076 case XML_ENTITY_NODE:
4077 case XML_PI_NODE:
4078 case XML_COMMENT_NODE:
4079 case XML_NOTATION_NODE:
4080 case XML_DTD_NODE:
4081 case XML_ELEMENT_DECL:
4082 case XML_ATTRIBUTE_DECL:
4083 case XML_XINCLUDE_START:
4084 case XML_XINCLUDE_END:
4085 case XML_ENTITY_DECL:
4086 if (ctxt->context->node->parent == NULL)
4087 return((xmlNodePtr) ctxt->context->doc);
4088 return(ctxt->context->node->parent);
4089 case XML_ATTRIBUTE_NODE: {
4090 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4091
4092 return(att->parent);
4093 }
4094 case XML_DOCUMENT_NODE:
4095 case XML_DOCUMENT_TYPE_NODE:
4096 case XML_DOCUMENT_FRAG_NODE:
4097 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004098#ifdef LIBXML_DOCB_ENABLED
4099 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004100#endif
4101 return(NULL);
4102 case XML_NAMESPACE_DECL:
4103 /*
4104 * TODO !!! may require extending struct _xmlNs with
4105 * parent field
4106 * C.f. Infoset case...
4107 */
4108 return(NULL);
4109 }
4110 }
4111 return(NULL);
4112}
4113
4114/**
4115 * xmlXPathNextAncestor:
4116 * @ctxt: the XPath Parser context
4117 * @cur: the current node in the traversal
4118 *
4119 * Traversal function for the "ancestor" direction
4120 * the ancestor axis contains the ancestors of the context node; the ancestors
4121 * of the context node consist of the parent of context node and the parent's
4122 * parent and so on; the nodes are ordered in reverse document order; thus the
4123 * parent is the first node on the axis, and the parent's parent is the second
4124 * node on the axis
4125 *
4126 * Returns the next element following that axis
4127 */
4128xmlNodePtr
4129xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4130 /*
4131 * the parent of an attribute or namespace node is the element
4132 * to which the attribute or namespace node is attached
4133 * !!!!!!!!!!!!!
4134 */
4135 if (cur == NULL) {
4136 if (ctxt->context->node == NULL) return(NULL);
4137 switch (ctxt->context->node->type) {
4138 case XML_ELEMENT_NODE:
4139 case XML_TEXT_NODE:
4140 case XML_CDATA_SECTION_NODE:
4141 case XML_ENTITY_REF_NODE:
4142 case XML_ENTITY_NODE:
4143 case XML_PI_NODE:
4144 case XML_COMMENT_NODE:
4145 case XML_DTD_NODE:
4146 case XML_ELEMENT_DECL:
4147 case XML_ATTRIBUTE_DECL:
4148 case XML_ENTITY_DECL:
4149 case XML_NOTATION_NODE:
4150 case XML_XINCLUDE_START:
4151 case XML_XINCLUDE_END:
4152 if (ctxt->context->node->parent == NULL)
4153 return((xmlNodePtr) ctxt->context->doc);
4154 return(ctxt->context->node->parent);
4155 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004156 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004157
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004158 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004159 }
4160 case XML_DOCUMENT_NODE:
4161 case XML_DOCUMENT_TYPE_NODE:
4162 case XML_DOCUMENT_FRAG_NODE:
4163 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004164#ifdef LIBXML_DOCB_ENABLED
4165 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004166#endif
4167 return(NULL);
4168 case XML_NAMESPACE_DECL:
4169 /*
4170 * TODO !!! may require extending struct _xmlNs with
4171 * parent field
4172 * C.f. Infoset case...
4173 */
4174 return(NULL);
4175 }
4176 return(NULL);
4177 }
4178 if (cur == ctxt->context->doc->children)
4179 return((xmlNodePtr) ctxt->context->doc);
4180 if (cur == (xmlNodePtr) ctxt->context->doc)
4181 return(NULL);
4182 switch (cur->type) {
4183 case XML_ELEMENT_NODE:
4184 case XML_TEXT_NODE:
4185 case XML_CDATA_SECTION_NODE:
4186 case XML_ENTITY_REF_NODE:
4187 case XML_ENTITY_NODE:
4188 case XML_PI_NODE:
4189 case XML_COMMENT_NODE:
4190 case XML_NOTATION_NODE:
4191 case XML_DTD_NODE:
4192 case XML_ELEMENT_DECL:
4193 case XML_ATTRIBUTE_DECL:
4194 case XML_ENTITY_DECL:
4195 case XML_XINCLUDE_START:
4196 case XML_XINCLUDE_END:
4197 return(cur->parent);
4198 case XML_ATTRIBUTE_NODE: {
4199 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4200
4201 return(att->parent);
4202 }
4203 case XML_DOCUMENT_NODE:
4204 case XML_DOCUMENT_TYPE_NODE:
4205 case XML_DOCUMENT_FRAG_NODE:
4206 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004207#ifdef LIBXML_DOCB_ENABLED
4208 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004209#endif
4210 return(NULL);
4211 case XML_NAMESPACE_DECL:
4212 /*
4213 * TODO !!! may require extending struct _xmlNs with
4214 * parent field
4215 * C.f. Infoset case...
4216 */
4217 return(NULL);
4218 }
4219 return(NULL);
4220}
4221
4222/**
4223 * xmlXPathNextAncestorOrSelf:
4224 * @ctxt: the XPath Parser context
4225 * @cur: the current node in the traversal
4226 *
4227 * Traversal function for the "ancestor-or-self" direction
4228 * he ancestor-or-self axis contains the context node and ancestors of
4229 * the context node in reverse document order; thus the context node is
4230 * the first node on the axis, and the context node's parent the second;
4231 * parent here is defined the same as with the parent axis.
4232 *
4233 * Returns the next element following that axis
4234 */
4235xmlNodePtr
4236xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4237 if (cur == NULL)
4238 return(ctxt->context->node);
4239 return(xmlXPathNextAncestor(ctxt, cur));
4240}
4241
4242/**
4243 * xmlXPathNextFollowingSibling:
4244 * @ctxt: the XPath Parser context
4245 * @cur: the current node in the traversal
4246 *
4247 * Traversal function for the "following-sibling" direction
4248 * The following-sibling axis contains the following siblings of the context
4249 * node in document order.
4250 *
4251 * Returns the next element following that axis
4252 */
4253xmlNodePtr
4254xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4255 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4256 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4257 return(NULL);
4258 if (cur == (xmlNodePtr) ctxt->context->doc)
4259 return(NULL);
4260 if (cur == NULL)
4261 return(ctxt->context->node->next);
4262 return(cur->next);
4263}
4264
4265/**
4266 * xmlXPathNextPrecedingSibling:
4267 * @ctxt: the XPath Parser context
4268 * @cur: the current node in the traversal
4269 *
4270 * Traversal function for the "preceding-sibling" direction
4271 * The preceding-sibling axis contains the preceding siblings of the context
4272 * node in reverse document order; the first preceding sibling is first on the
4273 * axis; the sibling preceding that node is the second on the axis and so on.
4274 *
4275 * Returns the next element following that axis
4276 */
4277xmlNodePtr
4278xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4279 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4280 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4281 return(NULL);
4282 if (cur == (xmlNodePtr) ctxt->context->doc)
4283 return(NULL);
4284 if (cur == NULL)
4285 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004286 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4287 cur = cur->prev;
4288 if (cur == NULL)
4289 return(ctxt->context->node->prev);
4290 }
Owen Taylor3473f882001-02-23 17:55:21 +00004291 return(cur->prev);
4292}
4293
4294/**
4295 * xmlXPathNextFollowing:
4296 * @ctxt: the XPath Parser context
4297 * @cur: the current node in the traversal
4298 *
4299 * Traversal function for the "following" direction
4300 * The following axis contains all nodes in the same document as the context
4301 * node that are after the context node in document order, excluding any
4302 * descendants and excluding attribute nodes and namespace nodes; the nodes
4303 * are ordered in document order
4304 *
4305 * Returns the next element following that axis
4306 */
4307xmlNodePtr
4308xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4309 if (cur != NULL && cur->children != NULL)
4310 return cur->children ;
4311 if (cur == NULL) cur = ctxt->context->node;
4312 if (cur == NULL) return(NULL) ; /* ERROR */
4313 if (cur->next != NULL) return(cur->next) ;
4314 do {
4315 cur = cur->parent;
4316 if (cur == NULL) return(NULL);
4317 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4318 if (cur->next != NULL) return(cur->next);
4319 } while (cur != NULL);
4320 return(cur);
4321}
4322
4323/*
4324 * xmlXPathIsAncestor:
4325 * @ancestor: the ancestor node
4326 * @node: the current node
4327 *
4328 * Check that @ancestor is a @node's ancestor
4329 *
4330 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4331 */
4332static int
4333xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4334 if ((ancestor == NULL) || (node == NULL)) return(0);
4335 /* nodes need to be in the same document */
4336 if (ancestor->doc != node->doc) return(0);
4337 /* avoid searching if ancestor or node is the root node */
4338 if (ancestor == (xmlNodePtr) node->doc) return(1);
4339 if (node == (xmlNodePtr) ancestor->doc) return(0);
4340 while (node->parent != NULL) {
4341 if (node->parent == ancestor)
4342 return(1);
4343 node = node->parent;
4344 }
4345 return(0);
4346}
4347
4348/**
4349 * xmlXPathNextPreceding:
4350 * @ctxt: the XPath Parser context
4351 * @cur: the current node in the traversal
4352 *
4353 * Traversal function for the "preceding" direction
4354 * the preceding axis contains all nodes in the same document as the context
4355 * node that are before the context node in document order, excluding any
4356 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4357 * ordered in reverse document order
4358 *
4359 * Returns the next element following that axis
4360 */
4361xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004362xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4363{
Owen Taylor3473f882001-02-23 17:55:21 +00004364 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004365 cur = ctxt->context->node;
4366 if (cur == NULL)
4367 return (NULL);
4368 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4369 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004370 do {
4371 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004372 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4373 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004374 }
4375
4376 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004377 if (cur == NULL)
4378 return (NULL);
4379 if (cur == ctxt->context->doc->children)
4380 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004381 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004382 return (cur);
4383}
4384
4385/**
4386 * xmlXPathNextPrecedingInternal:
4387 * @ctxt: the XPath Parser context
4388 * @cur: the current node in the traversal
4389 *
4390 * Traversal function for the "preceding" direction
4391 * the preceding axis contains all nodes in the same document as the context
4392 * node that are before the context node in document order, excluding any
4393 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4394 * ordered in reverse document order
4395 * This is a faster implementation but internal only since it requires a
4396 * state kept in the parser context: ctxt->ancestor.
4397 *
4398 * Returns the next element following that axis
4399 */
4400static xmlNodePtr
4401xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4402 xmlNodePtr cur)
4403{
4404 if (cur == NULL) {
4405 cur = ctxt->context->node;
4406 if (cur == NULL)
4407 return (NULL);
4408 ctxt->ancestor = cur->parent;
4409 }
4410 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4411 cur = cur->prev;
4412 while (cur->prev == NULL) {
4413 cur = cur->parent;
4414 if (cur == NULL)
4415 return (NULL);
4416 if (cur == ctxt->context->doc->children)
4417 return (NULL);
4418 if (cur != ctxt->ancestor)
4419 return (cur);
4420 ctxt->ancestor = cur->parent;
4421 }
4422 cur = cur->prev;
4423 while (cur->last != NULL)
4424 cur = cur->last;
4425 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004426}
4427
4428/**
4429 * xmlXPathNextNamespace:
4430 * @ctxt: the XPath Parser context
4431 * @cur: the current attribute in the traversal
4432 *
4433 * Traversal function for the "namespace" direction
4434 * the namespace axis contains the namespace nodes of the context node;
4435 * the order of nodes on this axis is implementation-defined; the axis will
4436 * be empty unless the context node is an element
4437 *
4438 * Returns the next element following that axis
4439 */
4440xmlNodePtr
4441xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4442 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
4443 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
4444 if (ctxt->context->namespaces != NULL)
4445 xmlFree(ctxt->context->namespaces);
4446 ctxt->context->namespaces =
4447 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
4448 if (ctxt->context->namespaces == NULL) return(NULL);
4449 ctxt->context->nsNr = 0;
4450 }
4451 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
4452}
4453
4454/**
4455 * xmlXPathNextAttribute:
4456 * @ctxt: the XPath Parser context
4457 * @cur: the current attribute in the traversal
4458 *
4459 * Traversal function for the "attribute" direction
4460 * TODO: support DTD inherited default attributes
4461 *
4462 * Returns the next element following that axis
4463 */
4464xmlNodePtr
4465xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00004466 if (ctxt->context->node == NULL)
4467 return(NULL);
4468 if (ctxt->context->node->type != XML_ELEMENT_NODE)
4469 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004470 if (cur == NULL) {
4471 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4472 return(NULL);
4473 return((xmlNodePtr)ctxt->context->node->properties);
4474 }
4475 return((xmlNodePtr)cur->next);
4476}
4477
4478/************************************************************************
4479 * *
4480 * NodeTest Functions *
4481 * *
4482 ************************************************************************/
4483
Owen Taylor3473f882001-02-23 17:55:21 +00004484#define IS_FUNCTION 200
4485
Owen Taylor3473f882001-02-23 17:55:21 +00004486
4487/************************************************************************
4488 * *
4489 * Implicit tree core function library *
4490 * *
4491 ************************************************************************/
4492
4493/**
4494 * xmlXPathRoot:
4495 * @ctxt: the XPath Parser context
4496 *
4497 * Initialize the context to the root of the document
4498 */
4499void
4500xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
4501 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
4502 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4503}
4504
4505/************************************************************************
4506 * *
4507 * The explicit core function library *
4508 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
4509 * *
4510 ************************************************************************/
4511
4512
4513/**
4514 * xmlXPathLastFunction:
4515 * @ctxt: the XPath Parser context
4516 * @nargs: the number of arguments
4517 *
4518 * Implement the last() XPath function
4519 * number last()
4520 * The last function returns the number of nodes in the context node list.
4521 */
4522void
4523xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4524 CHECK_ARITY(0);
4525 if (ctxt->context->contextSize >= 0) {
4526 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
4527#ifdef DEBUG_EXPR
4528 xmlGenericError(xmlGenericErrorContext,
4529 "last() : %d\n", ctxt->context->contextSize);
4530#endif
4531 } else {
4532 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
4533 }
4534}
4535
4536/**
4537 * xmlXPathPositionFunction:
4538 * @ctxt: the XPath Parser context
4539 * @nargs: the number of arguments
4540 *
4541 * Implement the position() XPath function
4542 * number position()
4543 * The position function returns the position of the context node in the
4544 * context node list. The first position is 1, and so the last positionr
4545 * will be equal to last().
4546 */
4547void
4548xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4549 CHECK_ARITY(0);
4550 if (ctxt->context->proximityPosition >= 0) {
4551 valuePush(ctxt,
4552 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
4553#ifdef DEBUG_EXPR
4554 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
4555 ctxt->context->proximityPosition);
4556#endif
4557 } else {
4558 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
4559 }
4560}
4561
4562/**
4563 * xmlXPathCountFunction:
4564 * @ctxt: the XPath Parser context
4565 * @nargs: the number of arguments
4566 *
4567 * Implement the count() XPath function
4568 * number count(node-set)
4569 */
4570void
4571xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4572 xmlXPathObjectPtr cur;
4573
4574 CHECK_ARITY(1);
4575 if ((ctxt->value == NULL) ||
4576 ((ctxt->value->type != XPATH_NODESET) &&
4577 (ctxt->value->type != XPATH_XSLT_TREE)))
4578 XP_ERROR(XPATH_INVALID_TYPE);
4579 cur = valuePop(ctxt);
4580
Daniel Veillard911f49a2001-04-07 15:39:35 +00004581 if ((cur == NULL) || (cur->nodesetval == NULL))
4582 valuePush(ctxt, xmlXPathNewFloat((double) 0));
4583 else
4584 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00004585 xmlXPathFreeObject(cur);
4586}
4587
4588/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004589 * xmlXPathGetElementsByIds:
4590 * @doc: the document
4591 * @ids: a whitespace separated list of IDs
4592 *
4593 * Selects elements by their unique ID.
4594 *
4595 * Returns a node-set of selected elements.
4596 */
4597static xmlNodeSetPtr
4598xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
4599 xmlNodeSetPtr ret;
4600 const xmlChar *cur = ids;
4601 xmlChar *ID;
4602 xmlAttrPtr attr;
4603 xmlNodePtr elem = NULL;
4604
4605 ret = xmlXPathNodeSetCreate(NULL);
4606
4607 while (IS_BLANK(*cur)) cur++;
4608 while (*cur != 0) {
4609 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
4610 (*cur == '.') || (*cur == '-') ||
4611 (*cur == '_') || (*cur == ':') ||
4612 (IS_COMBINING(*cur)) ||
4613 (IS_EXTENDER(*cur)))
4614 cur++;
4615
4616 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
4617
4618 ID = xmlStrndup(ids, cur - ids);
4619 attr = xmlGetID(doc, ID);
4620 if (attr != NULL) {
4621 elem = attr->parent;
4622 xmlXPathNodeSetAdd(ret, elem);
4623 }
4624 if (ID != NULL)
4625 xmlFree(ID);
4626
4627 while (IS_BLANK(*cur)) cur++;
4628 ids = cur;
4629 }
4630 return(ret);
4631}
4632
4633/**
Owen Taylor3473f882001-02-23 17:55:21 +00004634 * xmlXPathIdFunction:
4635 * @ctxt: the XPath Parser context
4636 * @nargs: the number of arguments
4637 *
4638 * Implement the id() XPath function
4639 * node-set id(object)
4640 * The id function selects elements by their unique ID
4641 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
4642 * then the result is the union of the result of applying id to the
4643 * string value of each of the nodes in the argument node-set. When the
4644 * argument to id is of any other type, the argument is converted to a
4645 * string as if by a call to the string function; the string is split
4646 * into a whitespace-separated list of tokens (whitespace is any sequence
4647 * of characters matching the production S); the result is a node-set
4648 * containing the elements in the same document as the context node that
4649 * have a unique ID equal to any of the tokens in the list.
4650 */
4651void
4652xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004653 xmlChar *tokens;
4654 xmlNodeSetPtr ret;
4655 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00004656
4657 CHECK_ARITY(1);
4658 obj = valuePop(ctxt);
4659 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
4660 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004661 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00004662 int i;
4663
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004664 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004665
Daniel Veillard911f49a2001-04-07 15:39:35 +00004666 if (obj->nodesetval != NULL) {
4667 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004668 tokens =
4669 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
4670 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
4671 ret = xmlXPathNodeSetMerge(ret, ns);
4672 xmlXPathFreeNodeSet(ns);
4673 if (tokens != NULL)
4674 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004675 }
Owen Taylor3473f882001-02-23 17:55:21 +00004676 }
4677
4678 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004679 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004680 return;
4681 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004682 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00004683
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004684 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
4685 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004686
Owen Taylor3473f882001-02-23 17:55:21 +00004687 xmlXPathFreeObject(obj);
4688 return;
4689}
4690
4691/**
4692 * xmlXPathLocalNameFunction:
4693 * @ctxt: the XPath Parser context
4694 * @nargs: the number of arguments
4695 *
4696 * Implement the local-name() XPath function
4697 * string local-name(node-set?)
4698 * The local-name function returns a string containing the local part
4699 * of the name of the node in the argument node-set that is first in
4700 * document order. If the node-set is empty or the first node has no
4701 * name, an empty string is returned. If the argument is omitted it
4702 * defaults to the context node.
4703 */
4704void
4705xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4706 xmlXPathObjectPtr cur;
4707
4708 if (nargs == 0) {
4709 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4710 nargs = 1;
4711 }
4712
4713 CHECK_ARITY(1);
4714 if ((ctxt->value == NULL) ||
4715 ((ctxt->value->type != XPATH_NODESET) &&
4716 (ctxt->value->type != XPATH_XSLT_TREE)))
4717 XP_ERROR(XPATH_INVALID_TYPE);
4718 cur = valuePop(ctxt);
4719
Daniel Veillard911f49a2001-04-07 15:39:35 +00004720 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004721 valuePush(ctxt, xmlXPathNewCString(""));
4722 } else {
4723 int i = 0; /* Should be first in document order !!!!! */
4724 switch (cur->nodesetval->nodeTab[i]->type) {
4725 case XML_ELEMENT_NODE:
4726 case XML_ATTRIBUTE_NODE:
4727 case XML_PI_NODE:
4728 valuePush(ctxt,
4729 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4730 break;
4731 case XML_NAMESPACE_DECL:
4732 valuePush(ctxt, xmlXPathNewString(
4733 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4734 break;
4735 default:
4736 valuePush(ctxt, xmlXPathNewCString(""));
4737 }
4738 }
4739 xmlXPathFreeObject(cur);
4740}
4741
4742/**
4743 * xmlXPathNamespaceURIFunction:
4744 * @ctxt: the XPath Parser context
4745 * @nargs: the number of arguments
4746 *
4747 * Implement the namespace-uri() XPath function
4748 * string namespace-uri(node-set?)
4749 * The namespace-uri function returns a string containing the
4750 * namespace URI of the expanded name of the node in the argument
4751 * node-set that is first in document order. If the node-set is empty,
4752 * the first node has no name, or the expanded name has no namespace
4753 * URI, an empty string is returned. If the argument is omitted it
4754 * defaults to the context node.
4755 */
4756void
4757xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4758 xmlXPathObjectPtr cur;
4759
4760 if (nargs == 0) {
4761 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4762 nargs = 1;
4763 }
4764 CHECK_ARITY(1);
4765 if ((ctxt->value == NULL) ||
4766 ((ctxt->value->type != XPATH_NODESET) &&
4767 (ctxt->value->type != XPATH_XSLT_TREE)))
4768 XP_ERROR(XPATH_INVALID_TYPE);
4769 cur = valuePop(ctxt);
4770
Daniel Veillard911f49a2001-04-07 15:39:35 +00004771 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004772 valuePush(ctxt, xmlXPathNewCString(""));
4773 } else {
4774 int i = 0; /* Should be first in document order !!!!! */
4775 switch (cur->nodesetval->nodeTab[i]->type) {
4776 case XML_ELEMENT_NODE:
4777 case XML_ATTRIBUTE_NODE:
4778 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4779 valuePush(ctxt, xmlXPathNewCString(""));
4780 else
4781 valuePush(ctxt, xmlXPathNewString(
4782 cur->nodesetval->nodeTab[i]->ns->href));
4783 break;
4784 default:
4785 valuePush(ctxt, xmlXPathNewCString(""));
4786 }
4787 }
4788 xmlXPathFreeObject(cur);
4789}
4790
4791/**
4792 * xmlXPathNameFunction:
4793 * @ctxt: the XPath Parser context
4794 * @nargs: the number of arguments
4795 *
4796 * Implement the name() XPath function
4797 * string name(node-set?)
4798 * The name function returns a string containing a QName representing
4799 * the name of the node in the argument node-set that is first in documenti
4800 * order. The QName must represent the name with respect to the namespace
4801 * declarations in effect on the node whose name is being represented.
4802 * Typically, this will be the form in which the name occurred in the XML
4803 * source. This need not be the case if there are namespace declarations
4804 * in effect on the node that associate multiple prefixes with the same
4805 * namespace. However, an implementation may include information about
4806 * the original prefix in its representation of nodes; in this case, an
4807 * implementation can ensure that the returned string is always the same
4808 * as the QName used in the XML source. If the argument it omitted it
4809 * defaults to the context node.
4810 * Libxml keep the original prefix so the "real qualified name" used is
4811 * returned.
4812 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004813static void
Owen Taylor3473f882001-02-23 17:55:21 +00004814xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4815 xmlXPathObjectPtr cur;
4816
4817 if (nargs == 0) {
4818 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4819 nargs = 1;
4820 }
4821
4822 CHECK_ARITY(1);
4823 if ((ctxt->value == NULL) ||
4824 ((ctxt->value->type != XPATH_NODESET) &&
4825 (ctxt->value->type != XPATH_XSLT_TREE)))
4826 XP_ERROR(XPATH_INVALID_TYPE);
4827 cur = valuePop(ctxt);
4828
Daniel Veillard911f49a2001-04-07 15:39:35 +00004829 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004830 valuePush(ctxt, xmlXPathNewCString(""));
4831 } else {
4832 int i = 0; /* Should be first in document order !!!!! */
4833
4834 switch (cur->nodesetval->nodeTab[i]->type) {
4835 case XML_ELEMENT_NODE:
4836 case XML_ATTRIBUTE_NODE:
4837 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4838 valuePush(ctxt, xmlXPathNewString(
4839 cur->nodesetval->nodeTab[i]->name));
4840
4841 else {
4842 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004843 snprintf(name, sizeof(name), "%s:%s",
4844 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4845 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004846 name[sizeof(name) - 1] = 0;
4847 valuePush(ctxt, xmlXPathNewCString(name));
4848 }
4849 break;
4850 default:
4851 valuePush(ctxt,
4852 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4853 xmlXPathLocalNameFunction(ctxt, 1);
4854 }
4855 }
4856 xmlXPathFreeObject(cur);
4857}
4858
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004859
4860/**
Owen Taylor3473f882001-02-23 17:55:21 +00004861 * xmlXPathStringFunction:
4862 * @ctxt: the XPath Parser context
4863 * @nargs: the number of arguments
4864 *
4865 * Implement the string() XPath function
4866 * string string(object?)
4867 * he string function converts an object to a string as follows:
4868 * - A node-set is converted to a string by returning the value of
4869 * the node in the node-set that is first in document order.
4870 * If the node-set is empty, an empty string is returned.
4871 * - A number is converted to a string as follows
4872 * + NaN is converted to the string NaN
4873 * + positive zero is converted to the string 0
4874 * + negative zero is converted to the string 0
4875 * + positive infinity is converted to the string Infinity
4876 * + negative infinity is converted to the string -Infinity
4877 * + if the number is an integer, the number is represented in
4878 * decimal form as a Number with no decimal point and no leading
4879 * zeros, preceded by a minus sign (-) if the number is negative
4880 * + otherwise, the number is represented in decimal form as a
4881 * Number including a decimal point with at least one digit
4882 * before the decimal point and at least one digit after the
4883 * decimal point, preceded by a minus sign (-) if the number
4884 * is negative; there must be no leading zeros before the decimal
4885 * point apart possibly from the one required digit immediatelyi
4886 * before the decimal point; beyond the one required digit
4887 * after the decimal point there must be as many, but only as
4888 * many, more digits as are needed to uniquely distinguish the
4889 * number from all other IEEE 754 numeric values.
4890 * - The boolean false value is converted to the string false.
4891 * The boolean true value is converted to the string true.
4892 *
4893 * If the argument is omitted, it defaults to a node-set with the
4894 * context node as its only member.
4895 */
4896void
4897xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4898 xmlXPathObjectPtr cur;
4899
4900 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004901 valuePush(ctxt,
4902 xmlXPathWrapString(
4903 xmlXPathCastNodeToString(ctxt->context->node)));
4904 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004905 }
4906
4907 CHECK_ARITY(1);
4908 cur = valuePop(ctxt);
4909 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004910 cur = xmlXPathConvertString(cur);
4911 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004912}
4913
4914/**
4915 * xmlXPathStringLengthFunction:
4916 * @ctxt: the XPath Parser context
4917 * @nargs: the number of arguments
4918 *
4919 * Implement the string-length() XPath function
4920 * number string-length(string?)
4921 * The string-length returns the number of characters in the string
4922 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4923 * the context node converted to a string, in other words the value
4924 * of the context node.
4925 */
4926void
4927xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4928 xmlXPathObjectPtr cur;
4929
4930 if (nargs == 0) {
4931 if (ctxt->context->node == NULL) {
4932 valuePush(ctxt, xmlXPathNewFloat(0));
4933 } else {
4934 xmlChar *content;
4935
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004936 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004937 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004938 xmlFree(content);
4939 }
4940 return;
4941 }
4942 CHECK_ARITY(1);
4943 CAST_TO_STRING;
4944 CHECK_TYPE(XPATH_STRING);
4945 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004946 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004947 xmlXPathFreeObject(cur);
4948}
4949
4950/**
4951 * xmlXPathConcatFunction:
4952 * @ctxt: the XPath Parser context
4953 * @nargs: the number of arguments
4954 *
4955 * Implement the concat() XPath function
4956 * string concat(string, string, string*)
4957 * The concat function returns the concatenation of its arguments.
4958 */
4959void
4960xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4961 xmlXPathObjectPtr cur, newobj;
4962 xmlChar *tmp;
4963
4964 if (nargs < 2) {
4965 CHECK_ARITY(2);
4966 }
4967
4968 CAST_TO_STRING;
4969 cur = valuePop(ctxt);
4970 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4971 xmlXPathFreeObject(cur);
4972 return;
4973 }
4974 nargs--;
4975
4976 while (nargs > 0) {
4977 CAST_TO_STRING;
4978 newobj = valuePop(ctxt);
4979 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4980 xmlXPathFreeObject(newobj);
4981 xmlXPathFreeObject(cur);
4982 XP_ERROR(XPATH_INVALID_TYPE);
4983 }
4984 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4985 newobj->stringval = cur->stringval;
4986 cur->stringval = tmp;
4987
4988 xmlXPathFreeObject(newobj);
4989 nargs--;
4990 }
4991 valuePush(ctxt, cur);
4992}
4993
4994/**
4995 * xmlXPathContainsFunction:
4996 * @ctxt: the XPath Parser context
4997 * @nargs: the number of arguments
4998 *
4999 * Implement the contains() XPath function
5000 * boolean contains(string, string)
5001 * The contains function returns true if the first argument string
5002 * contains the second argument string, and otherwise returns false.
5003 */
5004void
5005xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5006 xmlXPathObjectPtr hay, needle;
5007
5008 CHECK_ARITY(2);
5009 CAST_TO_STRING;
5010 CHECK_TYPE(XPATH_STRING);
5011 needle = valuePop(ctxt);
5012 CAST_TO_STRING;
5013 hay = valuePop(ctxt);
5014 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5015 xmlXPathFreeObject(hay);
5016 xmlXPathFreeObject(needle);
5017 XP_ERROR(XPATH_INVALID_TYPE);
5018 }
5019 if (xmlStrstr(hay->stringval, needle->stringval))
5020 valuePush(ctxt, xmlXPathNewBoolean(1));
5021 else
5022 valuePush(ctxt, xmlXPathNewBoolean(0));
5023 xmlXPathFreeObject(hay);
5024 xmlXPathFreeObject(needle);
5025}
5026
5027/**
5028 * xmlXPathStartsWithFunction:
5029 * @ctxt: the XPath Parser context
5030 * @nargs: the number of arguments
5031 *
5032 * Implement the starts-with() XPath function
5033 * boolean starts-with(string, string)
5034 * The starts-with function returns true if the first argument string
5035 * starts with the second argument string, and otherwise returns false.
5036 */
5037void
5038xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5039 xmlXPathObjectPtr hay, needle;
5040 int n;
5041
5042 CHECK_ARITY(2);
5043 CAST_TO_STRING;
5044 CHECK_TYPE(XPATH_STRING);
5045 needle = valuePop(ctxt);
5046 CAST_TO_STRING;
5047 hay = valuePop(ctxt);
5048 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5049 xmlXPathFreeObject(hay);
5050 xmlXPathFreeObject(needle);
5051 XP_ERROR(XPATH_INVALID_TYPE);
5052 }
5053 n = xmlStrlen(needle->stringval);
5054 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5055 valuePush(ctxt, xmlXPathNewBoolean(0));
5056 else
5057 valuePush(ctxt, xmlXPathNewBoolean(1));
5058 xmlXPathFreeObject(hay);
5059 xmlXPathFreeObject(needle);
5060}
5061
5062/**
5063 * xmlXPathSubstringFunction:
5064 * @ctxt: the XPath Parser context
5065 * @nargs: the number of arguments
5066 *
5067 * Implement the substring() XPath function
5068 * string substring(string, number, number?)
5069 * The substring function returns the substring of the first argument
5070 * starting at the position specified in the second argument with
5071 * length specified in the third argument. For example,
5072 * substring("12345",2,3) returns "234". If the third argument is not
5073 * specified, it returns the substring starting at the position specified
5074 * in the second argument and continuing to the end of the string. For
5075 * example, substring("12345",2) returns "2345". More precisely, each
5076 * character in the string (see [3.6 Strings]) is considered to have a
5077 * numeric position: the position of the first character is 1, the position
5078 * of the second character is 2 and so on. The returned substring contains
5079 * those characters for which the position of the character is greater than
5080 * or equal to the second argument and, if the third argument is specified,
5081 * less than the sum of the second and third arguments; the comparisons
5082 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5083 * - substring("12345", 1.5, 2.6) returns "234"
5084 * - substring("12345", 0, 3) returns "12"
5085 * - substring("12345", 0 div 0, 3) returns ""
5086 * - substring("12345", 1, 0 div 0) returns ""
5087 * - substring("12345", -42, 1 div 0) returns "12345"
5088 * - substring("12345", -1 div 0, 1 div 0) returns ""
5089 */
5090void
5091xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5092 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005093 double le=0, in;
5094 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005095 xmlChar *ret;
5096
Owen Taylor3473f882001-02-23 17:55:21 +00005097 if (nargs < 2) {
5098 CHECK_ARITY(2);
5099 }
5100 if (nargs > 3) {
5101 CHECK_ARITY(3);
5102 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005103 /*
5104 * take care of possible last (position) argument
5105 */
Owen Taylor3473f882001-02-23 17:55:21 +00005106 if (nargs == 3) {
5107 CAST_TO_NUMBER;
5108 CHECK_TYPE(XPATH_NUMBER);
5109 len = valuePop(ctxt);
5110 le = len->floatval;
5111 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005112 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005113
Owen Taylor3473f882001-02-23 17:55:21 +00005114 CAST_TO_NUMBER;
5115 CHECK_TYPE(XPATH_NUMBER);
5116 start = valuePop(ctxt);
5117 in = start->floatval;
5118 xmlXPathFreeObject(start);
5119 CAST_TO_STRING;
5120 CHECK_TYPE(XPATH_STRING);
5121 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005122 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005123
Daniel Veillard97ac1312001-05-30 19:14:17 +00005124 /*
5125 * If last pos not present, calculate last position
5126 */
5127 if (nargs != 3)
5128 le = m;
5129
5130 /*
5131 * To meet our requirements, initial index calculations
5132 * must be done before we convert to integer format
5133 *
5134 * First we normalize indices
5135 */
5136 in -= 1.0;
5137 le += in;
5138 if (in < 0.0)
5139 in = 0.0;
5140 if (le > (double)m)
5141 le = (double)m;
5142
5143 /*
5144 * Now we go to integer form, rounding up
5145 */
Owen Taylor3473f882001-02-23 17:55:21 +00005146 i = (int) in;
5147 if (((double)i) != in) i++;
5148
Owen Taylor3473f882001-02-23 17:55:21 +00005149 l = (int) le;
5150 if (((double)l) != le) l++;
5151
Daniel Veillard97ac1312001-05-30 19:14:17 +00005152 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005153
5154 /* number of chars to copy */
5155 l -= i;
5156
Daniel Veillard97ac1312001-05-30 19:14:17 +00005157 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005158 if (ret == NULL)
5159 valuePush(ctxt, xmlXPathNewCString(""));
5160 else {
5161 valuePush(ctxt, xmlXPathNewString(ret));
5162 xmlFree(ret);
5163 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005164
Owen Taylor3473f882001-02-23 17:55:21 +00005165 xmlXPathFreeObject(str);
5166}
5167
5168/**
5169 * xmlXPathSubstringBeforeFunction:
5170 * @ctxt: the XPath Parser context
5171 * @nargs: the number of arguments
5172 *
5173 * Implement the substring-before() XPath function
5174 * string substring-before(string, string)
5175 * The substring-before function returns the substring of the first
5176 * argument string that precedes the first occurrence of the second
5177 * argument string in the first argument string, or the empty string
5178 * if the first argument string does not contain the second argument
5179 * string. For example, substring-before("1999/04/01","/") returns 1999.
5180 */
5181void
5182xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5183 xmlXPathObjectPtr str;
5184 xmlXPathObjectPtr find;
5185 xmlBufferPtr target;
5186 const xmlChar *point;
5187 int offset;
5188
5189 CHECK_ARITY(2);
5190 CAST_TO_STRING;
5191 find = valuePop(ctxt);
5192 CAST_TO_STRING;
5193 str = valuePop(ctxt);
5194
5195 target = xmlBufferCreate();
5196 if (target) {
5197 point = xmlStrstr(str->stringval, find->stringval);
5198 if (point) {
5199 offset = (int)(point - str->stringval);
5200 xmlBufferAdd(target, str->stringval, offset);
5201 }
5202 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5203 xmlBufferFree(target);
5204 }
5205
5206 xmlXPathFreeObject(str);
5207 xmlXPathFreeObject(find);
5208}
5209
5210/**
5211 * xmlXPathSubstringAfterFunction:
5212 * @ctxt: the XPath Parser context
5213 * @nargs: the number of arguments
5214 *
5215 * Implement the substring-after() XPath function
5216 * string substring-after(string, string)
5217 * The substring-after function returns the substring of the first
5218 * argument string that follows the first occurrence of the second
5219 * argument string in the first argument string, or the empty stringi
5220 * if the first argument string does not contain the second argument
5221 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5222 * and substring-after("1999/04/01","19") returns 99/04/01.
5223 */
5224void
5225xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5226 xmlXPathObjectPtr str;
5227 xmlXPathObjectPtr find;
5228 xmlBufferPtr target;
5229 const xmlChar *point;
5230 int offset;
5231
5232 CHECK_ARITY(2);
5233 CAST_TO_STRING;
5234 find = valuePop(ctxt);
5235 CAST_TO_STRING;
5236 str = valuePop(ctxt);
5237
5238 target = xmlBufferCreate();
5239 if (target) {
5240 point = xmlStrstr(str->stringval, find->stringval);
5241 if (point) {
5242 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5243 xmlBufferAdd(target, &str->stringval[offset],
5244 xmlStrlen(str->stringval) - offset);
5245 }
5246 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5247 xmlBufferFree(target);
5248 }
5249
5250 xmlXPathFreeObject(str);
5251 xmlXPathFreeObject(find);
5252}
5253
5254/**
5255 * xmlXPathNormalizeFunction:
5256 * @ctxt: the XPath Parser context
5257 * @nargs: the number of arguments
5258 *
5259 * Implement the normalize-space() XPath function
5260 * string normalize-space(string?)
5261 * The normalize-space function returns the argument string with white
5262 * space normalized by stripping leading and trailing whitespace
5263 * and replacing sequences of whitespace characters by a single
5264 * space. Whitespace characters are the same allowed by the S production
5265 * in XML. If the argument is omitted, it defaults to the context
5266 * node converted to a string, in other words the value of the context node.
5267 */
5268void
5269xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5270 xmlXPathObjectPtr obj = NULL;
5271 xmlChar *source = NULL;
5272 xmlBufferPtr target;
5273 xmlChar blank;
5274
5275 if (nargs == 0) {
5276 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005277 valuePush(ctxt,
5278 xmlXPathWrapString(
5279 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005280 nargs = 1;
5281 }
5282
5283 CHECK_ARITY(1);
5284 CAST_TO_STRING;
5285 CHECK_TYPE(XPATH_STRING);
5286 obj = valuePop(ctxt);
5287 source = obj->stringval;
5288
5289 target = xmlBufferCreate();
5290 if (target && source) {
5291
5292 /* Skip leading whitespaces */
5293 while (IS_BLANK(*source))
5294 source++;
5295
5296 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5297 blank = 0;
5298 while (*source) {
5299 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005300 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005301 } else {
5302 if (blank) {
5303 xmlBufferAdd(target, &blank, 1);
5304 blank = 0;
5305 }
5306 xmlBufferAdd(target, source, 1);
5307 }
5308 source++;
5309 }
5310
5311 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5312 xmlBufferFree(target);
5313 }
5314 xmlXPathFreeObject(obj);
5315}
5316
5317/**
5318 * xmlXPathTranslateFunction:
5319 * @ctxt: the XPath Parser context
5320 * @nargs: the number of arguments
5321 *
5322 * Implement the translate() XPath function
5323 * string translate(string, string, string)
5324 * The translate function returns the first argument string with
5325 * occurrences of characters in the second argument string replaced
5326 * by the character at the corresponding position in the third argument
5327 * string. For example, translate("bar","abc","ABC") returns the string
5328 * BAr. If there is a character in the second argument string with no
5329 * character at a corresponding position in the third argument string
5330 * (because the second argument string is longer than the third argument
5331 * string), then occurrences of that character in the first argument
5332 * string are removed. For example, translate("--aaa--","abc-","ABC")
5333 * returns "AAA". If a character occurs more than once in second
5334 * argument string, then the first occurrence determines the replacement
5335 * character. If the third argument string is longer than the second
5336 * argument string, then excess characters are ignored.
5337 */
5338void
5339xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005340 xmlXPathObjectPtr str;
5341 xmlXPathObjectPtr from;
5342 xmlXPathObjectPtr to;
5343 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005344 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005345 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005346 xmlChar *point;
5347 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005348
Daniel Veillarde043ee12001-04-16 14:08:07 +00005349 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005350
Daniel Veillarde043ee12001-04-16 14:08:07 +00005351 CAST_TO_STRING;
5352 to = valuePop(ctxt);
5353 CAST_TO_STRING;
5354 from = valuePop(ctxt);
5355 CAST_TO_STRING;
5356 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005357
Daniel Veillarde043ee12001-04-16 14:08:07 +00005358 target = xmlBufferCreate();
5359 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005360 max = xmlUTF8Strlen(to->stringval);
5361 for (cptr = str->stringval; (ch=*cptr); ) {
5362 offset = xmlUTF8Strloc(from->stringval, cptr);
5363 if (offset >= 0) {
5364 if (offset < max) {
5365 point = xmlUTF8Strpos(to->stringval, offset);
5366 if (point)
5367 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5368 }
5369 } else
5370 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5371
5372 /* Step to next character in input */
5373 cptr++;
5374 if ( ch & 0x80 ) {
5375 /* if not simple ascii, verify proper format */
5376 if ( (ch & 0xc0) != 0xc0 ) {
5377 xmlGenericError(xmlGenericErrorContext,
5378 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5379 break;
5380 }
5381 /* then skip over remaining bytes for this char */
5382 while ( (ch <<= 1) & 0x80 )
5383 if ( (*cptr++ & 0xc0) != 0x80 ) {
5384 xmlGenericError(xmlGenericErrorContext,
5385 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5386 break;
5387 }
5388 if (ch & 0x80) /* must have had error encountered */
5389 break;
5390 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005391 }
Owen Taylor3473f882001-02-23 17:55:21 +00005392 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005393 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5394 xmlBufferFree(target);
5395 xmlXPathFreeObject(str);
5396 xmlXPathFreeObject(from);
5397 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005398}
5399
5400/**
5401 * xmlXPathBooleanFunction:
5402 * @ctxt: the XPath Parser context
5403 * @nargs: the number of arguments
5404 *
5405 * Implement the boolean() XPath function
5406 * boolean boolean(object)
5407 * he boolean function converts its argument to a boolean as follows:
5408 * - a number is true if and only if it is neither positive or
5409 * negative zero nor NaN
5410 * - a node-set is true if and only if it is non-empty
5411 * - a string is true if and only if its length is non-zero
5412 */
5413void
5414xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5415 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005416
5417 CHECK_ARITY(1);
5418 cur = valuePop(ctxt);
5419 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005420 cur = xmlXPathConvertBoolean(cur);
5421 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005422}
5423
5424/**
5425 * xmlXPathNotFunction:
5426 * @ctxt: the XPath Parser context
5427 * @nargs: the number of arguments
5428 *
5429 * Implement the not() XPath function
5430 * boolean not(boolean)
5431 * The not function returns true if its argument is false,
5432 * and false otherwise.
5433 */
5434void
5435xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5436 CHECK_ARITY(1);
5437 CAST_TO_BOOLEAN;
5438 CHECK_TYPE(XPATH_BOOLEAN);
5439 ctxt->value->boolval = ! ctxt->value->boolval;
5440}
5441
5442/**
5443 * xmlXPathTrueFunction:
5444 * @ctxt: the XPath Parser context
5445 * @nargs: the number of arguments
5446 *
5447 * Implement the true() XPath function
5448 * boolean true()
5449 */
5450void
5451xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5452 CHECK_ARITY(0);
5453 valuePush(ctxt, xmlXPathNewBoolean(1));
5454}
5455
5456/**
5457 * xmlXPathFalseFunction:
5458 * @ctxt: the XPath Parser context
5459 * @nargs: the number of arguments
5460 *
5461 * Implement the false() XPath function
5462 * boolean false()
5463 */
5464void
5465xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5466 CHECK_ARITY(0);
5467 valuePush(ctxt, xmlXPathNewBoolean(0));
5468}
5469
5470/**
5471 * xmlXPathLangFunction:
5472 * @ctxt: the XPath Parser context
5473 * @nargs: the number of arguments
5474 *
5475 * Implement the lang() XPath function
5476 * boolean lang(string)
5477 * The lang function returns true or false depending on whether the
5478 * language of the context node as specified by xml:lang attributes
5479 * is the same as or is a sublanguage of the language specified by
5480 * the argument string. The language of the context node is determined
5481 * by the value of the xml:lang attribute on the context node, or, if
5482 * the context node has no xml:lang attribute, by the value of the
5483 * xml:lang attribute on the nearest ancestor of the context node that
5484 * has an xml:lang attribute. If there is no such attribute, then lang
5485 * returns false. If there is such an attribute, then lang returns
5486 * true if the attribute value is equal to the argument ignoring case,
5487 * or if there is some suffix starting with - such that the attribute
5488 * value is equal to the argument ignoring that suffix of the attribute
5489 * value and ignoring case.
5490 */
5491void
5492xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5493 xmlXPathObjectPtr val;
5494 const xmlChar *theLang;
5495 const xmlChar *lang;
5496 int ret = 0;
5497 int i;
5498
5499 CHECK_ARITY(1);
5500 CAST_TO_STRING;
5501 CHECK_TYPE(XPATH_STRING);
5502 val = valuePop(ctxt);
5503 lang = val->stringval;
5504 theLang = xmlNodeGetLang(ctxt->context->node);
5505 if ((theLang != NULL) && (lang != NULL)) {
5506 for (i = 0;lang[i] != 0;i++)
5507 if (toupper(lang[i]) != toupper(theLang[i]))
5508 goto not_equal;
5509 ret = 1;
5510 }
5511not_equal:
5512 xmlXPathFreeObject(val);
5513 valuePush(ctxt, xmlXPathNewBoolean(ret));
5514}
5515
5516/**
5517 * xmlXPathNumberFunction:
5518 * @ctxt: the XPath Parser context
5519 * @nargs: the number of arguments
5520 *
5521 * Implement the number() XPath function
5522 * number number(object?)
5523 */
5524void
5525xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5526 xmlXPathObjectPtr cur;
5527 double res;
5528
5529 if (nargs == 0) {
5530 if (ctxt->context->node == NULL) {
5531 valuePush(ctxt, xmlXPathNewFloat(0.0));
5532 } else {
5533 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
5534
5535 res = xmlXPathStringEvalNumber(content);
5536 valuePush(ctxt, xmlXPathNewFloat(res));
5537 xmlFree(content);
5538 }
5539 return;
5540 }
5541
5542 CHECK_ARITY(1);
5543 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005544 cur = xmlXPathConvertNumber(cur);
5545 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005546}
5547
5548/**
5549 * xmlXPathSumFunction:
5550 * @ctxt: the XPath Parser context
5551 * @nargs: the number of arguments
5552 *
5553 * Implement the sum() XPath function
5554 * number sum(node-set)
5555 * The sum function returns the sum of the values of the nodes in
5556 * the argument node-set.
5557 */
5558void
5559xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5560 xmlXPathObjectPtr cur;
5561 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005562 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00005563
5564 CHECK_ARITY(1);
5565 if ((ctxt->value == NULL) ||
5566 ((ctxt->value->type != XPATH_NODESET) &&
5567 (ctxt->value->type != XPATH_XSLT_TREE)))
5568 XP_ERROR(XPATH_INVALID_TYPE);
5569 cur = valuePop(ctxt);
5570
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005571 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005572 valuePush(ctxt, xmlXPathNewFloat(0.0));
5573 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005574 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
5575 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00005576 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005577 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00005578 }
5579 xmlXPathFreeObject(cur);
5580}
5581
5582/**
5583 * xmlXPathFloorFunction:
5584 * @ctxt: the XPath Parser context
5585 * @nargs: the number of arguments
5586 *
5587 * Implement the floor() XPath function
5588 * number floor(number)
5589 * The floor function returns the largest (closest to positive infinity)
5590 * number that is not greater than the argument and that is an integer.
5591 */
5592void
5593xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5594 CHECK_ARITY(1);
5595 CAST_TO_NUMBER;
5596 CHECK_TYPE(XPATH_NUMBER);
5597#if 0
5598 ctxt->value->floatval = floor(ctxt->value->floatval);
5599#else
5600 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5601 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5602#endif
5603}
5604
5605/**
5606 * xmlXPathCeilingFunction:
5607 * @ctxt: the XPath Parser context
5608 * @nargs: the number of arguments
5609 *
5610 * Implement the ceiling() XPath function
5611 * number ceiling(number)
5612 * The ceiling function returns the smallest (closest to negative infinity)
5613 * number that is not less than the argument and that is an integer.
5614 */
5615void
5616xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5617 double f;
5618
5619 CHECK_ARITY(1);
5620 CAST_TO_NUMBER;
5621 CHECK_TYPE(XPATH_NUMBER);
5622
5623#if 0
5624 ctxt->value->floatval = ceil(ctxt->value->floatval);
5625#else
5626 f = (double)((int) ctxt->value->floatval);
5627 if (f != ctxt->value->floatval)
5628 ctxt->value->floatval = f + 1;
5629#endif
5630}
5631
5632/**
5633 * xmlXPathRoundFunction:
5634 * @ctxt: the XPath Parser context
5635 * @nargs: the number of arguments
5636 *
5637 * Implement the round() XPath function
5638 * number round(number)
5639 * The round function returns the number that is closest to the
5640 * argument and that is an integer. If there are two such numbers,
5641 * then the one that is even is returned.
5642 */
5643void
5644xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5645 double f;
5646
5647 CHECK_ARITY(1);
5648 CAST_TO_NUMBER;
5649 CHECK_TYPE(XPATH_NUMBER);
5650
5651 if ((ctxt->value->floatval == xmlXPathNAN) ||
5652 (ctxt->value->floatval == xmlXPathPINF) ||
5653 (ctxt->value->floatval == xmlXPathNINF) ||
5654 (ctxt->value->floatval == 0.0))
5655 return;
5656
5657#if 0
5658 f = floor(ctxt->value->floatval);
5659#else
5660 f = (double)((int) ctxt->value->floatval);
5661#endif
5662 if (ctxt->value->floatval < f + 0.5)
5663 ctxt->value->floatval = f;
5664 else
5665 ctxt->value->floatval = f + 1;
5666}
5667
5668/************************************************************************
5669 * *
5670 * The Parser *
5671 * *
5672 ************************************************************************/
5673
5674/*
5675 * a couple of forward declarations since we use a recursive call based
5676 * implementation.
5677 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005678static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005679static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005680static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005681#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005682static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5683#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005684#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005685static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005686#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005687static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5688 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005689
5690/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005691 * xmlXPathCurrentChar:
5692 * @ctxt: the XPath parser context
5693 * @cur: pointer to the beginning of the char
5694 * @len: pointer to the length of the char read
5695 *
5696 * The current char value, if using UTF-8 this may actaully span multiple
5697 * bytes in the input buffer.
5698 *
5699 * Returns the current char value and its lenght
5700 */
5701
5702static int
5703xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5704 unsigned char c;
5705 unsigned int val;
5706 const xmlChar *cur;
5707
5708 if (ctxt == NULL)
5709 return(0);
5710 cur = ctxt->cur;
5711
5712 /*
5713 * We are supposed to handle UTF8, check it's valid
5714 * From rfc2044: encoding of the Unicode values on UTF-8:
5715 *
5716 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5717 * 0000 0000-0000 007F 0xxxxxxx
5718 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5719 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5720 *
5721 * Check for the 0x110000 limit too
5722 */
5723 c = *cur;
5724 if (c & 0x80) {
5725 if ((cur[1] & 0xc0) != 0x80)
5726 goto encoding_error;
5727 if ((c & 0xe0) == 0xe0) {
5728
5729 if ((cur[2] & 0xc0) != 0x80)
5730 goto encoding_error;
5731 if ((c & 0xf0) == 0xf0) {
5732 if (((c & 0xf8) != 0xf0) ||
5733 ((cur[3] & 0xc0) != 0x80))
5734 goto encoding_error;
5735 /* 4-byte code */
5736 *len = 4;
5737 val = (cur[0] & 0x7) << 18;
5738 val |= (cur[1] & 0x3f) << 12;
5739 val |= (cur[2] & 0x3f) << 6;
5740 val |= cur[3] & 0x3f;
5741 } else {
5742 /* 3-byte code */
5743 *len = 3;
5744 val = (cur[0] & 0xf) << 12;
5745 val |= (cur[1] & 0x3f) << 6;
5746 val |= cur[2] & 0x3f;
5747 }
5748 } else {
5749 /* 2-byte code */
5750 *len = 2;
5751 val = (cur[0] & 0x1f) << 6;
5752 val |= cur[1] & 0x3f;
5753 }
5754 if (!IS_CHAR(val)) {
5755 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5756 }
5757 return(val);
5758 } else {
5759 /* 1-byte code */
5760 *len = 1;
5761 return((int) *cur);
5762 }
5763encoding_error:
5764 /*
5765 * If we detect an UTF8 error that probably mean that the
5766 * input encoding didn't get properly advertized in the
5767 * declaration header. Report the error and switch the encoding
5768 * to ISO-Latin-1 (if you don't like this policy, just declare the
5769 * encoding !)
5770 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00005771 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00005772 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005773}
5774
5775/**
Owen Taylor3473f882001-02-23 17:55:21 +00005776 * xmlXPathParseNCName:
5777 * @ctxt: the XPath Parser context
5778 *
5779 * parse an XML namespace non qualified name.
5780 *
5781 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5782 *
5783 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5784 * CombiningChar | Extender
5785 *
5786 * Returns the namespace name or NULL
5787 */
5788
5789xmlChar *
5790xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005791 const xmlChar *in;
5792 xmlChar *ret;
5793 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005794
Daniel Veillard2156a562001-04-28 12:24:34 +00005795 /*
5796 * Accelerator for simple ASCII names
5797 */
5798 in = ctxt->cur;
5799 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5800 ((*in >= 0x41) && (*in <= 0x5A)) ||
5801 (*in == '_')) {
5802 in++;
5803 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5804 ((*in >= 0x41) && (*in <= 0x5A)) ||
5805 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00005806 (*in == '_') || (*in == '.') ||
5807 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00005808 in++;
5809 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5810 (*in == '[') || (*in == ']') || (*in == ':') ||
5811 (*in == '@') || (*in == '*')) {
5812 count = in - ctxt->cur;
5813 if (count == 0)
5814 return(NULL);
5815 ret = xmlStrndup(ctxt->cur, count);
5816 ctxt->cur = in;
5817 return(ret);
5818 }
5819 }
5820 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005821}
5822
Daniel Veillard2156a562001-04-28 12:24:34 +00005823
Owen Taylor3473f882001-02-23 17:55:21 +00005824/**
5825 * xmlXPathParseQName:
5826 * @ctxt: the XPath Parser context
5827 * @prefix: a xmlChar **
5828 *
5829 * parse an XML qualified name
5830 *
5831 * [NS 5] QName ::= (Prefix ':')? LocalPart
5832 *
5833 * [NS 6] Prefix ::= NCName
5834 *
5835 * [NS 7] LocalPart ::= NCName
5836 *
5837 * Returns the function returns the local part, and prefix is updated
5838 * to get the Prefix if any.
5839 */
5840
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005841static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005842xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5843 xmlChar *ret = NULL;
5844
5845 *prefix = NULL;
5846 ret = xmlXPathParseNCName(ctxt);
5847 if (CUR == ':') {
5848 *prefix = ret;
5849 NEXT;
5850 ret = xmlXPathParseNCName(ctxt);
5851 }
5852 return(ret);
5853}
5854
5855/**
5856 * xmlXPathParseName:
5857 * @ctxt: the XPath Parser context
5858 *
5859 * parse an XML name
5860 *
5861 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5862 * CombiningChar | Extender
5863 *
5864 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5865 *
5866 * Returns the namespace name or NULL
5867 */
5868
5869xmlChar *
5870xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005871 const xmlChar *in;
5872 xmlChar *ret;
5873 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005874
Daniel Veillard61d80a22001-04-27 17:13:01 +00005875 /*
5876 * Accelerator for simple ASCII names
5877 */
5878 in = ctxt->cur;
5879 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5880 ((*in >= 0x41) && (*in <= 0x5A)) ||
5881 (*in == '_') || (*in == ':')) {
5882 in++;
5883 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5884 ((*in >= 0x41) && (*in <= 0x5A)) ||
5885 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00005886 (*in == '_') || (*in == '-') ||
5887 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00005888 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00005889 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005890 count = in - ctxt->cur;
5891 ret = xmlStrndup(ctxt->cur, count);
5892 ctxt->cur = in;
5893 return(ret);
5894 }
5895 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005896 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005897}
5898
Daniel Veillard61d80a22001-04-27 17:13:01 +00005899static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005900xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005901 xmlChar buf[XML_MAX_NAMELEN + 5];
5902 int len = 0, l;
5903 int c;
5904
5905 /*
5906 * Handler for more complex cases
5907 */
5908 c = CUR_CHAR(l);
5909 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005910 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5911 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005912 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005913 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005914 return(NULL);
5915 }
5916
5917 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5918 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5919 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005920 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005921 (IS_COMBINING(c)) ||
5922 (IS_EXTENDER(c)))) {
5923 COPY_BUF(l,buf,len,c);
5924 NEXTL(l);
5925 c = CUR_CHAR(l);
5926 if (len >= XML_MAX_NAMELEN) {
5927 /*
5928 * Okay someone managed to make a huge name, so he's ready to pay
5929 * for the processing speed.
5930 */
5931 xmlChar *buffer;
5932 int max = len * 2;
5933
5934 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5935 if (buffer == NULL) {
5936 XP_ERROR0(XPATH_MEMORY_ERROR);
5937 }
5938 memcpy(buffer, buf, len);
5939 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5940 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005941 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005942 (IS_COMBINING(c)) ||
5943 (IS_EXTENDER(c))) {
5944 if (len + 10 > max) {
5945 max *= 2;
5946 buffer = (xmlChar *) xmlRealloc(buffer,
5947 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00005948 if (buffer == NULL) {
5949 XP_ERROR0(XPATH_MEMORY_ERROR);
5950 }
5951 }
5952 COPY_BUF(l,buffer,len,c);
5953 NEXTL(l);
5954 c = CUR_CHAR(l);
5955 }
5956 buffer[len] = 0;
5957 return(buffer);
5958 }
5959 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005960 if (len == 0)
5961 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005962 return(xmlStrndup(buf, len));
5963}
Owen Taylor3473f882001-02-23 17:55:21 +00005964/**
5965 * xmlXPathStringEvalNumber:
5966 * @str: A string to scan
5967 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005968 * [30a] Float ::= Number ('e' Digits?)?
5969 *
Owen Taylor3473f882001-02-23 17:55:21 +00005970 * [30] Number ::= Digits ('.' Digits?)?
5971 * | '.' Digits
5972 * [31] Digits ::= [0-9]+
5973 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005974 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005975 * In complement of the Number expression, this function also handles
5976 * negative values : '-' Number.
5977 *
5978 * Returns the double value.
5979 */
5980double
5981xmlXPathStringEvalNumber(const xmlChar *str) {
5982 const xmlChar *cur = str;
5983 double ret = 0.0;
5984 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005985 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005986 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005987 int exponent = 0;
5988 int is_exponent_negative = 0;
5989
Owen Taylor3473f882001-02-23 17:55:21 +00005990 while (IS_BLANK(*cur)) cur++;
5991 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5992 return(xmlXPathNAN);
5993 }
5994 if (*cur == '-') {
5995 isneg = 1;
5996 cur++;
5997 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005998 /*
5999 * tmp is a workaroudn against a gcc compiler bug
6000 */
Owen Taylor3473f882001-02-23 17:55:21 +00006001 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006002 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006003 ok = 1;
6004 cur++;
6005 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006006 ret = (double) tmp;
6007
Owen Taylor3473f882001-02-23 17:55:21 +00006008 if (*cur == '.') {
6009 cur++;
6010 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6011 return(xmlXPathNAN);
6012 }
6013 while ((*cur >= '0') && (*cur <= '9')) {
6014 mult /= 10;
6015 ret = ret + (*cur - '0') * mult;
6016 cur++;
6017 }
6018 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006019 if ((*cur == 'e') || (*cur == 'E')) {
6020 cur++;
6021 if (*cur == '-') {
6022 is_exponent_negative = 1;
6023 cur++;
6024 }
6025 while ((*cur >= '0') && (*cur <= '9')) {
6026 exponent = exponent * 10 + (*cur - '0');
6027 cur++;
6028 }
6029 }
Owen Taylor3473f882001-02-23 17:55:21 +00006030 while (IS_BLANK(*cur)) cur++;
6031 if (*cur != 0) return(xmlXPathNAN);
6032 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006033 if (is_exponent_negative) exponent = -exponent;
6034 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006035 return(ret);
6036}
6037
6038/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006039 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006040 * @ctxt: the XPath Parser context
6041 *
6042 * [30] Number ::= Digits ('.' Digits?)?
6043 * | '.' Digits
6044 * [31] Digits ::= [0-9]+
6045 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006046 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006047 *
6048 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006049static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006050xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6051{
Owen Taylor3473f882001-02-23 17:55:21 +00006052 double ret = 0.0;
6053 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006054 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006055 int exponent = 0;
6056 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006057
6058 CHECK_ERROR;
6059 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6060 XP_ERROR(XPATH_NUMBER_ERROR);
6061 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006062 /*
6063 * Try to work around a gcc optimizer bug
6064 */
Owen Taylor3473f882001-02-23 17:55:21 +00006065 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006066 tmp = tmp * 10 + (CUR - '0');
6067 ok = 1;
6068 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006069 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006070 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006071 if (CUR == '.') {
6072 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006073 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6074 XP_ERROR(XPATH_NUMBER_ERROR);
6075 }
6076 while ((CUR >= '0') && (CUR <= '9')) {
6077 mult /= 10;
6078 ret = ret + (CUR - '0') * mult;
6079 NEXT;
6080 }
Owen Taylor3473f882001-02-23 17:55:21 +00006081 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006082 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006083 NEXT;
6084 if (CUR == '-') {
6085 is_exponent_negative = 1;
6086 NEXT;
6087 }
6088 while ((CUR >= '0') && (CUR <= '9')) {
6089 exponent = exponent * 10 + (CUR - '0');
6090 NEXT;
6091 }
6092 if (is_exponent_negative)
6093 exponent = -exponent;
6094 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006095 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006096 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006097 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006098}
6099
6100/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006101 * xmlXPathParseLiteral:
6102 * @ctxt: the XPath Parser context
6103 *
6104 * Parse a Literal
6105 *
6106 * [29] Literal ::= '"' [^"]* '"'
6107 * | "'" [^']* "'"
6108 *
6109 * Returns the value found or NULL in case of error
6110 */
6111static xmlChar *
6112xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6113 const xmlChar *q;
6114 xmlChar *ret = NULL;
6115
6116 if (CUR == '"') {
6117 NEXT;
6118 q = CUR_PTR;
6119 while ((IS_CHAR(CUR)) && (CUR != '"'))
6120 NEXT;
6121 if (!IS_CHAR(CUR)) {
6122 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6123 } else {
6124 ret = xmlStrndup(q, CUR_PTR - q);
6125 NEXT;
6126 }
6127 } else if (CUR == '\'') {
6128 NEXT;
6129 q = CUR_PTR;
6130 while ((IS_CHAR(CUR)) && (CUR != '\''))
6131 NEXT;
6132 if (!IS_CHAR(CUR)) {
6133 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6134 } else {
6135 ret = xmlStrndup(q, CUR_PTR - q);
6136 NEXT;
6137 }
6138 } else {
6139 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6140 }
6141 return(ret);
6142}
6143
6144/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006145 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006146 * @ctxt: the XPath Parser context
6147 *
6148 * Parse a Literal and push it on the stack.
6149 *
6150 * [29] Literal ::= '"' [^"]* '"'
6151 * | "'" [^']* "'"
6152 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006153 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006154 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006155static void
6156xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006157 const xmlChar *q;
6158 xmlChar *ret = NULL;
6159
6160 if (CUR == '"') {
6161 NEXT;
6162 q = CUR_PTR;
6163 while ((IS_CHAR(CUR)) && (CUR != '"'))
6164 NEXT;
6165 if (!IS_CHAR(CUR)) {
6166 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6167 } else {
6168 ret = xmlStrndup(q, CUR_PTR - q);
6169 NEXT;
6170 }
6171 } else if (CUR == '\'') {
6172 NEXT;
6173 q = CUR_PTR;
6174 while ((IS_CHAR(CUR)) && (CUR != '\''))
6175 NEXT;
6176 if (!IS_CHAR(CUR)) {
6177 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6178 } else {
6179 ret = xmlStrndup(q, CUR_PTR - q);
6180 NEXT;
6181 }
6182 } else {
6183 XP_ERROR(XPATH_START_LITERAL_ERROR);
6184 }
6185 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006186 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6187 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006188 xmlFree(ret);
6189}
6190
6191/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006192 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006193 * @ctxt: the XPath Parser context
6194 *
6195 * Parse a VariableReference, evaluate it and push it on the stack.
6196 *
6197 * The variable bindings consist of a mapping from variable names
6198 * to variable values. The value of a variable is an object, which
6199 * of any of the types that are possible for the value of an expression,
6200 * and may also be of additional types not specified here.
6201 *
6202 * Early evaluation is possible since:
6203 * The variable bindings [...] used to evaluate a subexpression are
6204 * always the same as those used to evaluate the containing expression.
6205 *
6206 * [36] VariableReference ::= '$' QName
6207 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006208static void
6209xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006210 xmlChar *name;
6211 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006212
6213 SKIP_BLANKS;
6214 if (CUR != '$') {
6215 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6216 }
6217 NEXT;
6218 name = xmlXPathParseQName(ctxt, &prefix);
6219 if (name == NULL) {
6220 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6221 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006222 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006223 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6224 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006225 SKIP_BLANKS;
6226}
6227
6228/**
6229 * xmlXPathIsNodeType:
6230 * @ctxt: the XPath Parser context
6231 * @name: a name string
6232 *
6233 * Is the name given a NodeType one.
6234 *
6235 * [38] NodeType ::= 'comment'
6236 * | 'text'
6237 * | 'processing-instruction'
6238 * | 'node'
6239 *
6240 * Returns 1 if true 0 otherwise
6241 */
6242int
6243xmlXPathIsNodeType(const xmlChar *name) {
6244 if (name == NULL)
6245 return(0);
6246
6247 if (xmlStrEqual(name, BAD_CAST "comment"))
6248 return(1);
6249 if (xmlStrEqual(name, BAD_CAST "text"))
6250 return(1);
6251 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6252 return(1);
6253 if (xmlStrEqual(name, BAD_CAST "node"))
6254 return(1);
6255 return(0);
6256}
6257
6258/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006259 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006260 * @ctxt: the XPath Parser context
6261 *
6262 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6263 * [17] Argument ::= Expr
6264 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006265 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006266 * pushed on the stack
6267 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006268static void
6269xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006270 xmlChar *name;
6271 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006272 int nbargs = 0;
6273
6274 name = xmlXPathParseQName(ctxt, &prefix);
6275 if (name == NULL) {
6276 XP_ERROR(XPATH_EXPR_ERROR);
6277 }
6278 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006279#ifdef DEBUG_EXPR
6280 if (prefix == NULL)
6281 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6282 name);
6283 else
6284 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6285 prefix, name);
6286#endif
6287
Owen Taylor3473f882001-02-23 17:55:21 +00006288 if (CUR != '(') {
6289 XP_ERROR(XPATH_EXPR_ERROR);
6290 }
6291 NEXT;
6292 SKIP_BLANKS;
6293
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006294 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006295 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006296 int op1 = ctxt->comp->last;
6297 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006298 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006299 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006300 nbargs++;
6301 if (CUR == ')') break;
6302 if (CUR != ',') {
6303 XP_ERROR(XPATH_EXPR_ERROR);
6304 }
6305 NEXT;
6306 SKIP_BLANKS;
6307 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006308 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6309 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006310 NEXT;
6311 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006312}
6313
6314/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006315 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006316 * @ctxt: the XPath Parser context
6317 *
6318 * [15] PrimaryExpr ::= VariableReference
6319 * | '(' Expr ')'
6320 * | Literal
6321 * | Number
6322 * | FunctionCall
6323 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006324 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006325 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006326static void
6327xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006328 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006329 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006330 else if (CUR == '(') {
6331 NEXT;
6332 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006333 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006334 if (CUR != ')') {
6335 XP_ERROR(XPATH_EXPR_ERROR);
6336 }
6337 NEXT;
6338 SKIP_BLANKS;
6339 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006340 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006341 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006342 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006343 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006344 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006345 }
6346 SKIP_BLANKS;
6347}
6348
6349/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006350 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006351 * @ctxt: the XPath Parser context
6352 *
6353 * [20] FilterExpr ::= PrimaryExpr
6354 * | FilterExpr Predicate
6355 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006356 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006357 * Square brackets are used to filter expressions in the same way that
6358 * they are used in location paths. It is an error if the expression to
6359 * be filtered does not evaluate to a node-set. The context node list
6360 * used for evaluating the expression in square brackets is the node-set
6361 * to be filtered listed in document order.
6362 */
6363
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006364static void
6365xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6366 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006367 CHECK_ERROR;
6368 SKIP_BLANKS;
6369
6370 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006371 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006372 SKIP_BLANKS;
6373 }
6374
6375
6376}
6377
6378/**
6379 * xmlXPathScanName:
6380 * @ctxt: the XPath Parser context
6381 *
6382 * Trickery: parse an XML name but without consuming the input flow
6383 * Needed to avoid insanity in the parser state.
6384 *
6385 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6386 * CombiningChar | Extender
6387 *
6388 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6389 *
6390 * [6] Names ::= Name (S Name)*
6391 *
6392 * Returns the Name parsed or NULL
6393 */
6394
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006395static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006396xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6397 xmlChar buf[XML_MAX_NAMELEN];
6398 int len = 0;
6399
6400 SKIP_BLANKS;
6401 if (!IS_LETTER(CUR) && (CUR != '_') &&
6402 (CUR != ':')) {
6403 return(NULL);
6404 }
6405
6406 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6407 (NXT(len) == '.') || (NXT(len) == '-') ||
6408 (NXT(len) == '_') || (NXT(len) == ':') ||
6409 (IS_COMBINING(NXT(len))) ||
6410 (IS_EXTENDER(NXT(len)))) {
6411 buf[len] = NXT(len);
6412 len++;
6413 if (len >= XML_MAX_NAMELEN) {
6414 xmlGenericError(xmlGenericErrorContext,
6415 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6416 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6417 (NXT(len) == '.') || (NXT(len) == '-') ||
6418 (NXT(len) == '_') || (NXT(len) == ':') ||
6419 (IS_COMBINING(NXT(len))) ||
6420 (IS_EXTENDER(NXT(len))))
6421 len++;
6422 break;
6423 }
6424 }
6425 return(xmlStrndup(buf, len));
6426}
6427
6428/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006429 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006430 * @ctxt: the XPath Parser context
6431 *
6432 * [19] PathExpr ::= LocationPath
6433 * | FilterExpr
6434 * | FilterExpr '/' RelativeLocationPath
6435 * | FilterExpr '//' RelativeLocationPath
6436 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006437 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006438 * The / operator and // operators combine an arbitrary expression
6439 * and a relative location path. It is an error if the expression
6440 * does not evaluate to a node-set.
6441 * The / operator does composition in the same way as when / is
6442 * used in a location path. As in location paths, // is short for
6443 * /descendant-or-self::node()/.
6444 */
6445
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006446static void
6447xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006448 int lc = 1; /* Should we branch to LocationPath ? */
6449 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6450
6451 SKIP_BLANKS;
6452 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6453 (CUR == '\'') || (CUR == '"')) {
6454 lc = 0;
6455 } else if (CUR == '*') {
6456 /* relative or absolute location path */
6457 lc = 1;
6458 } else if (CUR == '/') {
6459 /* relative or absolute location path */
6460 lc = 1;
6461 } else if (CUR == '@') {
6462 /* relative abbreviated attribute location path */
6463 lc = 1;
6464 } else if (CUR == '.') {
6465 /* relative abbreviated attribute location path */
6466 lc = 1;
6467 } else {
6468 /*
6469 * Problem is finding if we have a name here whether it's:
6470 * - a nodetype
6471 * - a function call in which case it's followed by '('
6472 * - an axis in which case it's followed by ':'
6473 * - a element name
6474 * We do an a priori analysis here rather than having to
6475 * maintain parsed token content through the recursive function
6476 * calls. This looks uglier but makes the code quite easier to
6477 * read/write/debug.
6478 */
6479 SKIP_BLANKS;
6480 name = xmlXPathScanName(ctxt);
6481 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6482#ifdef DEBUG_STEP
6483 xmlGenericError(xmlGenericErrorContext,
6484 "PathExpr: Axis\n");
6485#endif
6486 lc = 1;
6487 xmlFree(name);
6488 } else if (name != NULL) {
6489 int len =xmlStrlen(name);
6490 int blank = 0;
6491
6492
6493 while (NXT(len) != 0) {
6494 if (NXT(len) == '/') {
6495 /* element name */
6496#ifdef DEBUG_STEP
6497 xmlGenericError(xmlGenericErrorContext,
6498 "PathExpr: AbbrRelLocation\n");
6499#endif
6500 lc = 1;
6501 break;
6502 } else if (IS_BLANK(NXT(len))) {
6503 /* skip to next */
6504 blank = 1;
6505 } else if (NXT(len) == ':') {
6506#ifdef DEBUG_STEP
6507 xmlGenericError(xmlGenericErrorContext,
6508 "PathExpr: AbbrRelLocation\n");
6509#endif
6510 lc = 1;
6511 break;
6512 } else if ((NXT(len) == '(')) {
6513 /* Note Type or Function */
6514 if (xmlXPathIsNodeType(name)) {
6515#ifdef DEBUG_STEP
6516 xmlGenericError(xmlGenericErrorContext,
6517 "PathExpr: Type search\n");
6518#endif
6519 lc = 1;
6520 } else {
6521#ifdef DEBUG_STEP
6522 xmlGenericError(xmlGenericErrorContext,
6523 "PathExpr: function call\n");
6524#endif
6525 lc = 0;
6526 }
6527 break;
6528 } else if ((NXT(len) == '[')) {
6529 /* element name */
6530#ifdef DEBUG_STEP
6531 xmlGenericError(xmlGenericErrorContext,
6532 "PathExpr: AbbrRelLocation\n");
6533#endif
6534 lc = 1;
6535 break;
6536 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6537 (NXT(len) == '=')) {
6538 lc = 1;
6539 break;
6540 } else {
6541 lc = 1;
6542 break;
6543 }
6544 len++;
6545 }
6546 if (NXT(len) == 0) {
6547#ifdef DEBUG_STEP
6548 xmlGenericError(xmlGenericErrorContext,
6549 "PathExpr: AbbrRelLocation\n");
6550#endif
6551 /* element name */
6552 lc = 1;
6553 }
6554 xmlFree(name);
6555 } else {
6556 /* make sure all cases are covered explicitely */
6557 XP_ERROR(XPATH_EXPR_ERROR);
6558 }
6559 }
6560
6561 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006562 if (CUR == '/') {
6563 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6564 } else {
6565 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006566 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006567 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006568 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006569 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006570 CHECK_ERROR;
6571 if ((CUR == '/') && (NXT(1) == '/')) {
6572 SKIP(2);
6573 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006574
6575 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6576 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6577 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6578
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006579 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006580 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006581 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006582 }
6583 }
6584 SKIP_BLANKS;
6585}
6586
6587/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006588 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006589 * @ctxt: the XPath Parser context
6590 *
6591 * [18] UnionExpr ::= PathExpr
6592 * | UnionExpr '|' PathExpr
6593 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006594 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006595 */
6596
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006597static void
6598xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6599 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006600 CHECK_ERROR;
6601 SKIP_BLANKS;
6602 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006603 int op1 = ctxt->comp->last;
6604 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006605
6606 NEXT;
6607 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006608 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006609
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006610 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6611
Owen Taylor3473f882001-02-23 17:55:21 +00006612 SKIP_BLANKS;
6613 }
Owen Taylor3473f882001-02-23 17:55:21 +00006614}
6615
6616/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006617 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006618 * @ctxt: the XPath Parser context
6619 *
6620 * [27] UnaryExpr ::= UnionExpr
6621 * | '-' UnaryExpr
6622 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006623 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006624 */
6625
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006626static void
6627xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006628 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006629 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006630
6631 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006632 while (CUR == '-') {
6633 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006634 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006635 NEXT;
6636 SKIP_BLANKS;
6637 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006638
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006639 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006640 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006641 if (found) {
6642 if (minus)
6643 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6644 else
6645 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006646 }
6647}
6648
6649/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006650 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006651 * @ctxt: the XPath Parser context
6652 *
6653 * [26] MultiplicativeExpr ::= UnaryExpr
6654 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6655 * | MultiplicativeExpr 'div' UnaryExpr
6656 * | MultiplicativeExpr 'mod' UnaryExpr
6657 * [34] MultiplyOperator ::= '*'
6658 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006659 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006660 */
6661
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006662static void
6663xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6664 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006665 CHECK_ERROR;
6666 SKIP_BLANKS;
6667 while ((CUR == '*') ||
6668 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6669 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6670 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006671 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006672
6673 if (CUR == '*') {
6674 op = 0;
6675 NEXT;
6676 } else if (CUR == 'd') {
6677 op = 1;
6678 SKIP(3);
6679 } else if (CUR == 'm') {
6680 op = 2;
6681 SKIP(3);
6682 }
6683 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006684 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006685 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006686 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006687 SKIP_BLANKS;
6688 }
6689}
6690
6691/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006692 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006693 * @ctxt: the XPath Parser context
6694 *
6695 * [25] AdditiveExpr ::= MultiplicativeExpr
6696 * | AdditiveExpr '+' MultiplicativeExpr
6697 * | AdditiveExpr '-' MultiplicativeExpr
6698 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006699 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006700 */
6701
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006702static void
6703xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006704
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006705 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006706 CHECK_ERROR;
6707 SKIP_BLANKS;
6708 while ((CUR == '+') || (CUR == '-')) {
6709 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006710 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006711
6712 if (CUR == '+') plus = 1;
6713 else plus = 0;
6714 NEXT;
6715 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006716 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006717 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006718 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006719 SKIP_BLANKS;
6720 }
6721}
6722
6723/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006724 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006725 * @ctxt: the XPath Parser context
6726 *
6727 * [24] RelationalExpr ::= AdditiveExpr
6728 * | RelationalExpr '<' AdditiveExpr
6729 * | RelationalExpr '>' AdditiveExpr
6730 * | RelationalExpr '<=' AdditiveExpr
6731 * | RelationalExpr '>=' AdditiveExpr
6732 *
6733 * A <= B > C is allowed ? Answer from James, yes with
6734 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6735 * which is basically what got implemented.
6736 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006737 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006738 * on the stack
6739 */
6740
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006741static void
6742xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6743 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006744 CHECK_ERROR;
6745 SKIP_BLANKS;
6746 while ((CUR == '<') ||
6747 (CUR == '>') ||
6748 ((CUR == '<') && (NXT(1) == '=')) ||
6749 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006750 int inf, strict;
6751 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006752
6753 if (CUR == '<') inf = 1;
6754 else inf = 0;
6755 if (NXT(1) == '=') strict = 0;
6756 else strict = 1;
6757 NEXT;
6758 if (!strict) NEXT;
6759 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006760 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006761 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006762 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006763 SKIP_BLANKS;
6764 }
6765}
6766
6767/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006768 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006769 * @ctxt: the XPath Parser context
6770 *
6771 * [23] EqualityExpr ::= RelationalExpr
6772 * | EqualityExpr '=' RelationalExpr
6773 * | EqualityExpr '!=' RelationalExpr
6774 *
6775 * A != B != C is allowed ? Answer from James, yes with
6776 * (RelationalExpr = RelationalExpr) = RelationalExpr
6777 * (RelationalExpr != RelationalExpr) != RelationalExpr
6778 * which is basically what got implemented.
6779 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006780 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006781 *
6782 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006783static void
6784xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6785 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006786 CHECK_ERROR;
6787 SKIP_BLANKS;
6788 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006789 int eq;
6790 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006791
6792 if (CUR == '=') eq = 1;
6793 else eq = 0;
6794 NEXT;
6795 if (!eq) NEXT;
6796 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006797 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006798 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006799 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006800 SKIP_BLANKS;
6801 }
6802}
6803
6804/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006805 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006806 * @ctxt: the XPath Parser context
6807 *
6808 * [22] AndExpr ::= EqualityExpr
6809 * | AndExpr 'and' EqualityExpr
6810 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006811 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006812 *
6813 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006814static void
6815xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6816 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006817 CHECK_ERROR;
6818 SKIP_BLANKS;
6819 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006820 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006821 SKIP(3);
6822 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006823 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006824 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006825 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006826 SKIP_BLANKS;
6827 }
6828}
6829
6830/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006831 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006832 * @ctxt: the XPath Parser context
6833 *
6834 * [14] Expr ::= OrExpr
6835 * [21] OrExpr ::= AndExpr
6836 * | OrExpr 'or' AndExpr
6837 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006838 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006839 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006840static void
6841xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6842 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006843 CHECK_ERROR;
6844 SKIP_BLANKS;
6845 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006846 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006847 SKIP(2);
6848 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006849 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006850 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006851 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6852 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006853 SKIP_BLANKS;
6854 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006855 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6856 /* more ops could be optimized too */
6857 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6858 }
Owen Taylor3473f882001-02-23 17:55:21 +00006859}
6860
6861/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006862 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006863 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006864 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006865 *
6866 * [8] Predicate ::= '[' PredicateExpr ']'
6867 * [9] PredicateExpr ::= Expr
6868 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006869 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006870 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006871static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006872xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006873 int op1 = ctxt->comp->last;
6874
6875 SKIP_BLANKS;
6876 if (CUR != '[') {
6877 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6878 }
6879 NEXT;
6880 SKIP_BLANKS;
6881
6882 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006883 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006884 CHECK_ERROR;
6885
6886 if (CUR != ']') {
6887 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6888 }
6889
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006890 if (filter)
6891 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6892 else
6893 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006894
6895 NEXT;
6896 SKIP_BLANKS;
6897}
6898
6899/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006900 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006901 * @ctxt: the XPath Parser context
6902 * @test: pointer to a xmlXPathTestVal
6903 * @type: pointer to a xmlXPathTypeVal
6904 * @prefix: placeholder for a possible name prefix
6905 *
6906 * [7] NodeTest ::= NameTest
6907 * | NodeType '(' ')'
6908 * | 'processing-instruction' '(' Literal ')'
6909 *
6910 * [37] NameTest ::= '*'
6911 * | NCName ':' '*'
6912 * | QName
6913 * [38] NodeType ::= 'comment'
6914 * | 'text'
6915 * | 'processing-instruction'
6916 * | 'node'
6917 *
6918 * Returns the name found and update @test, @type and @prefix appropriately
6919 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006920static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006921xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6922 xmlXPathTypeVal *type, const xmlChar **prefix,
6923 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006924 int blanks;
6925
6926 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6927 STRANGE;
6928 return(NULL);
6929 }
6930 *type = 0;
6931 *test = 0;
6932 *prefix = NULL;
6933 SKIP_BLANKS;
6934
6935 if ((name == NULL) && (CUR == '*')) {
6936 /*
6937 * All elements
6938 */
6939 NEXT;
6940 *test = NODE_TEST_ALL;
6941 return(NULL);
6942 }
6943
6944 if (name == NULL)
6945 name = xmlXPathParseNCName(ctxt);
6946 if (name == NULL) {
6947 XP_ERROR0(XPATH_EXPR_ERROR);
6948 }
6949
6950 blanks = IS_BLANK(CUR);
6951 SKIP_BLANKS;
6952 if (CUR == '(') {
6953 NEXT;
6954 /*
6955 * NodeType or PI search
6956 */
6957 if (xmlStrEqual(name, BAD_CAST "comment"))
6958 *type = NODE_TYPE_COMMENT;
6959 else if (xmlStrEqual(name, BAD_CAST "node"))
6960 *type = NODE_TYPE_NODE;
6961 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6962 *type = NODE_TYPE_PI;
6963 else if (xmlStrEqual(name, BAD_CAST "text"))
6964 *type = NODE_TYPE_TEXT;
6965 else {
6966 if (name != NULL)
6967 xmlFree(name);
6968 XP_ERROR0(XPATH_EXPR_ERROR);
6969 }
6970
6971 *test = NODE_TEST_TYPE;
6972
6973 SKIP_BLANKS;
6974 if (*type == NODE_TYPE_PI) {
6975 /*
6976 * Specific case: search a PI by name.
6977 */
Owen Taylor3473f882001-02-23 17:55:21 +00006978 if (name != NULL)
6979 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006980 name = NULL;
6981 if (CUR != ')') {
6982 name = xmlXPathParseLiteral(ctxt);
6983 CHECK_ERROR 0;
6984 SKIP_BLANKS;
6985 }
Owen Taylor3473f882001-02-23 17:55:21 +00006986 }
6987 if (CUR != ')') {
6988 if (name != NULL)
6989 xmlFree(name);
6990 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6991 }
6992 NEXT;
6993 return(name);
6994 }
6995 *test = NODE_TEST_NAME;
6996 if ((!blanks) && (CUR == ':')) {
6997 NEXT;
6998
6999 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007000 * Since currently the parser context don't have a
7001 * namespace list associated:
7002 * The namespace name for this prefix can be computed
7003 * only at evaluation time. The compilation is done
7004 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007005 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007006#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007007 *prefix = xmlXPathNsLookup(ctxt->context, name);
7008 if (name != NULL)
7009 xmlFree(name);
7010 if (*prefix == NULL) {
7011 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7012 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007013#else
7014 *prefix = name;
7015#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007016
7017 if (CUR == '*') {
7018 /*
7019 * All elements
7020 */
7021 NEXT;
7022 *test = NODE_TEST_ALL;
7023 return(NULL);
7024 }
7025
7026 name = xmlXPathParseNCName(ctxt);
7027 if (name == NULL) {
7028 XP_ERROR0(XPATH_EXPR_ERROR);
7029 }
7030 }
7031 return(name);
7032}
7033
7034/**
7035 * xmlXPathIsAxisName:
7036 * @name: a preparsed name token
7037 *
7038 * [6] AxisName ::= 'ancestor'
7039 * | 'ancestor-or-self'
7040 * | 'attribute'
7041 * | 'child'
7042 * | 'descendant'
7043 * | 'descendant-or-self'
7044 * | 'following'
7045 * | 'following-sibling'
7046 * | 'namespace'
7047 * | 'parent'
7048 * | 'preceding'
7049 * | 'preceding-sibling'
7050 * | 'self'
7051 *
7052 * Returns the axis or 0
7053 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007054static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007055xmlXPathIsAxisName(const xmlChar *name) {
7056 xmlXPathAxisVal ret = 0;
7057 switch (name[0]) {
7058 case 'a':
7059 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7060 ret = AXIS_ANCESTOR;
7061 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7062 ret = AXIS_ANCESTOR_OR_SELF;
7063 if (xmlStrEqual(name, BAD_CAST "attribute"))
7064 ret = AXIS_ATTRIBUTE;
7065 break;
7066 case 'c':
7067 if (xmlStrEqual(name, BAD_CAST "child"))
7068 ret = AXIS_CHILD;
7069 break;
7070 case 'd':
7071 if (xmlStrEqual(name, BAD_CAST "descendant"))
7072 ret = AXIS_DESCENDANT;
7073 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7074 ret = AXIS_DESCENDANT_OR_SELF;
7075 break;
7076 case 'f':
7077 if (xmlStrEqual(name, BAD_CAST "following"))
7078 ret = AXIS_FOLLOWING;
7079 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7080 ret = AXIS_FOLLOWING_SIBLING;
7081 break;
7082 case 'n':
7083 if (xmlStrEqual(name, BAD_CAST "namespace"))
7084 ret = AXIS_NAMESPACE;
7085 break;
7086 case 'p':
7087 if (xmlStrEqual(name, BAD_CAST "parent"))
7088 ret = AXIS_PARENT;
7089 if (xmlStrEqual(name, BAD_CAST "preceding"))
7090 ret = AXIS_PRECEDING;
7091 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7092 ret = AXIS_PRECEDING_SIBLING;
7093 break;
7094 case 's':
7095 if (xmlStrEqual(name, BAD_CAST "self"))
7096 ret = AXIS_SELF;
7097 break;
7098 }
7099 return(ret);
7100}
7101
7102/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007103 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007104 * @ctxt: the XPath Parser context
7105 *
7106 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7107 * | AbbreviatedStep
7108 *
7109 * [12] AbbreviatedStep ::= '.' | '..'
7110 *
7111 * [5] AxisSpecifier ::= AxisName '::'
7112 * | AbbreviatedAxisSpecifier
7113 *
7114 * [13] AbbreviatedAxisSpecifier ::= '@'?
7115 *
7116 * Modified for XPtr range support as:
7117 *
7118 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7119 * | AbbreviatedStep
7120 * | 'range-to' '(' Expr ')' Predicate*
7121 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007122 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007123 * A location step of . is short for self::node(). This is
7124 * particularly useful in conjunction with //. For example, the
7125 * location path .//para is short for
7126 * self::node()/descendant-or-self::node()/child::para
7127 * and so will select all para descendant elements of the context
7128 * node.
7129 * Similarly, a location step of .. is short for parent::node().
7130 * For example, ../title is short for parent::node()/child::title
7131 * and so will select the title children of the parent of the context
7132 * node.
7133 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007134static void
7135xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007136#ifdef LIBXML_XPTR_ENABLED
7137 int rangeto = 0;
7138 int op2 = -1;
7139#endif
7140
Owen Taylor3473f882001-02-23 17:55:21 +00007141 SKIP_BLANKS;
7142 if ((CUR == '.') && (NXT(1) == '.')) {
7143 SKIP(2);
7144 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007145 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7146 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007147 } else if (CUR == '.') {
7148 NEXT;
7149 SKIP_BLANKS;
7150 } else {
7151 xmlChar *name = NULL;
7152 const xmlChar *prefix = NULL;
7153 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007154 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007155 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007156 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007157
7158 /*
7159 * The modification needed for XPointer change to the production
7160 */
7161#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007162 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007163 name = xmlXPathParseNCName(ctxt);
7164 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007165 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007166 xmlFree(name);
7167 SKIP_BLANKS;
7168 if (CUR != '(') {
7169 XP_ERROR(XPATH_EXPR_ERROR);
7170 }
7171 NEXT;
7172 SKIP_BLANKS;
7173
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007174 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007175 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007176 CHECK_ERROR;
7177
7178 SKIP_BLANKS;
7179 if (CUR != ')') {
7180 XP_ERROR(XPATH_EXPR_ERROR);
7181 }
7182 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007183 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007184 goto eval_predicates;
7185 }
7186 }
7187#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007188 if (CUR == '*') {
7189 axis = AXIS_CHILD;
7190 } else {
7191 if (name == NULL)
7192 name = xmlXPathParseNCName(ctxt);
7193 if (name != NULL) {
7194 axis = xmlXPathIsAxisName(name);
7195 if (axis != 0) {
7196 SKIP_BLANKS;
7197 if ((CUR == ':') && (NXT(1) == ':')) {
7198 SKIP(2);
7199 xmlFree(name);
7200 name = NULL;
7201 } else {
7202 /* an element name can conflict with an axis one :-\ */
7203 axis = AXIS_CHILD;
7204 }
Owen Taylor3473f882001-02-23 17:55:21 +00007205 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007206 axis = AXIS_CHILD;
7207 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007208 } else if (CUR == '@') {
7209 NEXT;
7210 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007211 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007212 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007213 }
Owen Taylor3473f882001-02-23 17:55:21 +00007214 }
7215
7216 CHECK_ERROR;
7217
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007218 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007219 if (test == 0)
7220 return;
7221
7222#ifdef DEBUG_STEP
7223 xmlGenericError(xmlGenericErrorContext,
7224 "Basis : computing new set\n");
7225#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007226
Owen Taylor3473f882001-02-23 17:55:21 +00007227#ifdef DEBUG_STEP
7228 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007229 if (ctxt->value == NULL)
7230 xmlGenericError(xmlGenericErrorContext, "no value\n");
7231 else if (ctxt->value->nodesetval == NULL)
7232 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7233 else
7234 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007235#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007236
7237eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007238 op1 = ctxt->comp->last;
7239 ctxt->comp->last = -1;
7240
Owen Taylor3473f882001-02-23 17:55:21 +00007241 SKIP_BLANKS;
7242 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007243 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007244 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007245
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007246#ifdef LIBXML_XPTR_ENABLED
7247 if (rangeto) {
7248 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7249 } else
7250#endif
7251 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7252 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007253
Owen Taylor3473f882001-02-23 17:55:21 +00007254 }
7255#ifdef DEBUG_STEP
7256 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007257 if (ctxt->value == NULL)
7258 xmlGenericError(xmlGenericErrorContext, "no value\n");
7259 else if (ctxt->value->nodesetval == NULL)
7260 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7261 else
7262 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7263 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007264#endif
7265}
7266
7267/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007268 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007269 * @ctxt: the XPath Parser context
7270 *
7271 * [3] RelativeLocationPath ::= Step
7272 * | RelativeLocationPath '/' Step
7273 * | AbbreviatedRelativeLocationPath
7274 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7275 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007276 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007277 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007278static void
Owen Taylor3473f882001-02-23 17:55:21 +00007279#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007280xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007281#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007282xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007283#endif
7284(xmlXPathParserContextPtr ctxt) {
7285 SKIP_BLANKS;
7286 if ((CUR == '/') && (NXT(1) == '/')) {
7287 SKIP(2);
7288 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007289 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7290 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007291 } else if (CUR == '/') {
7292 NEXT;
7293 SKIP_BLANKS;
7294 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007295 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007296 SKIP_BLANKS;
7297 while (CUR == '/') {
7298 if ((CUR == '/') && (NXT(1) == '/')) {
7299 SKIP(2);
7300 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007301 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007302 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007303 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007304 } else if (CUR == '/') {
7305 NEXT;
7306 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007307 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007308 }
7309 SKIP_BLANKS;
7310 }
7311}
7312
7313/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007314 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007315 * @ctxt: the XPath Parser context
7316 *
7317 * [1] LocationPath ::= RelativeLocationPath
7318 * | AbsoluteLocationPath
7319 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7320 * | AbbreviatedAbsoluteLocationPath
7321 * [10] AbbreviatedAbsoluteLocationPath ::=
7322 * '//' RelativeLocationPath
7323 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007324 * Compile a location path
7325 *
Owen Taylor3473f882001-02-23 17:55:21 +00007326 * // is short for /descendant-or-self::node()/. For example,
7327 * //para is short for /descendant-or-self::node()/child::para and
7328 * so will select any para element in the document (even a para element
7329 * that is a document element will be selected by //para since the
7330 * document element node is a child of the root node); div//para is
7331 * short for div/descendant-or-self::node()/child::para and so will
7332 * select all para descendants of div children.
7333 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007334static void
7335xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007336 SKIP_BLANKS;
7337 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007338 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007339 } else {
7340 while (CUR == '/') {
7341 if ((CUR == '/') && (NXT(1) == '/')) {
7342 SKIP(2);
7343 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007344 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7345 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007346 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007347 } else if (CUR == '/') {
7348 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007349 SKIP_BLANKS;
7350 if ((CUR != 0 ) &&
7351 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7352 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007353 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007354 }
7355 }
7356 }
7357}
7358
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007359/************************************************************************
7360 * *
7361 * XPath precompiled expression evaluation *
7362 * *
7363 ************************************************************************/
7364
Daniel Veillardf06307e2001-07-03 10:35:50 +00007365static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007366xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7367
7368/**
7369 * xmlXPathNodeCollectAndTest:
7370 * @ctxt: the XPath Parser context
7371 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007372 * @first: pointer to the first element in document order
7373 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007374 *
7375 * This is the function implementing a step: based on the current list
7376 * of nodes, it builds up a new list, looking at all nodes under that
7377 * axis and selecting them it also do the predicate filtering
7378 *
7379 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007380 *
7381 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007382 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007383static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007384xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007385 xmlXPathStepOpPtr op,
7386 xmlNodePtr * first, xmlNodePtr * last)
7387{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007388 xmlXPathAxisVal axis = op->value;
7389 xmlXPathTestVal test = op->value2;
7390 xmlXPathTypeVal type = op->value3;
7391 const xmlChar *prefix = op->value4;
7392 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007393 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007394
7395#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007396 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007397#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007398 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007399 xmlNodeSetPtr ret, list;
7400 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007401 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007402 xmlNodePtr cur = NULL;
7403 xmlXPathObjectPtr obj;
7404 xmlNodeSetPtr nodelist;
7405 xmlNodePtr tmp;
7406
Daniel Veillardf06307e2001-07-03 10:35:50 +00007407 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007408 obj = valuePop(ctxt);
7409 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007410 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007411 URI = xmlXPathNsLookup(ctxt->context, prefix);
7412 if (URI == NULL)
7413 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00007414 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007415#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007416 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007417#endif
7418 switch (axis) {
7419 case AXIS_ANCESTOR:
7420#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007421 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007422#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007423 first = NULL;
7424 next = xmlXPathNextAncestor;
7425 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007426 case AXIS_ANCESTOR_OR_SELF:
7427#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007428 xmlGenericError(xmlGenericErrorContext,
7429 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007430#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007431 first = NULL;
7432 next = xmlXPathNextAncestorOrSelf;
7433 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007434 case AXIS_ATTRIBUTE:
7435#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007436 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007437#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007438 first = NULL;
7439 last = NULL;
7440 next = xmlXPathNextAttribute;
7441 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007442 case AXIS_CHILD:
7443#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007444 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007445#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007446 last = NULL;
7447 next = xmlXPathNextChild;
7448 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007449 case AXIS_DESCENDANT:
7450#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007451 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007452#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007453 last = NULL;
7454 next = xmlXPathNextDescendant;
7455 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007456 case AXIS_DESCENDANT_OR_SELF:
7457#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007458 xmlGenericError(xmlGenericErrorContext,
7459 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007460#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007461 last = NULL;
7462 next = xmlXPathNextDescendantOrSelf;
7463 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007464 case AXIS_FOLLOWING:
7465#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007466 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007467#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007468 last = NULL;
7469 next = xmlXPathNextFollowing;
7470 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007471 case AXIS_FOLLOWING_SIBLING:
7472#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007473 xmlGenericError(xmlGenericErrorContext,
7474 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007475#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007476 last = NULL;
7477 next = xmlXPathNextFollowingSibling;
7478 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007479 case AXIS_NAMESPACE:
7480#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007481 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007482#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007483 first = NULL;
7484 last = NULL;
7485 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
7486 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007487 case AXIS_PARENT:
7488#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007489 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007490#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007491 first = NULL;
7492 next = xmlXPathNextParent;
7493 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007494 case AXIS_PRECEDING:
7495#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007496 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007497#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007498 first = NULL;
7499 next = xmlXPathNextPrecedingInternal;
7500 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007501 case AXIS_PRECEDING_SIBLING:
7502#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007503 xmlGenericError(xmlGenericErrorContext,
7504 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007505#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007506 first = NULL;
7507 next = xmlXPathNextPrecedingSibling;
7508 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007509 case AXIS_SELF:
7510#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007511 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007512#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007513 first = NULL;
7514 last = NULL;
7515 next = xmlXPathNextSelf;
7516 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007517 }
7518 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00007519 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007520
7521 nodelist = obj->nodesetval;
7522 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007523 xmlXPathFreeObject(obj);
7524 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7525 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007526 }
7527 addNode = xmlXPathNodeSetAddUnique;
7528 ret = NULL;
7529#ifdef DEBUG_STEP
7530 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007531 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007532 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007533 case NODE_TEST_NONE:
7534 xmlGenericError(xmlGenericErrorContext,
7535 " searching for none !!!\n");
7536 break;
7537 case NODE_TEST_TYPE:
7538 xmlGenericError(xmlGenericErrorContext,
7539 " searching for type %d\n", type);
7540 break;
7541 case NODE_TEST_PI:
7542 xmlGenericError(xmlGenericErrorContext,
7543 " searching for PI !!!\n");
7544 break;
7545 case NODE_TEST_ALL:
7546 xmlGenericError(xmlGenericErrorContext,
7547 " searching for *\n");
7548 break;
7549 case NODE_TEST_NS:
7550 xmlGenericError(xmlGenericErrorContext,
7551 " searching for namespace %s\n",
7552 prefix);
7553 break;
7554 case NODE_TEST_NAME:
7555 xmlGenericError(xmlGenericErrorContext,
7556 " searching for name %s\n", name);
7557 if (prefix != NULL)
7558 xmlGenericError(xmlGenericErrorContext,
7559 " with namespace %s\n", prefix);
7560 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007561 }
7562 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7563#endif
7564 /*
7565 * 2.3 Node Tests
7566 * - For the attribute axis, the principal node type is attribute.
7567 * - For the namespace axis, the principal node type is namespace.
7568 * - For other axes, the principal node type is element.
7569 *
7570 * A node test * is true for any node of the
7571 * principal node type. For example, child::* willi
7572 * select all element children of the context node
7573 */
7574 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007575 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007576 ctxt->context->node = nodelist->nodeTab[i];
7577
Daniel Veillardf06307e2001-07-03 10:35:50 +00007578 cur = NULL;
7579 list = xmlXPathNodeSetCreate(NULL);
7580 do {
7581 cur = next(ctxt, cur);
7582 if (cur == NULL)
7583 break;
7584 if ((first != NULL) && (*first == cur))
7585 break;
7586 if (((t % 256) == 0) &&
7587 (first != NULL) && (*first != NULL) &&
7588 (xmlXPathCmpNodes(*first, cur) >= 0))
7589 break;
7590 if ((last != NULL) && (*last == cur))
7591 break;
7592 if (((t % 256) == 0) &&
7593 (last != NULL) && (*last != NULL) &&
7594 (xmlXPathCmpNodes(cur, *last) >= 0))
7595 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007596 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007597#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007598 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7599#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007600 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007601 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007602 ctxt->context->node = tmp;
7603 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007604 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007605 if ((cur->type == type) ||
7606 ((type == NODE_TYPE_NODE) &&
7607 ((cur->type == XML_DOCUMENT_NODE) ||
7608 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7609 (cur->type == XML_ELEMENT_NODE) ||
7610 (cur->type == XML_PI_NODE) ||
7611 (cur->type == XML_COMMENT_NODE) ||
7612 (cur->type == XML_CDATA_SECTION_NODE) ||
7613 (cur->type == XML_TEXT_NODE)))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007614#ifdef DEBUG_STEP
7615 n++;
7616#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007617 addNode(list, cur);
7618 }
7619 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007620 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007621 if (cur->type == XML_PI_NODE) {
7622 if ((name != NULL) &&
7623 (!xmlStrEqual(name, cur->name)))
7624 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007625#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007626 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007627#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007628 addNode(list, cur);
7629 }
7630 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007631 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007632 if (axis == AXIS_ATTRIBUTE) {
7633 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007634#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007635 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007636#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007637 addNode(list, cur);
7638 }
7639 } else if (axis == AXIS_NAMESPACE) {
7640 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007641#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007642 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007643#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007644 addNode(list, cur);
7645 }
7646 } else {
7647 if (cur->type == XML_ELEMENT_NODE) {
7648 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007649#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007650 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007651#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007652 addNode(list, cur);
7653 } else if ((cur->ns != NULL) &&
7654 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007655#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007656 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007657#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007658 addNode(list, cur);
7659 }
7660 }
7661 }
7662 break;
7663 case NODE_TEST_NS:{
7664 TODO;
7665 break;
7666 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007667 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007668 switch (cur->type) {
7669 case XML_ELEMENT_NODE:
7670 if (xmlStrEqual(name, cur->name)) {
7671 if (prefix == NULL) {
7672 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007673#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007674 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007675#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007676 addNode(list, cur);
7677 }
7678 } else {
7679 if ((cur->ns != NULL) &&
7680 (xmlStrEqual(URI,
7681 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007682#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007683 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007684#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007685 addNode(list, cur);
7686 }
7687 }
7688 }
7689 break;
7690 case XML_ATTRIBUTE_NODE:{
7691 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007692
Daniel Veillardf06307e2001-07-03 10:35:50 +00007693 if (xmlStrEqual(name, attr->name)) {
7694 if (prefix == NULL) {
7695 if ((attr->ns == NULL) ||
7696 (attr->ns->prefix == NULL)) {
7697#ifdef DEBUG_STEP
7698 n++;
7699#endif
7700 addNode(list,
7701 (xmlNodePtr) attr);
7702 }
7703 } else {
7704 if ((attr->ns != NULL) &&
7705 (xmlStrEqual(URI,
7706 attr->ns->
7707 href))) {
7708#ifdef DEBUG_STEP
7709 n++;
7710#endif
7711 addNode(list,
7712 (xmlNodePtr) attr);
7713 }
7714 }
7715 }
7716 break;
7717 }
7718 case XML_NAMESPACE_DECL:
7719 if (cur->type == XML_NAMESPACE_DECL) {
7720 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007721
Daniel Veillardf06307e2001-07-03 10:35:50 +00007722 if ((ns->prefix != NULL) && (name != NULL)
7723 && (xmlStrEqual(ns->prefix, name))) {
7724#ifdef DEBUG_STEP
7725 n++;
7726#endif
7727 addNode(list, cur);
7728 }
7729 }
7730 break;
7731 default:
7732 break;
7733 }
7734 break;
7735 break;
7736 }
7737 } while (cur != NULL);
7738
7739 /*
7740 * If there is some predicate filtering do it now
7741 */
7742 if (op->ch2 != -1) {
7743 xmlXPathObjectPtr obj2;
7744
7745 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7746 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7747 CHECK_TYPE0(XPATH_NODESET);
7748 obj2 = valuePop(ctxt);
7749 list = obj2->nodesetval;
7750 obj2->nodesetval = NULL;
7751 xmlXPathFreeObject(obj2);
7752 }
7753 if (ret == NULL) {
7754 ret = list;
7755 } else {
7756 ret = xmlXPathNodeSetMerge(ret, list);
7757 xmlXPathFreeNodeSet(list);
7758 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007759 }
7760 ctxt->context->node = tmp;
7761#ifdef DEBUG_STEP
7762 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007763 "\nExamined %d nodes, found %d nodes at that step\n",
7764 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007765#endif
7766 xmlXPathFreeObject(obj);
7767 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +00007768 return(t);
7769}
7770
7771/**
7772 * xmlXPathNodeCollectAndTestNth:
7773 * @ctxt: the XPath Parser context
7774 * @op: the XPath precompiled step operation
7775 * @indx: the index to collect
7776 * @first: pointer to the first element in document order
7777 * @last: pointer to the last element in document order
7778 *
7779 * This is the function implementing a step: based on the current list
7780 * of nodes, it builds up a new list, looking at all nodes under that
7781 * axis and selecting them it also do the predicate filtering
7782 *
7783 * Pushes the new NodeSet resulting from the search.
7784 * Returns the number of node traversed
7785 */
7786static int
7787xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
7788 xmlXPathStepOpPtr op, int indx,
7789 xmlNodePtr * first, xmlNodePtr * last)
7790{
7791 xmlXPathAxisVal axis = op->value;
7792 xmlXPathTestVal test = op->value2;
7793 xmlXPathTypeVal type = op->value3;
7794 const xmlChar *prefix = op->value4;
7795 const xmlChar *name = op->value5;
7796 const xmlChar *URI = NULL;
7797 int n = 0, t = 0;
7798
7799 int i;
7800 xmlNodeSetPtr list;
7801 xmlXPathTraversalFunction next = NULL;
7802 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
7803 xmlNodePtr cur = NULL;
7804 xmlXPathObjectPtr obj;
7805 xmlNodeSetPtr nodelist;
7806 xmlNodePtr tmp;
7807
7808 CHECK_TYPE0(XPATH_NODESET);
7809 obj = valuePop(ctxt);
7810 addNode = xmlXPathNodeSetAdd;
7811 if (prefix != NULL) {
7812 URI = xmlXPathNsLookup(ctxt->context, prefix);
7813 if (URI == NULL)
7814 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7815 }
7816#ifdef DEBUG_STEP_NTH
7817 xmlGenericError(xmlGenericErrorContext, "new step : ");
7818 if (first != NULL) {
7819 if (*first != NULL)
7820 xmlGenericError(xmlGenericErrorContext, "first = %s ",
7821 (*first)->name);
7822 else
7823 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
7824 }
7825 if (last != NULL) {
7826 if (*last != NULL)
7827 xmlGenericError(xmlGenericErrorContext, "last = %s ",
7828 (*last)->name);
7829 else
7830 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
7831 }
7832#endif
7833 switch (axis) {
7834 case AXIS_ANCESTOR:
7835#ifdef DEBUG_STEP_NTH
7836 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
7837#endif
7838 first = NULL;
7839 next = xmlXPathNextAncestor;
7840 break;
7841 case AXIS_ANCESTOR_OR_SELF:
7842#ifdef DEBUG_STEP_NTH
7843 xmlGenericError(xmlGenericErrorContext,
7844 "axis 'ancestors-or-self' ");
7845#endif
7846 first = NULL;
7847 next = xmlXPathNextAncestorOrSelf;
7848 break;
7849 case AXIS_ATTRIBUTE:
7850#ifdef DEBUG_STEP_NTH
7851 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
7852#endif
7853 first = NULL;
7854 last = NULL;
7855 next = xmlXPathNextAttribute;
7856 break;
7857 case AXIS_CHILD:
7858#ifdef DEBUG_STEP_NTH
7859 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
7860#endif
7861 last = NULL;
7862 next = xmlXPathNextChild;
7863 break;
7864 case AXIS_DESCENDANT:
7865#ifdef DEBUG_STEP_NTH
7866 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
7867#endif
7868 last = NULL;
7869 next = xmlXPathNextDescendant;
7870 break;
7871 case AXIS_DESCENDANT_OR_SELF:
7872#ifdef DEBUG_STEP_NTH
7873 xmlGenericError(xmlGenericErrorContext,
7874 "axis 'descendant-or-self' ");
7875#endif
7876 last = NULL;
7877 next = xmlXPathNextDescendantOrSelf;
7878 break;
7879 case AXIS_FOLLOWING:
7880#ifdef DEBUG_STEP_NTH
7881 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
7882#endif
7883 last = NULL;
7884 next = xmlXPathNextFollowing;
7885 break;
7886 case AXIS_FOLLOWING_SIBLING:
7887#ifdef DEBUG_STEP_NTH
7888 xmlGenericError(xmlGenericErrorContext,
7889 "axis 'following-siblings' ");
7890#endif
7891 last = NULL;
7892 next = xmlXPathNextFollowingSibling;
7893 break;
7894 case AXIS_NAMESPACE:
7895#ifdef DEBUG_STEP_NTH
7896 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
7897#endif
7898 last = NULL;
7899 first = NULL;
7900 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
7901 break;
7902 case AXIS_PARENT:
7903#ifdef DEBUG_STEP_NTH
7904 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
7905#endif
7906 first = NULL;
7907 next = xmlXPathNextParent;
7908 break;
7909 case AXIS_PRECEDING:
7910#ifdef DEBUG_STEP_NTH
7911 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
7912#endif
7913 first = NULL;
7914 next = xmlXPathNextPrecedingInternal;
7915 break;
7916 case AXIS_PRECEDING_SIBLING:
7917#ifdef DEBUG_STEP_NTH
7918 xmlGenericError(xmlGenericErrorContext,
7919 "axis 'preceding-sibling' ");
7920#endif
7921 first = NULL;
7922 next = xmlXPathNextPrecedingSibling;
7923 break;
7924 case AXIS_SELF:
7925#ifdef DEBUG_STEP_NTH
7926 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
7927#endif
7928 first = NULL;
7929 last = NULL;
7930 next = xmlXPathNextSelf;
7931 break;
7932 }
7933 if (next == NULL)
7934 return(0);
7935
7936 nodelist = obj->nodesetval;
7937 if (nodelist == NULL) {
7938 xmlXPathFreeObject(obj);
7939 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7940 return(0);
7941 }
7942 addNode = xmlXPathNodeSetAddUnique;
7943#ifdef DEBUG_STEP_NTH
7944 xmlGenericError(xmlGenericErrorContext,
7945 " context contains %d nodes\n", nodelist->nodeNr);
7946 switch (test) {
7947 case NODE_TEST_NONE:
7948 xmlGenericError(xmlGenericErrorContext,
7949 " searching for none !!!\n");
7950 break;
7951 case NODE_TEST_TYPE:
7952 xmlGenericError(xmlGenericErrorContext,
7953 " searching for type %d\n", type);
7954 break;
7955 case NODE_TEST_PI:
7956 xmlGenericError(xmlGenericErrorContext,
7957 " searching for PI !!!\n");
7958 break;
7959 case NODE_TEST_ALL:
7960 xmlGenericError(xmlGenericErrorContext,
7961 " searching for *\n");
7962 break;
7963 case NODE_TEST_NS:
7964 xmlGenericError(xmlGenericErrorContext,
7965 " searching for namespace %s\n",
7966 prefix);
7967 break;
7968 case NODE_TEST_NAME:
7969 xmlGenericError(xmlGenericErrorContext,
7970 " searching for name %s\n", name);
7971 if (prefix != NULL)
7972 xmlGenericError(xmlGenericErrorContext,
7973 " with namespace %s\n", prefix);
7974 break;
7975 }
7976 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7977#endif
7978 /*
7979 * 2.3 Node Tests
7980 * - For the attribute axis, the principal node type is attribute.
7981 * - For the namespace axis, the principal node type is namespace.
7982 * - For other axes, the principal node type is element.
7983 *
7984 * A node test * is true for any node of the
7985 * principal node type. For example, child::* willi
7986 * select all element children of the context node
7987 */
7988 tmp = ctxt->context->node;
7989 list = xmlXPathNodeSetCreate(NULL);
7990 for (i = 0; i < nodelist->nodeNr; i++) {
7991 ctxt->context->node = nodelist->nodeTab[i];
7992
7993 cur = NULL;
7994 n = 0;
7995 do {
7996 cur = next(ctxt, cur);
7997 if (cur == NULL)
7998 break;
7999 if ((first != NULL) && (*first == cur))
8000 break;
8001 if (((t % 256) == 0) &&
8002 (first != NULL) && (*first != NULL) &&
8003 (xmlXPathCmpNodes(*first, cur) >= 0))
8004 break;
8005 if ((last != NULL) && (*last == cur))
8006 break;
8007 if (((t % 256) == 0) &&
8008 (last != NULL) && (*last != NULL) &&
8009 (xmlXPathCmpNodes(cur, *last) >= 0))
8010 break;
8011 t++;
8012 switch (test) {
8013 case NODE_TEST_NONE:
8014 ctxt->context->node = tmp;
8015 STRANGE return(0);
8016 case NODE_TEST_TYPE:
8017 if ((cur->type == type) ||
8018 ((type == NODE_TYPE_NODE) &&
8019 ((cur->type == XML_DOCUMENT_NODE) ||
8020 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8021 (cur->type == XML_ELEMENT_NODE) ||
8022 (cur->type == XML_PI_NODE) ||
8023 (cur->type == XML_COMMENT_NODE) ||
8024 (cur->type == XML_CDATA_SECTION_NODE) ||
8025 (cur->type == XML_TEXT_NODE)))) {
8026 n++;
8027 if (n == indx)
8028 addNode(list, cur);
8029 }
8030 break;
8031 case NODE_TEST_PI:
8032 if (cur->type == XML_PI_NODE) {
8033 if ((name != NULL) &&
8034 (!xmlStrEqual(name, cur->name)))
8035 break;
8036 n++;
8037 if (n == indx)
8038 addNode(list, cur);
8039 }
8040 break;
8041 case NODE_TEST_ALL:
8042 if (axis == AXIS_ATTRIBUTE) {
8043 if (cur->type == XML_ATTRIBUTE_NODE) {
8044 n++;
8045 if (n == indx)
8046 addNode(list, cur);
8047 }
8048 } else if (axis == AXIS_NAMESPACE) {
8049 if (cur->type == XML_NAMESPACE_DECL) {
8050 n++;
8051 if (n == indx)
8052 addNode(list, cur);
8053 }
8054 } else {
8055 if (cur->type == XML_ELEMENT_NODE) {
8056 if (prefix == NULL) {
8057 n++;
8058 if (n == indx)
8059 addNode(list, cur);
8060 } else if ((cur->ns != NULL) &&
8061 (xmlStrEqual(URI, cur->ns->href))) {
8062 n++;
8063 if (n == indx)
8064 addNode(list, cur);
8065 }
8066 }
8067 }
8068 break;
8069 case NODE_TEST_NS:{
8070 TODO;
8071 break;
8072 }
8073 case NODE_TEST_NAME:
8074 switch (cur->type) {
8075 case XML_ELEMENT_NODE:
8076 if (xmlStrEqual(name, cur->name)) {
8077 if (prefix == NULL) {
8078 if (cur->ns == NULL) {
8079 n++;
8080 if (n == indx)
8081 addNode(list, cur);
8082 }
8083 } else {
8084 if ((cur->ns != NULL) &&
8085 (xmlStrEqual(URI,
8086 cur->ns->href))) {
8087 n++;
8088 if (n == indx)
8089 addNode(list, cur);
8090 }
8091 }
8092 }
8093 break;
8094 case XML_ATTRIBUTE_NODE:{
8095 xmlAttrPtr attr = (xmlAttrPtr) cur;
8096
8097 if (xmlStrEqual(name, attr->name)) {
8098 if (prefix == NULL) {
8099 if ((attr->ns == NULL) ||
8100 (attr->ns->prefix == NULL)) {
8101 n++;
8102 if (n == indx)
8103 addNode(list, cur);
8104 }
8105 } else {
8106 if ((attr->ns != NULL) &&
8107 (xmlStrEqual(URI,
8108 attr->ns->
8109 href))) {
8110 n++;
8111 if (n == indx)
8112 addNode(list, cur);
8113 }
8114 }
8115 }
8116 break;
8117 }
8118 case XML_NAMESPACE_DECL:
8119 if (cur->type == XML_NAMESPACE_DECL) {
8120 xmlNsPtr ns = (xmlNsPtr) cur;
8121
8122 if ((ns->prefix != NULL) && (name != NULL)
8123 && (xmlStrEqual(ns->prefix, name))) {
8124 n++;
8125 if (n == indx)
8126 addNode(list, cur);
8127 }
8128 }
8129 break;
8130 default:
8131 break;
8132 }
8133 break;
8134 break;
8135 }
8136 } while (n < indx);
8137 }
8138 ctxt->context->node = tmp;
8139#ifdef DEBUG_STEP_NTH
8140 xmlGenericError(xmlGenericErrorContext,
8141 "\nExamined %d nodes, found %d nodes at that step\n",
8142 t, list->nodeNr);
8143#endif
8144 xmlXPathFreeObject(obj);
8145 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8146 return(t);
8147}
8148
8149/**
8150 * xmlXPathCompOpEvalFirst:
8151 * @ctxt: the XPath parser context with the compiled expression
8152 * @op: an XPath compiled operation
8153 * @first: the first elem found so far
8154 *
8155 * Evaluate the Precompiled XPath operation searching only the first
8156 * element in document order
8157 *
8158 * Returns the number of examined objects.
8159 */
8160static int
8161xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8162 xmlXPathStepOpPtr op, xmlNodePtr * first)
8163{
8164 int total = 0, cur;
8165 xmlXPathCompExprPtr comp;
8166 xmlXPathObjectPtr arg1, arg2;
8167
8168 comp = ctxt->comp;
8169 switch (op->op) {
8170 case XPATH_OP_END:
8171 return (0);
8172 case XPATH_OP_UNION:
8173 total =
8174 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8175 first);
8176 if ((ctxt->value != NULL)
8177 && (ctxt->value->type == XPATH_NODESET)
8178 && (ctxt->value->nodesetval != NULL)
8179 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8180 /*
8181 * limit tree traversing to first node in the result
8182 */
8183 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8184 *first = ctxt->value->nodesetval->nodeTab[0];
8185 }
8186 cur =
8187 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8188 first);
8189 CHECK_TYPE0(XPATH_NODESET);
8190 arg2 = valuePop(ctxt);
8191
8192 CHECK_TYPE0(XPATH_NODESET);
8193 arg1 = valuePop(ctxt);
8194
8195 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8196 arg2->nodesetval);
8197 valuePush(ctxt, arg1);
8198 xmlXPathFreeObject(arg2);
8199 /* optimizer */
8200 if (total > cur)
8201 xmlXPathCompSwap(op);
8202 return (total + cur);
8203 case XPATH_OP_ROOT:
8204 xmlXPathRoot(ctxt);
8205 return (0);
8206 case XPATH_OP_NODE:
8207 if (op->ch1 != -1)
8208 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8209 if (op->ch2 != -1)
8210 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8211 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8212 return (total);
8213 case XPATH_OP_RESET:
8214 if (op->ch1 != -1)
8215 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8216 if (op->ch2 != -1)
8217 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8218 ctxt->context->node = NULL;
8219 return (total);
8220 case XPATH_OP_COLLECT:{
8221 if (op->ch1 == -1)
8222 return (total);
8223
8224 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8225
8226 /*
8227 * Optimization for [n] selection where n is a number
8228 */
8229 if ((op->ch2 != -1) &&
8230 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8231 (comp->steps[op->ch2].ch1 == -1) &&
8232 (comp->steps[op->ch2].ch2 != -1) &&
8233 (comp->steps[comp->steps[op->ch2].ch2].op ==
8234 XPATH_OP_VALUE)) {
8235 xmlXPathObjectPtr val;
8236
8237 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8238 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8239 int indx = (int) val->floatval;
8240
8241 if (val->floatval == (float) indx) {
8242 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8243 first, NULL);
8244 return (total);
8245 }
8246 }
8247 }
8248 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8249 return (total);
8250 }
8251 case XPATH_OP_VALUE:
8252 valuePush(ctxt,
8253 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8254 return (0);
8255 case XPATH_OP_SORT:
8256 if (op->ch1 != -1)
8257 total +=
8258 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8259 first);
8260 if ((ctxt->value != NULL)
8261 && (ctxt->value->type == XPATH_NODESET)
8262 && (ctxt->value->nodesetval != NULL))
8263 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8264 return (total);
8265 default:
8266 return (xmlXPathCompOpEval(ctxt, op));
8267 }
8268}
8269
8270/**
8271 * xmlXPathCompOpEvalLast:
8272 * @ctxt: the XPath parser context with the compiled expression
8273 * @op: an XPath compiled operation
8274 * @last: the last elem found so far
8275 *
8276 * Evaluate the Precompiled XPath operation searching only the last
8277 * element in document order
8278 *
8279 * Returns the number of node traversed
8280 */
8281static int
8282xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8283 xmlNodePtr * last)
8284{
8285 int total = 0, cur;
8286 xmlXPathCompExprPtr comp;
8287 xmlXPathObjectPtr arg1, arg2;
8288
8289 comp = ctxt->comp;
8290 switch (op->op) {
8291 case XPATH_OP_END:
8292 return (0);
8293 case XPATH_OP_UNION:
8294 total =
8295 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8296 if ((ctxt->value != NULL)
8297 && (ctxt->value->type == XPATH_NODESET)
8298 && (ctxt->value->nodesetval != NULL)
8299 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8300 /*
8301 * limit tree traversing to first node in the result
8302 */
8303 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8304 *last =
8305 ctxt->value->nodesetval->nodeTab[ctxt->value->
8306 nodesetval->nodeNr -
8307 1];
8308 }
8309 cur =
8310 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8311 if ((ctxt->value != NULL)
8312 && (ctxt->value->type == XPATH_NODESET)
8313 && (ctxt->value->nodesetval != NULL)
8314 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8315 }
8316 CHECK_TYPE0(XPATH_NODESET);
8317 arg2 = valuePop(ctxt);
8318
8319 CHECK_TYPE0(XPATH_NODESET);
8320 arg1 = valuePop(ctxt);
8321
8322 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8323 arg2->nodesetval);
8324 valuePush(ctxt, arg1);
8325 xmlXPathFreeObject(arg2);
8326 /* optimizer */
8327 if (total > cur)
8328 xmlXPathCompSwap(op);
8329 return (total + cur);
8330 case XPATH_OP_ROOT:
8331 xmlXPathRoot(ctxt);
8332 return (0);
8333 case XPATH_OP_NODE:
8334 if (op->ch1 != -1)
8335 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8336 if (op->ch2 != -1)
8337 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8338 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8339 return (total);
8340 case XPATH_OP_RESET:
8341 if (op->ch1 != -1)
8342 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8343 if (op->ch2 != -1)
8344 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8345 ctxt->context->node = NULL;
8346 return (total);
8347 case XPATH_OP_COLLECT:{
8348 if (op->ch1 == -1)
8349 return (0);
8350
8351 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8352
8353 /*
8354 * Optimization for [n] selection where n is a number
8355 */
8356 if ((op->ch2 != -1) &&
8357 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8358 (comp->steps[op->ch2].ch1 == -1) &&
8359 (comp->steps[op->ch2].ch2 != -1) &&
8360 (comp->steps[comp->steps[op->ch2].ch2].op ==
8361 XPATH_OP_VALUE)) {
8362 xmlXPathObjectPtr val;
8363
8364 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8365 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8366 int indx = (int) val->floatval;
8367
8368 if (val->floatval == (float) indx) {
8369 total +=
8370 xmlXPathNodeCollectAndTestNth(ctxt, op,
8371 indx, NULL,
8372 last);
8373 return (total);
8374 }
8375 }
8376 }
8377 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8378 return (total);
8379 }
8380 case XPATH_OP_VALUE:
8381 valuePush(ctxt,
8382 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8383 return (0);
8384 case XPATH_OP_SORT:
8385 if (op->ch1 != -1)
8386 total +=
8387 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8388 last);
8389 if ((ctxt->value != NULL)
8390 && (ctxt->value->type == XPATH_NODESET)
8391 && (ctxt->value->nodesetval != NULL))
8392 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8393 return (total);
8394 default:
8395 return (xmlXPathCompOpEval(ctxt, op));
8396 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008397}
8398
Owen Taylor3473f882001-02-23 17:55:21 +00008399/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008400 * xmlXPathCompOpEval:
8401 * @ctxt: the XPath parser context with the compiled expression
8402 * @op: an XPath compiled operation
8403 *
8404 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008405 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008406 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008407static int
8408xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
8409{
8410 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008411 int equal, ret;
8412 xmlXPathCompExprPtr comp;
8413 xmlXPathObjectPtr arg1, arg2;
8414
8415 comp = ctxt->comp;
8416 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008417 case XPATH_OP_END:
8418 return (0);
8419 case XPATH_OP_AND:
8420 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8421 xmlXPathBooleanFunction(ctxt, 1);
8422 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
8423 return (total);
8424 arg2 = valuePop(ctxt);
8425 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8426 xmlXPathBooleanFunction(ctxt, 1);
8427 arg1 = valuePop(ctxt);
8428 arg1->boolval &= arg2->boolval;
8429 valuePush(ctxt, arg1);
8430 xmlXPathFreeObject(arg2);
8431 return (total);
8432 case XPATH_OP_OR:
8433 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8434 xmlXPathBooleanFunction(ctxt, 1);
8435 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
8436 return (total);
8437 arg2 = valuePop(ctxt);
8438 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8439 xmlXPathBooleanFunction(ctxt, 1);
8440 arg1 = valuePop(ctxt);
8441 arg1->boolval |= arg2->boolval;
8442 valuePush(ctxt, arg1);
8443 xmlXPathFreeObject(arg2);
8444 return (total);
8445 case XPATH_OP_EQUAL:
8446 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8447 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8448 equal = xmlXPathEqualValues(ctxt);
8449 if (op->value)
8450 valuePush(ctxt, xmlXPathNewBoolean(equal));
8451 else
8452 valuePush(ctxt, xmlXPathNewBoolean(!equal));
8453 return (total);
8454 case XPATH_OP_CMP:
8455 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8456 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8457 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
8458 valuePush(ctxt, xmlXPathNewBoolean(ret));
8459 return (total);
8460 case XPATH_OP_PLUS:
8461 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8462 if (op->ch2 != -1)
8463 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8464 if (op->value == 0)
8465 xmlXPathSubValues(ctxt);
8466 else if (op->value == 1)
8467 xmlXPathAddValues(ctxt);
8468 else if (op->value == 2)
8469 xmlXPathValueFlipSign(ctxt);
8470 else if (op->value == 3) {
8471 CAST_TO_NUMBER;
8472 CHECK_TYPE0(XPATH_NUMBER);
8473 }
8474 return (total);
8475 case XPATH_OP_MULT:
8476 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8477 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8478 if (op->value == 0)
8479 xmlXPathMultValues(ctxt);
8480 else if (op->value == 1)
8481 xmlXPathDivValues(ctxt);
8482 else if (op->value == 2)
8483 xmlXPathModValues(ctxt);
8484 return (total);
8485 case XPATH_OP_UNION:
8486 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8487 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8488 CHECK_TYPE0(XPATH_NODESET);
8489 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008490
Daniel Veillardf06307e2001-07-03 10:35:50 +00008491 CHECK_TYPE0(XPATH_NODESET);
8492 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008493
Daniel Veillardf06307e2001-07-03 10:35:50 +00008494 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8495 arg2->nodesetval);
8496 valuePush(ctxt, arg1);
8497 xmlXPathFreeObject(arg2);
8498 return (total);
8499 case XPATH_OP_ROOT:
8500 xmlXPathRoot(ctxt);
8501 return (total);
8502 case XPATH_OP_NODE:
8503 if (op->ch1 != -1)
8504 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8505 if (op->ch2 != -1)
8506 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8507 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8508 return (total);
8509 case XPATH_OP_RESET:
8510 if (op->ch1 != -1)
8511 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8512 if (op->ch2 != -1)
8513 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8514 ctxt->context->node = NULL;
8515 return (total);
8516 case XPATH_OP_COLLECT:{
8517 if (op->ch1 == -1)
8518 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008519
Daniel Veillardf06307e2001-07-03 10:35:50 +00008520 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008521
Daniel Veillardf06307e2001-07-03 10:35:50 +00008522 /*
8523 * Optimization for [n] selection where n is a number
8524 */
8525 if ((op->ch2 != -1) &&
8526 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8527 (comp->steps[op->ch2].ch1 == -1) &&
8528 (comp->steps[op->ch2].ch2 != -1) &&
8529 (comp->steps[comp->steps[op->ch2].ch2].op ==
8530 XPATH_OP_VALUE)) {
8531 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00008532
Daniel Veillardf06307e2001-07-03 10:35:50 +00008533 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8534 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8535 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008536
Daniel Veillardf06307e2001-07-03 10:35:50 +00008537 if (val->floatval == (float) indx) {
8538 total +=
8539 xmlXPathNodeCollectAndTestNth(ctxt, op,
8540 indx, NULL,
8541 NULL);
8542 return (total);
8543 }
8544 }
8545 }
8546 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
8547 return (total);
8548 }
8549 case XPATH_OP_VALUE:
8550 valuePush(ctxt,
8551 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8552 return (total);
8553 case XPATH_OP_VARIABLE:{
8554 if (op->ch1 != -1)
8555 total +=
8556 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8557 if (op->value5 == NULL)
8558 valuePush(ctxt,
8559 xmlXPathVariableLookup(ctxt->context,
8560 op->value4));
8561 else {
8562 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008563
Daniel Veillardf06307e2001-07-03 10:35:50 +00008564 URI = xmlXPathNsLookup(ctxt->context, op->value5);
8565 if (URI == NULL) {
8566 xmlGenericError(xmlGenericErrorContext,
8567 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
8568 op->value4, op->value5);
8569 return (total);
8570 }
8571 valuePush(ctxt,
8572 xmlXPathVariableLookupNS(ctxt->context,
8573 op->value4, URI));
8574 }
8575 return (total);
8576 }
8577 case XPATH_OP_FUNCTION:{
8578 xmlXPathFunction func;
8579 const xmlChar *oldFunc, *oldFuncURI;
8580
8581 if (op->ch1 != -1)
8582 total +=
8583 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8584 if (op->cache != NULL)
8585 func = (xmlXPathFunction) op->cache;
8586 else {
8587 const xmlChar *URI = NULL;
8588
8589 if (op->value5 == NULL)
8590 func =
8591 xmlXPathFunctionLookup(ctxt->context,
8592 op->value4);
8593 else {
8594 URI = xmlXPathNsLookup(ctxt->context, op->value5);
8595 if (URI == NULL) {
8596 xmlGenericError(xmlGenericErrorContext,
8597 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
8598 op->value4, op->value5);
8599 return (total);
8600 }
8601 func = xmlXPathFunctionLookupNS(ctxt->context,
8602 op->value4, URI);
8603 }
8604 if (func == NULL) {
8605 xmlGenericError(xmlGenericErrorContext,
8606 "xmlXPathRunEval: function %s not found\n",
8607 op->value4);
8608 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
8609 return (total);
8610 }
8611 op->cache = (void *) func;
8612 op->cacheURI = (void *) URI;
8613 }
8614 oldFunc = ctxt->context->function;
8615 oldFuncURI = ctxt->context->functionURI;
8616 ctxt->context->function = op->value4;
8617 ctxt->context->functionURI = op->cacheURI;
8618 func(ctxt, op->value);
8619 ctxt->context->function = oldFunc;
8620 ctxt->context->functionURI = oldFuncURI;
8621 return (total);
8622 }
8623 case XPATH_OP_ARG:
8624 if (op->ch1 != -1)
8625 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8626 if (op->ch2 != -1)
8627 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8628 return (total);
8629 case XPATH_OP_PREDICATE:
8630 case XPATH_OP_FILTER:{
8631 xmlXPathObjectPtr res;
8632 xmlXPathObjectPtr obj, tmp;
8633 xmlNodeSetPtr newset = NULL;
8634 xmlNodeSetPtr oldset;
8635 xmlNodePtr oldnode;
8636 int i;
8637
8638 /*
8639 * Optimization for ()[1] selection i.e. the first elem
8640 */
8641 if ((op->ch1 != -1) && (op->ch2 != -1) &&
8642 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
8643 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
8644 xmlXPathObjectPtr val;
8645
8646 val = comp->steps[op->ch2].value4;
8647 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
8648 (val->floatval == 1.0)) {
8649 xmlNodePtr first = NULL;
8650
8651 total +=
8652 xmlXPathCompOpEvalFirst(ctxt,
8653 &comp->steps[op->ch1],
8654 &first);
8655 /*
8656 * The nodeset should be in document order,
8657 * Keep only the first value
8658 */
8659 if ((ctxt->value != NULL) &&
8660 (ctxt->value->type == XPATH_NODESET) &&
8661 (ctxt->value->nodesetval != NULL) &&
8662 (ctxt->value->nodesetval->nodeNr > 1))
8663 ctxt->value->nodesetval->nodeNr = 1;
8664 return (total);
8665 }
8666 }
8667 /*
8668 * Optimization for ()[last()] selection i.e. the last elem
8669 */
8670 if ((op->ch1 != -1) && (op->ch2 != -1) &&
8671 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
8672 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
8673 int f = comp->steps[op->ch2].ch1;
8674
8675 if ((f != -1) &&
8676 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
8677 (comp->steps[f].value5 == NULL) &&
8678 (comp->steps[f].value == 0) &&
8679 (comp->steps[f].value4 != NULL) &&
8680 (xmlStrEqual
8681 (comp->steps[f].value4, BAD_CAST "last"))) {
8682 xmlNodePtr last = NULL;
8683
8684 total +=
8685 xmlXPathCompOpEvalLast(ctxt,
8686 &comp->steps[op->ch1],
8687 &last);
8688 /*
8689 * The nodeset should be in document order,
8690 * Keep only the last value
8691 */
8692 if ((ctxt->value != NULL) &&
8693 (ctxt->value->type == XPATH_NODESET) &&
8694 (ctxt->value->nodesetval != NULL) &&
8695 (ctxt->value->nodesetval->nodeTab != NULL) &&
8696 (ctxt->value->nodesetval->nodeNr > 1)) {
8697 ctxt->value->nodesetval->nodeTab[0] =
8698 ctxt->value->nodesetval->nodeTab[ctxt->
8699 value->
8700 nodesetval->
8701 nodeNr -
8702 1];
8703 ctxt->value->nodesetval->nodeNr = 1;
8704 }
8705 return (total);
8706 }
8707 }
8708
8709 if (op->ch1 != -1)
8710 total +=
8711 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8712 if (op->ch2 == -1)
8713 return (total);
8714 if (ctxt->value == NULL)
8715 return (total);
8716
8717 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008718
8719#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00008720 /*
8721 * Hum are we filtering the result of an XPointer expression
8722 */
8723 if (ctxt->value->type == XPATH_LOCATIONSET) {
8724 xmlLocationSetPtr newlocset = NULL;
8725 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008726
Daniel Veillardf06307e2001-07-03 10:35:50 +00008727 /*
8728 * Extract the old locset, and then evaluate the result of the
8729 * expression for all the element in the locset. use it to grow
8730 * up a new locset.
8731 */
8732 CHECK_TYPE0(XPATH_LOCATIONSET);
8733 obj = valuePop(ctxt);
8734 oldlocset = obj->user;
8735 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008736
Daniel Veillardf06307e2001-07-03 10:35:50 +00008737 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
8738 ctxt->context->contextSize = 0;
8739 ctxt->context->proximityPosition = 0;
8740 if (op->ch2 != -1)
8741 total +=
8742 xmlXPathCompOpEval(ctxt,
8743 &comp->steps[op->ch2]);
8744 res = valuePop(ctxt);
8745 if (res != NULL)
8746 xmlXPathFreeObject(res);
8747 valuePush(ctxt, obj);
8748 CHECK_ERROR0;
8749 return (total);
8750 }
8751 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008752
Daniel Veillardf06307e2001-07-03 10:35:50 +00008753 for (i = 0; i < oldlocset->locNr; i++) {
8754 /*
8755 * Run the evaluation with a node list made of a
8756 * single item in the nodelocset.
8757 */
8758 ctxt->context->node = oldlocset->locTab[i]->user;
8759 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8760 valuePush(ctxt, tmp);
8761 ctxt->context->contextSize = oldlocset->locNr;
8762 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008763
Daniel Veillardf06307e2001-07-03 10:35:50 +00008764 if (op->ch2 != -1)
8765 total +=
8766 xmlXPathCompOpEval(ctxt,
8767 &comp->steps[op->ch2]);
8768 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008769
Daniel Veillardf06307e2001-07-03 10:35:50 +00008770 /*
8771 * The result of the evaluation need to be tested to
8772 * decided whether the filter succeeded or not
8773 */
8774 res = valuePop(ctxt);
8775 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
8776 xmlXPtrLocationSetAdd(newlocset,
8777 xmlXPathObjectCopy
8778 (oldlocset->locTab[i]));
8779 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008780
Daniel Veillardf06307e2001-07-03 10:35:50 +00008781 /*
8782 * Cleanup
8783 */
8784 if (res != NULL)
8785 xmlXPathFreeObject(res);
8786 if (ctxt->value == tmp) {
8787 res = valuePop(ctxt);
8788 xmlXPathFreeObject(res);
8789 }
8790
8791 ctxt->context->node = NULL;
8792 }
8793
8794 /*
8795 * The result is used as the new evaluation locset.
8796 */
8797 xmlXPathFreeObject(obj);
8798 ctxt->context->node = NULL;
8799 ctxt->context->contextSize = -1;
8800 ctxt->context->proximityPosition = -1;
8801 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
8802 ctxt->context->node = oldnode;
8803 return (total);
8804 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008805#endif /* LIBXML_XPTR_ENABLED */
8806
Daniel Veillardf06307e2001-07-03 10:35:50 +00008807 /*
8808 * Extract the old set, and then evaluate the result of the
8809 * expression for all the element in the set. use it to grow
8810 * up a new set.
8811 */
8812 CHECK_TYPE0(XPATH_NODESET);
8813 obj = valuePop(ctxt);
8814 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00008815
Daniel Veillardf06307e2001-07-03 10:35:50 +00008816 oldnode = ctxt->context->node;
8817 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008818
Daniel Veillardf06307e2001-07-03 10:35:50 +00008819 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
8820 ctxt->context->contextSize = 0;
8821 ctxt->context->proximityPosition = 0;
8822 if (op->ch2 != -1)
8823 total +=
8824 xmlXPathCompOpEval(ctxt,
8825 &comp->steps[op->ch2]);
8826 res = valuePop(ctxt);
8827 if (res != NULL)
8828 xmlXPathFreeObject(res);
8829 valuePush(ctxt, obj);
8830 ctxt->context->node = oldnode;
8831 CHECK_ERROR0;
8832 } else {
8833 /*
8834 * Initialize the new set.
8835 */
8836 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008837
Daniel Veillardf06307e2001-07-03 10:35:50 +00008838 for (i = 0; i < oldset->nodeNr; i++) {
8839 /*
8840 * Run the evaluation with a node list made of
8841 * a single item in the nodeset.
8842 */
8843 ctxt->context->node = oldset->nodeTab[i];
8844 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8845 valuePush(ctxt, tmp);
8846 ctxt->context->contextSize = oldset->nodeNr;
8847 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008848
Daniel Veillardf06307e2001-07-03 10:35:50 +00008849 if (op->ch2 != -1)
8850 total +=
8851 xmlXPathCompOpEval(ctxt,
8852 &comp->steps[op->ch2]);
8853 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008854
Daniel Veillardf06307e2001-07-03 10:35:50 +00008855 /*
8856 * The result of the evaluation need to be tested to
8857 * decided whether the filter succeeded or not
8858 */
8859 res = valuePop(ctxt);
8860 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
8861 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
8862 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008863
Daniel Veillardf06307e2001-07-03 10:35:50 +00008864 /*
8865 * Cleanup
8866 */
8867 if (res != NULL)
8868 xmlXPathFreeObject(res);
8869 if (ctxt->value == tmp) {
8870 res = valuePop(ctxt);
8871 xmlXPathFreeObject(res);
8872 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008873
Daniel Veillardf06307e2001-07-03 10:35:50 +00008874 ctxt->context->node = NULL;
8875 }
8876
8877 /*
8878 * The result is used as the new evaluation set.
8879 */
8880 xmlXPathFreeObject(obj);
8881 ctxt->context->node = NULL;
8882 ctxt->context->contextSize = -1;
8883 ctxt->context->proximityPosition = -1;
8884 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
8885 }
8886 ctxt->context->node = oldnode;
8887 return (total);
8888 }
8889 case XPATH_OP_SORT:
8890 if (op->ch1 != -1)
8891 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8892 if ((ctxt->value != NULL) &&
8893 (ctxt->value->type == XPATH_NODESET) &&
8894 (ctxt->value->nodesetval != NULL))
8895 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8896 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008897#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00008898 case XPATH_OP_RANGETO:{
8899 xmlXPathObjectPtr range;
8900 xmlXPathObjectPtr res, obj;
8901 xmlXPathObjectPtr tmp;
8902 xmlLocationSetPtr newset = NULL;
8903 xmlNodeSetPtr oldset;
8904 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008905
Daniel Veillardf06307e2001-07-03 10:35:50 +00008906 if (op->ch1 != -1)
8907 total +=
8908 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8909 if (op->ch2 == -1)
8910 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008911
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 CHECK_TYPE0(XPATH_NODESET);
8913 obj = valuePop(ctxt);
8914 oldset = obj->nodesetval;
8915 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008916
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008918
Daniel Veillardf06307e2001-07-03 10:35:50 +00008919 if (oldset != NULL) {
8920 for (i = 0; i < oldset->nodeNr; i++) {
8921 /*
8922 * Run the evaluation with a node list made of a single item
8923 * in the nodeset.
8924 */
8925 ctxt->context->node = oldset->nodeTab[i];
8926 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8927 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008928
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 if (op->ch2 != -1)
8930 total +=
8931 xmlXPathCompOpEval(ctxt,
8932 &comp->steps[op->ch2]);
8933 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008934
Daniel Veillardf06307e2001-07-03 10:35:50 +00008935 /*
8936 * The result of the evaluation need to be tested to
8937 * decided whether the filter succeeded or not
8938 */
8939 res = valuePop(ctxt);
8940 range =
8941 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
8942 res);
8943 if (range != NULL) {
8944 xmlXPtrLocationSetAdd(newset, range);
8945 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008946
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 /*
8948 * Cleanup
8949 */
8950 if (res != NULL)
8951 xmlXPathFreeObject(res);
8952 if (ctxt->value == tmp) {
8953 res = valuePop(ctxt);
8954 xmlXPathFreeObject(res);
8955 }
8956
8957 ctxt->context->node = NULL;
8958 }
8959 }
8960
8961 /*
8962 * The result is used as the new evaluation set.
8963 */
8964 xmlXPathFreeObject(obj);
8965 ctxt->context->node = NULL;
8966 ctxt->context->contextSize = -1;
8967 ctxt->context->proximityPosition = -1;
8968 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
8969 return (total);
8970 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008971#endif /* LIBXML_XPTR_ENABLED */
8972 }
8973 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 "XPath: unknown precompiled operation %d\n", op->op);
8975 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008976}
8977
8978/**
8979 * xmlXPathRunEval:
8980 * @ctxt: the XPath parser context with the compiled expression
8981 *
8982 * Evaluate the Precompiled XPath expression in the given context.
8983 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008984static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008985xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
8986 xmlXPathCompExprPtr comp;
8987
8988 if ((ctxt == NULL) || (ctxt->comp == NULL))
8989 return;
8990
8991 if (ctxt->valueTab == NULL) {
8992 /* Allocate the value stack */
8993 ctxt->valueTab = (xmlXPathObjectPtr *)
8994 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
8995 if (ctxt->valueTab == NULL) {
8996 xmlFree(ctxt);
8997 xmlGenericError(xmlGenericErrorContext,
8998 "xmlXPathRunEval: out of memory\n");
8999 return;
9000 }
9001 ctxt->valueNr = 0;
9002 ctxt->valueMax = 10;
9003 ctxt->value = NULL;
9004 }
9005 comp = ctxt->comp;
9006 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9007}
9008
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009009/************************************************************************
9010 * *
9011 * Public interfaces *
9012 * *
9013 ************************************************************************/
9014
9015/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009016 * xmlXPathEvalPredicate:
9017 * @ctxt: the XPath context
9018 * @res: the Predicate Expression evaluation result
9019 *
9020 * Evaluate a predicate result for the current node.
9021 * A PredicateExpr is evaluated by evaluating the Expr and converting
9022 * the result to a boolean. If the result is a number, the result will
9023 * be converted to true if the number is equal to the position of the
9024 * context node in the context node list (as returned by the position
9025 * function) and will be converted to false otherwise; if the result
9026 * is not a number, then the result will be converted as if by a call
9027 * to the boolean function.
9028 *
9029 * Return 1 if predicate is true, 0 otherwise
9030 */
9031int
9032xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9033 if (res == NULL) return(0);
9034 switch (res->type) {
9035 case XPATH_BOOLEAN:
9036 return(res->boolval);
9037 case XPATH_NUMBER:
9038 return(res->floatval == ctxt->proximityPosition);
9039 case XPATH_NODESET:
9040 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009041 if (res->nodesetval == NULL)
9042 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009043 return(res->nodesetval->nodeNr != 0);
9044 case XPATH_STRING:
9045 return((res->stringval != NULL) &&
9046 (xmlStrlen(res->stringval) != 0));
9047 default:
9048 STRANGE
9049 }
9050 return(0);
9051}
9052
9053/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009054 * xmlXPathEvaluatePredicateResult:
9055 * @ctxt: the XPath Parser context
9056 * @res: the Predicate Expression evaluation result
9057 *
9058 * Evaluate a predicate result for the current node.
9059 * A PredicateExpr is evaluated by evaluating the Expr and converting
9060 * the result to a boolean. If the result is a number, the result will
9061 * be converted to true if the number is equal to the position of the
9062 * context node in the context node list (as returned by the position
9063 * function) and will be converted to false otherwise; if the result
9064 * is not a number, then the result will be converted as if by a call
9065 * to the boolean function.
9066 *
9067 * Return 1 if predicate is true, 0 otherwise
9068 */
9069int
9070xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9071 xmlXPathObjectPtr res) {
9072 if (res == NULL) return(0);
9073 switch (res->type) {
9074 case XPATH_BOOLEAN:
9075 return(res->boolval);
9076 case XPATH_NUMBER:
9077 return(res->floatval == ctxt->context->proximityPosition);
9078 case XPATH_NODESET:
9079 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009080 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009081 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009082 return(res->nodesetval->nodeNr != 0);
9083 case XPATH_STRING:
9084 return((res->stringval != NULL) &&
9085 (xmlStrlen(res->stringval) != 0));
9086 default:
9087 STRANGE
9088 }
9089 return(0);
9090}
9091
9092/**
9093 * xmlXPathCompile:
9094 * @str: the XPath expression
9095 *
9096 * Compile an XPath expression
9097 *
9098 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9099 * the caller has to free the object.
9100 */
9101xmlXPathCompExprPtr
9102xmlXPathCompile(const xmlChar *str) {
9103 xmlXPathParserContextPtr ctxt;
9104 xmlXPathCompExprPtr comp;
9105
9106 xmlXPathInit();
9107
9108 ctxt = xmlXPathNewParserContext(str, NULL);
9109 xmlXPathCompileExpr(ctxt);
9110
Daniel Veillard40af6492001-04-22 08:50:55 +00009111 if (*ctxt->cur != 0) {
9112 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9113 comp = NULL;
9114 } else {
9115 comp = ctxt->comp;
9116 ctxt->comp = NULL;
9117 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009118 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009119#ifdef DEBUG_EVAL_COUNTS
9120 if (comp != NULL) {
9121 comp->string = xmlStrdup(str);
9122 comp->nb = 0;
9123 }
9124#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009125 return(comp);
9126}
9127
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009128/**
9129 * xmlXPathCompiledEval:
9130 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009131 * @ctx: the XPath context
9132 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009133 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009134 *
9135 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9136 * the caller has to free the object.
9137 */
9138xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009139xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009140 xmlXPathParserContextPtr ctxt;
9141 xmlXPathObjectPtr res, tmp, init = NULL;
9142 int stack = 0;
9143
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009144 if ((comp == NULL) || (ctx == NULL))
9145 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009146 xmlXPathInit();
9147
9148 CHECK_CONTEXT(ctx)
9149
Daniel Veillardf06307e2001-07-03 10:35:50 +00009150#ifdef DEBUG_EVAL_COUNTS
9151 comp->nb++;
9152 if ((comp->string != NULL) && (comp->nb > 100)) {
9153 fprintf(stderr, "100 x %s\n", comp->string);
9154 comp->nb = 0;
9155 }
9156#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009157 ctxt = xmlXPathCompParserContext(comp, ctx);
9158 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009159
9160 if (ctxt->value == NULL) {
9161 xmlGenericError(xmlGenericErrorContext,
9162 "xmlXPathEval: evaluation failed\n");
9163 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009164 } else {
9165 res = valuePop(ctxt);
9166 }
9167
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168
Owen Taylor3473f882001-02-23 17:55:21 +00009169 do {
9170 tmp = valuePop(ctxt);
9171 if (tmp != NULL) {
9172 if (tmp != init)
9173 stack++;
9174 xmlXPathFreeObject(tmp);
9175 }
9176 } while (tmp != NULL);
9177 if ((stack != 0) && (res != NULL)) {
9178 xmlGenericError(xmlGenericErrorContext,
9179 "xmlXPathEval: %d object left on the stack\n",
9180 stack);
9181 }
9182 if (ctxt->error != XPATH_EXPRESSION_OK) {
9183 xmlXPathFreeObject(res);
9184 res = NULL;
9185 }
9186
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009187
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009188 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009189 xmlXPathFreeParserContext(ctxt);
9190 return(res);
9191}
9192
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009193/**
9194 * xmlXPathEvalExpr:
9195 * @ctxt: the XPath Parser context
9196 *
9197 * Parse and evaluate an XPath expression in the given context,
9198 * then push the result on the context stack
9199 */
9200void
9201xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9202 xmlXPathCompileExpr(ctxt);
9203 xmlXPathRunEval(ctxt);
9204}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009205
9206/**
9207 * xmlXPathEval:
9208 * @str: the XPath expression
9209 * @ctx: the XPath context
9210 *
9211 * Evaluate the XPath Location Path in the given context.
9212 *
9213 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9214 * the caller has to free the object.
9215 */
9216xmlXPathObjectPtr
9217xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9218 xmlXPathParserContextPtr ctxt;
9219 xmlXPathObjectPtr res, tmp, init = NULL;
9220 int stack = 0;
9221
9222 xmlXPathInit();
9223
9224 CHECK_CONTEXT(ctx)
9225
9226 ctxt = xmlXPathNewParserContext(str, ctx);
9227 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009228
9229 if (ctxt->value == NULL) {
9230 xmlGenericError(xmlGenericErrorContext,
9231 "xmlXPathEval: evaluation failed\n");
9232 res = NULL;
9233 } else if (*ctxt->cur != 0) {
9234 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9235 res = NULL;
9236 } else {
9237 res = valuePop(ctxt);
9238 }
9239
9240 do {
9241 tmp = valuePop(ctxt);
9242 if (tmp != NULL) {
9243 if (tmp != init)
9244 stack++;
9245 xmlXPathFreeObject(tmp);
9246 }
9247 } while (tmp != NULL);
9248 if ((stack != 0) && (res != NULL)) {
9249 xmlGenericError(xmlGenericErrorContext,
9250 "xmlXPathEval: %d object left on the stack\n",
9251 stack);
9252 }
9253 if (ctxt->error != XPATH_EXPRESSION_OK) {
9254 xmlXPathFreeObject(res);
9255 res = NULL;
9256 }
9257
Owen Taylor3473f882001-02-23 17:55:21 +00009258 xmlXPathFreeParserContext(ctxt);
9259 return(res);
9260}
9261
9262/**
9263 * xmlXPathEvalExpression:
9264 * @str: the XPath expression
9265 * @ctxt: the XPath context
9266 *
9267 * Evaluate the XPath expression in the given context.
9268 *
9269 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9270 * the caller has to free the object.
9271 */
9272xmlXPathObjectPtr
9273xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9274 xmlXPathParserContextPtr pctxt;
9275 xmlXPathObjectPtr res, tmp;
9276 int stack = 0;
9277
9278 xmlXPathInit();
9279
9280 CHECK_CONTEXT(ctxt)
9281
9282 pctxt = xmlXPathNewParserContext(str, ctxt);
9283 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009284
9285 if (*pctxt->cur != 0) {
9286 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9287 res = NULL;
9288 } else {
9289 res = valuePop(pctxt);
9290 }
9291 do {
9292 tmp = valuePop(pctxt);
9293 if (tmp != NULL) {
9294 xmlXPathFreeObject(tmp);
9295 stack++;
9296 }
9297 } while (tmp != NULL);
9298 if ((stack != 0) && (res != NULL)) {
9299 xmlGenericError(xmlGenericErrorContext,
9300 "xmlXPathEvalExpression: %d object left on the stack\n",
9301 stack);
9302 }
9303 xmlXPathFreeParserContext(pctxt);
9304 return(res);
9305}
9306
9307/**
9308 * xmlXPathRegisterAllFunctions:
9309 * @ctxt: the XPath context
9310 *
9311 * Registers all default XPath functions in this context
9312 */
9313void
9314xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9315{
9316 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9317 xmlXPathBooleanFunction);
9318 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9319 xmlXPathCeilingFunction);
9320 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9321 xmlXPathCountFunction);
9322 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9323 xmlXPathConcatFunction);
9324 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9325 xmlXPathContainsFunction);
9326 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9327 xmlXPathIdFunction);
9328 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9329 xmlXPathFalseFunction);
9330 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9331 xmlXPathFloorFunction);
9332 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9333 xmlXPathLastFunction);
9334 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9335 xmlXPathLangFunction);
9336 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9337 xmlXPathLocalNameFunction);
9338 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9339 xmlXPathNotFunction);
9340 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9341 xmlXPathNameFunction);
9342 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9343 xmlXPathNamespaceURIFunction);
9344 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9345 xmlXPathNormalizeFunction);
9346 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9347 xmlXPathNumberFunction);
9348 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9349 xmlXPathPositionFunction);
9350 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9351 xmlXPathRoundFunction);
9352 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9353 xmlXPathStringFunction);
9354 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9355 xmlXPathStringLengthFunction);
9356 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9357 xmlXPathStartsWithFunction);
9358 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9359 xmlXPathSubstringFunction);
9360 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9361 xmlXPathSubstringBeforeFunction);
9362 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9363 xmlXPathSubstringAfterFunction);
9364 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9365 xmlXPathSumFunction);
9366 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9367 xmlXPathTrueFunction);
9368 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9369 xmlXPathTranslateFunction);
9370}
9371
9372#endif /* LIBXML_XPATH_ENABLED */