blob: 39e05831ac4585c1de1247d9792eb5b6f3fb9f5c [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
Daniel Veillard8c357d52001-07-03 23:43:33 +00001954 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
1955 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00001956}
1957
1958/**
1959 * xmlXPathRegisteredVariablesCleanup:
1960 * @ctxt: the XPath context
1961 *
1962 * Cleanup the XPath context data associated to registered variables
1963 */
1964void
1965xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1966 if (ctxt == NULL)
1967 return;
1968
Daniel Veillard76d66f42001-05-16 21:05:17 +00001969 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00001970 ctxt->varHash = NULL;
1971}
1972
1973/**
1974 * xmlXPathRegisterNs:
1975 * @ctxt: the XPath context
1976 * @prefix: the namespace prefix
1977 * @ns_uri: the namespace name
1978 *
1979 * Register a new namespace. If @ns_uri is NULL it unregisters
1980 * the namespace
1981 *
1982 * Returns 0 in case of success, -1 in case of error
1983 */
1984int
1985xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1986 const xmlChar *ns_uri) {
1987 if (ctxt == NULL)
1988 return(-1);
1989 if (prefix == NULL)
1990 return(-1);
1991
1992 if (ctxt->nsHash == NULL)
1993 ctxt->nsHash = xmlHashCreate(10);
1994 if (ctxt->nsHash == NULL)
1995 return(-1);
1996 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1997 (xmlHashDeallocator)xmlFree));
1998}
1999
2000/**
2001 * xmlXPathNsLookup:
2002 * @ctxt: the XPath context
2003 * @prefix: the namespace prefix value
2004 *
2005 * Search in the namespace declaration array of the context for the given
2006 * namespace name associated to the given prefix
2007 *
2008 * Returns the value or NULL if not found
2009 */
2010const xmlChar *
2011xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2012 if (ctxt == NULL)
2013 return(NULL);
2014 if (prefix == NULL)
2015 return(NULL);
2016
2017#ifdef XML_XML_NAMESPACE
2018 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2019 return(XML_XML_NAMESPACE);
2020#endif
2021
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002022 if (ctxt->namespaces != NULL) {
2023 int i;
2024
2025 for (i = 0;i < ctxt->nsNr;i++) {
2026 if ((ctxt->namespaces[i] != NULL) &&
2027 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2028 return(ctxt->namespaces[i]->href);
2029 }
2030 }
Owen Taylor3473f882001-02-23 17:55:21 +00002031
2032 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2033}
2034
2035/**
2036 * xmlXPathRegisteredVariablesCleanup:
2037 * @ctxt: the XPath context
2038 *
2039 * Cleanup the XPath context data associated to registered variables
2040 */
2041void
2042xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2043 if (ctxt == NULL)
2044 return;
2045
2046 xmlHashFree(ctxt->nsHash, NULL);
2047 ctxt->nsHash = NULL;
2048}
2049
2050/************************************************************************
2051 * *
2052 * Routines to handle Values *
2053 * *
2054 ************************************************************************/
2055
2056/* Allocations are terrible, one need to optimize all this !!! */
2057
2058/**
2059 * xmlXPathNewFloat:
2060 * @val: the double value
2061 *
2062 * Create a new xmlXPathObjectPtr of type double and of value @val
2063 *
2064 * Returns the newly created object.
2065 */
2066xmlXPathObjectPtr
2067xmlXPathNewFloat(double val) {
2068 xmlXPathObjectPtr ret;
2069
2070 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2071 if (ret == NULL) {
2072 xmlGenericError(xmlGenericErrorContext,
2073 "xmlXPathNewFloat: out of memory\n");
2074 return(NULL);
2075 }
2076 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2077 ret->type = XPATH_NUMBER;
2078 ret->floatval = val;
2079 return(ret);
2080}
2081
2082/**
2083 * xmlXPathNewBoolean:
2084 * @val: the boolean value
2085 *
2086 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2087 *
2088 * Returns the newly created object.
2089 */
2090xmlXPathObjectPtr
2091xmlXPathNewBoolean(int val) {
2092 xmlXPathObjectPtr ret;
2093
2094 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2095 if (ret == NULL) {
2096 xmlGenericError(xmlGenericErrorContext,
2097 "xmlXPathNewBoolean: out of memory\n");
2098 return(NULL);
2099 }
2100 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2101 ret->type = XPATH_BOOLEAN;
2102 ret->boolval = (val != 0);
2103 return(ret);
2104}
2105
2106/**
2107 * xmlXPathNewString:
2108 * @val: the xmlChar * value
2109 *
2110 * Create a new xmlXPathObjectPtr of type string and of value @val
2111 *
2112 * Returns the newly created object.
2113 */
2114xmlXPathObjectPtr
2115xmlXPathNewString(const xmlChar *val) {
2116 xmlXPathObjectPtr ret;
2117
2118 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2119 if (ret == NULL) {
2120 xmlGenericError(xmlGenericErrorContext,
2121 "xmlXPathNewString: out of memory\n");
2122 return(NULL);
2123 }
2124 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2125 ret->type = XPATH_STRING;
2126 if (val != NULL)
2127 ret->stringval = xmlStrdup(val);
2128 else
2129 ret->stringval = xmlStrdup((const xmlChar *)"");
2130 return(ret);
2131}
2132
2133/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002134 * xmlXPathWrapString:
2135 * @val: the xmlChar * value
2136 *
2137 * Wraps the @val string into an XPath object.
2138 *
2139 * Returns the newly created object.
2140 */
2141xmlXPathObjectPtr
2142xmlXPathWrapString (xmlChar *val) {
2143 xmlXPathObjectPtr ret;
2144
2145 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2146 if (ret == NULL) {
2147 xmlGenericError(xmlGenericErrorContext,
2148 "xmlXPathWrapString: out of memory\n");
2149 return(NULL);
2150 }
2151 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2152 ret->type = XPATH_STRING;
2153 ret->stringval = val;
2154 return(ret);
2155}
2156
2157/**
Owen Taylor3473f882001-02-23 17:55:21 +00002158 * xmlXPathNewCString:
2159 * @val: the char * value
2160 *
2161 * Create a new xmlXPathObjectPtr of type string and of value @val
2162 *
2163 * Returns the newly created object.
2164 */
2165xmlXPathObjectPtr
2166xmlXPathNewCString(const char *val) {
2167 xmlXPathObjectPtr ret;
2168
2169 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2170 if (ret == NULL) {
2171 xmlGenericError(xmlGenericErrorContext,
2172 "xmlXPathNewCString: out of memory\n");
2173 return(NULL);
2174 }
2175 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2176 ret->type = XPATH_STRING;
2177 ret->stringval = xmlStrdup(BAD_CAST val);
2178 return(ret);
2179}
2180
2181/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002182 * xmlXPathWrapCString:
2183 * @val: the char * value
2184 *
2185 * Wraps a string into an XPath object.
2186 *
2187 * Returns the newly created object.
2188 */
2189xmlXPathObjectPtr
2190xmlXPathWrapCString (char * val) {
2191 return(xmlXPathWrapString((xmlChar *)(val)));
2192}
2193
2194/**
Owen Taylor3473f882001-02-23 17:55:21 +00002195 * xmlXPathObjectCopy:
2196 * @val: the original object
2197 *
2198 * allocate a new copy of a given object
2199 *
2200 * Returns the newly created object.
2201 */
2202xmlXPathObjectPtr
2203xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2204 xmlXPathObjectPtr ret;
2205
2206 if (val == NULL)
2207 return(NULL);
2208
2209 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2210 if (ret == NULL) {
2211 xmlGenericError(xmlGenericErrorContext,
2212 "xmlXPathObjectCopy: out of memory\n");
2213 return(NULL);
2214 }
2215 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2216 switch (val->type) {
2217 case XPATH_BOOLEAN:
2218 case XPATH_NUMBER:
2219 case XPATH_POINT:
2220 case XPATH_RANGE:
2221 break;
2222 case XPATH_STRING:
2223 ret->stringval = xmlStrdup(val->stringval);
2224 break;
2225 case XPATH_XSLT_TREE:
2226 if ((val->nodesetval != NULL) &&
2227 (val->nodesetval->nodeTab != NULL))
2228 ret->nodesetval = xmlXPathNodeSetCreate(
2229 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2230 else
2231 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2232 break;
2233 case XPATH_NODESET:
2234 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2235 break;
2236 case XPATH_LOCATIONSET:
2237#ifdef LIBXML_XPTR_ENABLED
2238 {
2239 xmlLocationSetPtr loc = val->user;
2240 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2241 break;
2242 }
2243#endif
2244 case XPATH_UNDEFINED:
2245 case XPATH_USERS:
2246 xmlGenericError(xmlGenericErrorContext,
2247 "xmlXPathObjectCopy: unsupported type %d\n",
2248 val->type);
2249 break;
2250 }
2251 return(ret);
2252}
2253
2254/**
2255 * xmlXPathFreeObject:
2256 * @obj: the object to free
2257 *
2258 * Free up an xmlXPathObjectPtr object.
2259 */
2260void
2261xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2262 if (obj == NULL) return;
2263 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002264 if (obj->boolval) {
2265 obj->type = XPATH_XSLT_TREE;
2266 if (obj->nodesetval != NULL)
2267 xmlXPathFreeValueTree(obj->nodesetval);
2268 } else {
2269 if (obj->nodesetval != NULL)
2270 xmlXPathFreeNodeSet(obj->nodesetval);
2271 }
Owen Taylor3473f882001-02-23 17:55:21 +00002272#ifdef LIBXML_XPTR_ENABLED
2273 } else if (obj->type == XPATH_LOCATIONSET) {
2274 if (obj->user != NULL)
2275 xmlXPtrFreeLocationSet(obj->user);
2276#endif
2277 } else if (obj->type == XPATH_STRING) {
2278 if (obj->stringval != NULL)
2279 xmlFree(obj->stringval);
2280 } else if (obj->type == XPATH_XSLT_TREE) {
2281 if (obj->nodesetval != NULL)
2282 xmlXPathFreeValueTree(obj->nodesetval);
2283 }
2284
Owen Taylor3473f882001-02-23 17:55:21 +00002285 xmlFree(obj);
2286}
2287
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002288
2289/************************************************************************
2290 * *
2291 * Type Casting Routines *
2292 * *
2293 ************************************************************************/
2294
2295/**
2296 * xmlXPathCastBooleanToString:
2297 * @val: a boolean
2298 *
2299 * Converts a boolean to its string value.
2300 *
2301 * Returns a newly allocated string.
2302 */
2303xmlChar *
2304xmlXPathCastBooleanToString (int val) {
2305 xmlChar *ret;
2306 if (val)
2307 ret = xmlStrdup((const xmlChar *) "true");
2308 else
2309 ret = xmlStrdup((const xmlChar *) "false");
2310 return(ret);
2311}
2312
2313/**
2314 * xmlXPathCastNumberToString:
2315 * @val: a number
2316 *
2317 * Converts a number to its string value.
2318 *
2319 * Returns a newly allocated string.
2320 */
2321xmlChar *
2322xmlXPathCastNumberToString (double val) {
2323 xmlChar *ret;
2324 switch (isinf(val)) {
2325 case 1:
2326 ret = xmlStrdup((const xmlChar *) "+Infinity");
2327 break;
2328 case -1:
2329 ret = xmlStrdup((const xmlChar *) "-Infinity");
2330 break;
2331 default:
2332 if (isnan(val)) {
2333 ret = xmlStrdup((const xmlChar *) "NaN");
2334 } else {
2335 /* could be improved */
2336 char buf[100];
2337 xmlXPathFormatNumber(val, buf, 100);
2338 ret = xmlStrdup((const xmlChar *) buf);
2339 }
2340 }
2341 return(ret);
2342}
2343
2344/**
2345 * xmlXPathCastNodeToString:
2346 * @node: a node
2347 *
2348 * Converts a node to its string value.
2349 *
2350 * Returns a newly allocated string.
2351 */
2352xmlChar *
2353xmlXPathCastNodeToString (xmlNodePtr node) {
2354 return(xmlNodeGetContent(node));
2355}
2356
2357/**
2358 * xmlXPathCastNodeSetToString:
2359 * @ns: a node-set
2360 *
2361 * Converts a node-set to its string value.
2362 *
2363 * Returns a newly allocated string.
2364 */
2365xmlChar *
2366xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2367 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2368 return(xmlStrdup((const xmlChar *) ""));
2369
2370 xmlXPathNodeSetSort(ns);
2371 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2372}
2373
2374/**
2375 * xmlXPathCastToString:
2376 * @val: an XPath object
2377 *
2378 * Converts an existing object to its string() equivalent
2379 *
2380 * Returns the string value of the object, NULL in case of error.
2381 * A new string is allocated only if needed (val isn't a
2382 * string object).
2383 */
2384xmlChar *
2385xmlXPathCastToString(xmlXPathObjectPtr val) {
2386 xmlChar *ret = NULL;
2387
2388 if (val == NULL)
2389 return(xmlStrdup((const xmlChar *) ""));
2390 switch (val->type) {
2391 case XPATH_UNDEFINED:
2392#ifdef DEBUG_EXPR
2393 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2394#endif
2395 ret = xmlStrdup((const xmlChar *) "");
2396 break;
2397 case XPATH_XSLT_TREE:
2398 case XPATH_NODESET:
2399 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2400 break;
2401 case XPATH_STRING:
2402 return(val->stringval);
2403 case XPATH_BOOLEAN:
2404 ret = xmlXPathCastBooleanToString(val->boolval);
2405 break;
2406 case XPATH_NUMBER: {
2407 ret = xmlXPathCastNumberToString(val->floatval);
2408 break;
2409 }
2410 case XPATH_USERS:
2411 case XPATH_POINT:
2412 case XPATH_RANGE:
2413 case XPATH_LOCATIONSET:
2414 TODO
2415 ret = xmlStrdup((const xmlChar *) "");
2416 break;
2417 }
2418 return(ret);
2419}
2420
2421/**
2422 * xmlXPathConvertString:
2423 * @val: an XPath object
2424 *
2425 * Converts an existing object to its string() equivalent
2426 *
2427 * Returns the new object, the old one is freed (or the operation
2428 * is done directly on @val)
2429 */
2430xmlXPathObjectPtr
2431xmlXPathConvertString(xmlXPathObjectPtr val) {
2432 xmlChar *res = NULL;
2433
2434 if (val == NULL)
2435 return(xmlXPathNewCString(""));
2436
2437 switch (val->type) {
2438 case XPATH_UNDEFINED:
2439#ifdef DEBUG_EXPR
2440 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2441#endif
2442 break;
2443 case XPATH_XSLT_TREE:
2444 case XPATH_NODESET:
2445 res = xmlXPathCastNodeSetToString(val->nodesetval);
2446 break;
2447 case XPATH_STRING:
2448 return(val);
2449 case XPATH_BOOLEAN:
2450 res = xmlXPathCastBooleanToString(val->boolval);
2451 break;
2452 case XPATH_NUMBER:
2453 res = xmlXPathCastNumberToString(val->floatval);
2454 break;
2455 case XPATH_USERS:
2456 case XPATH_POINT:
2457 case XPATH_RANGE:
2458 case XPATH_LOCATIONSET:
2459 TODO;
2460 break;
2461 }
2462 xmlXPathFreeObject(val);
2463 if (res == NULL)
2464 return(xmlXPathNewCString(""));
2465 return(xmlXPathWrapString(res));
2466}
2467
2468/**
2469 * xmlXPathCastBooleanToNumber:
2470 * @val: a boolean
2471 *
2472 * Converts a boolean to its number value
2473 *
2474 * Returns the number value
2475 */
2476double
2477xmlXPathCastBooleanToNumber(int val) {
2478 if (val)
2479 return(1.0);
2480 return(0.0);
2481}
2482
2483/**
2484 * xmlXPathCastStringToNumber:
2485 * @val: a string
2486 *
2487 * Converts a string to its number value
2488 *
2489 * Returns the number value
2490 */
2491double
2492xmlXPathCastStringToNumber(const xmlChar * val) {
2493 return(xmlXPathStringEvalNumber(val));
2494}
2495
2496/**
2497 * xmlXPathCastNodeToNumber:
2498 * @node: a node
2499 *
2500 * Converts a node to its number value
2501 *
2502 * Returns the number value
2503 */
2504double
2505xmlXPathCastNodeToNumber (xmlNodePtr node) {
2506 xmlChar *strval;
2507 double ret;
2508
2509 if (node == NULL)
2510 return(xmlXPathNAN);
2511 strval = xmlXPathCastNodeToString(node);
2512 if (strval == NULL)
2513 return(xmlXPathNAN);
2514 ret = xmlXPathCastStringToNumber(strval);
2515 xmlFree(strval);
2516
2517 return(ret);
2518}
2519
2520/**
2521 * xmlXPathCastNodeSetToNumber:
2522 * @ns: a node-set
2523 *
2524 * Converts a node-set to its number value
2525 *
2526 * Returns the number value
2527 */
2528double
2529xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
2530 xmlChar *str;
2531 double ret;
2532
2533 if (ns == NULL)
2534 return(xmlXPathNAN);
2535 str = xmlXPathCastNodeSetToString(ns);
2536 ret = xmlXPathCastStringToNumber(str);
2537 xmlFree(str);
2538 return(ret);
2539}
2540
2541/**
2542 * xmlXPathCastToNumber:
2543 * @val: an XPath object
2544 *
2545 * Converts an XPath object to its number value
2546 *
2547 * Returns the number value
2548 */
2549double
2550xmlXPathCastToNumber(xmlXPathObjectPtr val) {
2551 double ret = 0.0;
2552
2553 if (val == NULL)
2554 return(xmlXPathNAN);
2555 switch (val->type) {
2556 case XPATH_UNDEFINED:
2557#ifdef DEGUB_EXPR
2558 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
2559#endif
2560 ret = xmlXPathNAN;
2561 break;
2562 case XPATH_XSLT_TREE:
2563 case XPATH_NODESET:
2564 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
2565 break;
2566 case XPATH_STRING:
2567 ret = xmlXPathCastStringToNumber(val->stringval);
2568 break;
2569 case XPATH_NUMBER:
2570 ret = val->floatval;
2571 break;
2572 case XPATH_BOOLEAN:
2573 ret = xmlXPathCastBooleanToNumber(val->boolval);
2574 break;
2575 case XPATH_USERS:
2576 case XPATH_POINT:
2577 case XPATH_RANGE:
2578 case XPATH_LOCATIONSET:
2579 TODO;
2580 ret = xmlXPathNAN;
2581 break;
2582 }
2583 return(ret);
2584}
2585
2586/**
2587 * xmlXPathConvertNumber:
2588 * @val: an XPath object
2589 *
2590 * Converts an existing object to its number() equivalent
2591 *
2592 * Returns the new object, the old one is freed (or the operation
2593 * is done directly on @val)
2594 */
2595xmlXPathObjectPtr
2596xmlXPathConvertNumber(xmlXPathObjectPtr val) {
2597 xmlXPathObjectPtr ret;
2598
2599 if (val == NULL)
2600 return(xmlXPathNewFloat(0.0));
2601 if (val->type == XPATH_NUMBER)
2602 return(val);
2603 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
2604 xmlXPathFreeObject(val);
2605 return(ret);
2606}
2607
2608/**
2609 * xmlXPathCastNumberToBoolean:
2610 * @val: a number
2611 *
2612 * Converts a number to its boolean value
2613 *
2614 * Returns the boolean value
2615 */
2616int
2617xmlXPathCastNumberToBoolean (double val) {
2618 if (isnan(val) || (val == 0.0))
2619 return(0);
2620 return(1);
2621}
2622
2623/**
2624 * xmlXPathCastStringToBoolean:
2625 * @val: a string
2626 *
2627 * Converts a string to its boolean value
2628 *
2629 * Returns the boolean value
2630 */
2631int
2632xmlXPathCastStringToBoolean (const xmlChar *val) {
2633 if ((val == NULL) || (xmlStrlen(val) == 0))
2634 return(0);
2635 return(1);
2636}
2637
2638/**
2639 * xmlXPathCastNodeSetToBoolean:
2640 * @ns: a node-set
2641 *
2642 * Converts a node-set to its boolean value
2643 *
2644 * Returns the boolean value
2645 */
2646int
2647xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
2648 if ((ns == NULL) || (ns->nodeNr == 0))
2649 return(0);
2650 return(1);
2651}
2652
2653/**
2654 * xmlXpathCastToBoolean:
2655 * @val: an XPath object
2656 *
2657 * Converts an XPath object to its boolean value
2658 *
2659 * Returns the boolean value
2660 */
2661int
2662xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
2663 int ret = 0;
2664
2665 if (val == NULL)
2666 return(0);
2667 switch (val->type) {
2668 case XPATH_UNDEFINED:
2669#ifdef DEBUG_EXPR
2670 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
2671#endif
2672 ret = 0;
2673 break;
2674 case XPATH_XSLT_TREE:
2675 case XPATH_NODESET:
2676 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
2677 break;
2678 case XPATH_STRING:
2679 ret = xmlXPathCastStringToBoolean(val->stringval);
2680 break;
2681 case XPATH_NUMBER:
2682 ret = xmlXPathCastNumberToBoolean(val->floatval);
2683 break;
2684 case XPATH_BOOLEAN:
2685 ret = val->boolval;
2686 break;
2687 case XPATH_USERS:
2688 case XPATH_POINT:
2689 case XPATH_RANGE:
2690 case XPATH_LOCATIONSET:
2691 TODO;
2692 ret = 0;
2693 break;
2694 }
2695 return(ret);
2696}
2697
2698
2699/**
2700 * xmlXPathConvertBoolean:
2701 * @val: an XPath object
2702 *
2703 * Converts an existing object to its boolean() equivalent
2704 *
2705 * Returns the new object, the old one is freed (or the operation
2706 * is done directly on @val)
2707 */
2708xmlXPathObjectPtr
2709xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
2710 xmlXPathObjectPtr ret;
2711
2712 if (val == NULL)
2713 return(xmlXPathNewBoolean(0));
2714 if (val->type == XPATH_BOOLEAN)
2715 return(val);
2716 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
2717 xmlXPathFreeObject(val);
2718 return(ret);
2719}
2720
Owen Taylor3473f882001-02-23 17:55:21 +00002721/************************************************************************
2722 * *
2723 * Routines to handle XPath contexts *
2724 * *
2725 ************************************************************************/
2726
2727/**
2728 * xmlXPathNewContext:
2729 * @doc: the XML document
2730 *
2731 * Create a new xmlXPathContext
2732 *
2733 * Returns the xmlXPathContext just allocated.
2734 */
2735xmlXPathContextPtr
2736xmlXPathNewContext(xmlDocPtr doc) {
2737 xmlXPathContextPtr ret;
2738
2739 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2740 if (ret == NULL) {
2741 xmlGenericError(xmlGenericErrorContext,
2742 "xmlXPathNewContext: out of memory\n");
2743 return(NULL);
2744 }
2745 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2746 ret->doc = doc;
2747 ret->node = NULL;
2748
2749 ret->varHash = NULL;
2750
2751 ret->nb_types = 0;
2752 ret->max_types = 0;
2753 ret->types = NULL;
2754
2755 ret->funcHash = xmlHashCreate(0);
2756
2757 ret->nb_axis = 0;
2758 ret->max_axis = 0;
2759 ret->axis = NULL;
2760
2761 ret->nsHash = NULL;
2762 ret->user = NULL;
2763
2764 ret->contextSize = -1;
2765 ret->proximityPosition = -1;
2766
2767 xmlXPathRegisterAllFunctions(ret);
2768
2769 return(ret);
2770}
2771
2772/**
2773 * xmlXPathFreeContext:
2774 * @ctxt: the context to free
2775 *
2776 * Free up an xmlXPathContext
2777 */
2778void
2779xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2780 xmlXPathRegisteredNsCleanup(ctxt);
2781 xmlXPathRegisteredFuncsCleanup(ctxt);
2782 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002783 xmlFree(ctxt);
2784}
2785
2786/************************************************************************
2787 * *
2788 * Routines to handle XPath parser contexts *
2789 * *
2790 ************************************************************************/
2791
2792#define CHECK_CTXT(ctxt) \
2793 if (ctxt == NULL) { \
2794 xmlGenericError(xmlGenericErrorContext, \
2795 "%s:%d Internal error: ctxt == NULL\n", \
2796 __FILE__, __LINE__); \
2797 } \
2798
2799
2800#define CHECK_CONTEXT(ctxt) \
2801 if (ctxt == NULL) { \
2802 xmlGenericError(xmlGenericErrorContext, \
2803 "%s:%d Internal error: no context\n", \
2804 __FILE__, __LINE__); \
2805 } \
2806 else if (ctxt->doc == NULL) { \
2807 xmlGenericError(xmlGenericErrorContext, \
2808 "%s:%d Internal error: no document\n", \
2809 __FILE__, __LINE__); \
2810 } \
2811 else if (ctxt->doc->children == NULL) { \
2812 xmlGenericError(xmlGenericErrorContext, \
2813 "%s:%d Internal error: document without root\n", \
2814 __FILE__, __LINE__); \
2815 } \
2816
2817
2818/**
2819 * xmlXPathNewParserContext:
2820 * @str: the XPath expression
2821 * @ctxt: the XPath context
2822 *
2823 * Create a new xmlXPathParserContext
2824 *
2825 * Returns the xmlXPathParserContext just allocated.
2826 */
2827xmlXPathParserContextPtr
2828xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2829 xmlXPathParserContextPtr ret;
2830
2831 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2832 if (ret == NULL) {
2833 xmlGenericError(xmlGenericErrorContext,
2834 "xmlXPathNewParserContext: out of memory\n");
2835 return(NULL);
2836 }
2837 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2838 ret->cur = ret->base = str;
2839 ret->context = ctxt;
2840
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002841 ret->comp = xmlXPathNewCompExpr();
2842 if (ret->comp == NULL) {
2843 xmlFree(ret->valueTab);
2844 xmlFree(ret);
2845 return(NULL);
2846 }
2847
2848 return(ret);
2849}
2850
2851/**
2852 * xmlXPathCompParserContext:
2853 * @comp: the XPath compiled expression
2854 * @ctxt: the XPath context
2855 *
2856 * Create a new xmlXPathParserContext when processing a compiled expression
2857 *
2858 * Returns the xmlXPathParserContext just allocated.
2859 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002860static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002861xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2862 xmlXPathParserContextPtr ret;
2863
2864 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2865 if (ret == NULL) {
2866 xmlGenericError(xmlGenericErrorContext,
2867 "xmlXPathNewParserContext: out of memory\n");
2868 return(NULL);
2869 }
2870 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2871
Owen Taylor3473f882001-02-23 17:55:21 +00002872 /* Allocate the value stack */
2873 ret->valueTab = (xmlXPathObjectPtr *)
2874 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002875 if (ret->valueTab == NULL) {
2876 xmlFree(ret);
2877 xmlGenericError(xmlGenericErrorContext,
2878 "xmlXPathNewParserContext: out of memory\n");
2879 return(NULL);
2880 }
Owen Taylor3473f882001-02-23 17:55:21 +00002881 ret->valueNr = 0;
2882 ret->valueMax = 10;
2883 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002884
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002885 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002886 ret->comp = comp;
2887
Owen Taylor3473f882001-02-23 17:55:21 +00002888 return(ret);
2889}
2890
2891/**
2892 * xmlXPathFreeParserContext:
2893 * @ctxt: the context to free
2894 *
2895 * Free up an xmlXPathParserContext
2896 */
2897void
2898xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2899 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002900 xmlFree(ctxt->valueTab);
2901 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002902 if (ctxt->comp)
2903 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002904 xmlFree(ctxt);
2905}
2906
2907/************************************************************************
2908 * *
2909 * The implicit core function library *
2910 * *
2911 ************************************************************************/
2912
Owen Taylor3473f882001-02-23 17:55:21 +00002913/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00002914 * xmlXPathNodeStringHash:
2915 * @node: a node pointer
2916 *
2917 * Function computing the beginning of the string value of the node,
2918 * used to speed up comparisons
2919 *
2920 * Returns an int usable as a hash
2921 */
2922static unsigned int
2923xmlXPathNodeValHash(xmlNodePtr node) {
2924 int len = 2;
2925 const xmlChar * string = NULL;
2926 xmlNodePtr tmp = NULL;
2927 unsigned int ret = 0;
2928
2929 if (node == NULL)
2930 return(0);
2931
2932
2933 switch (node->type) {
2934 case XML_COMMENT_NODE:
2935 case XML_PI_NODE:
2936 case XML_CDATA_SECTION_NODE:
2937 case XML_TEXT_NODE:
2938 string = node->content;
2939 if (string == NULL)
2940 return(0);
2941 if (string[0] == 0)
2942 return(0);
2943 return(((unsigned int) string[0]) +
2944 (((unsigned int) string[1]) << 8));
2945 case XML_NAMESPACE_DECL:
2946 string = ((xmlNsPtr)node)->href;
2947 if (string == NULL)
2948 return(0);
2949 if (string[0] == 0)
2950 return(0);
2951 return(((unsigned int) string[0]) +
2952 (((unsigned int) string[1]) << 8));
2953 case XML_ATTRIBUTE_NODE:
2954 tmp = ((xmlAttrPtr) node)->children;
2955 break;
2956 case XML_ELEMENT_NODE:
2957 tmp = node->children;
2958 break;
2959 default:
2960 return(0);
2961 }
2962 while (tmp != NULL) {
2963 switch (tmp->type) {
2964 case XML_COMMENT_NODE:
2965 case XML_PI_NODE:
2966 case XML_CDATA_SECTION_NODE:
2967 case XML_TEXT_NODE:
2968 string = tmp->content;
2969 break;
2970 case XML_NAMESPACE_DECL:
2971 string = ((xmlNsPtr)tmp)->href;
2972 break;
2973 default:
2974 break;
2975 }
2976 if ((string != NULL) && (string[0] != 0)) {
2977 if (string[0] == 0)
2978 return(0);
2979 if (len == 1) {
2980 return(ret + (((unsigned int) string[0]) << 8));
2981 }
2982 if (string[1] == 0) {
2983 len = 1;
2984 ret = (unsigned int) string[0];
2985 } else {
2986 return(((unsigned int) string[0]) +
2987 (((unsigned int) string[1]) << 8));
2988 }
2989 }
2990 /*
2991 * Skip to next node
2992 */
2993 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
2994 if (tmp->children->type != XML_ENTITY_DECL) {
2995 tmp = tmp->children;
2996 continue;
2997 }
2998 }
2999 if (tmp == node)
3000 break;
3001
3002 if (tmp->next != NULL) {
3003 tmp = tmp->next;
3004 continue;
3005 }
3006
3007 do {
3008 tmp = tmp->parent;
3009 if (tmp == NULL)
3010 break;
3011 if (tmp == node) {
3012 tmp = NULL;
3013 break;
3014 }
3015 if (tmp->next != NULL) {
3016 tmp = tmp->next;
3017 break;
3018 }
3019 } while (tmp != NULL);
3020 }
3021 return(ret);
3022}
3023
3024/**
3025 * xmlXPathStringHash:
3026 * @string: a string
3027 *
3028 * Function computing the beginning of the string value of the node,
3029 * used to speed up comparisons
3030 *
3031 * Returns an int usable as a hash
3032 */
3033static unsigned int
3034xmlXPathStringHash(const xmlChar * string) {
3035 if (string == NULL)
3036 return((unsigned int) 0);
3037 if (string[0] == 0)
3038 return(0);
3039 return(((unsigned int) string[0]) +
3040 (((unsigned int) string[1]) << 8));
3041}
3042
3043/**
Owen Taylor3473f882001-02-23 17:55:21 +00003044 * xmlXPathCompareNodeSetFloat:
3045 * @ctxt: the XPath Parser context
3046 * @inf: less than (1) or greater than (0)
3047 * @strict: is the comparison strict
3048 * @arg: the node set
3049 * @f: the value
3050 *
3051 * Implement the compare operation between a nodeset and a number
3052 * @ns < @val (1, 1, ...
3053 * @ns <= @val (1, 0, ...
3054 * @ns > @val (0, 1, ...
3055 * @ns >= @val (0, 0, ...
3056 *
3057 * If one object to be compared is a node-set and the other is a number,
3058 * then the comparison will be true if and only if there is a node in the
3059 * node-set such that the result of performing the comparison on the number
3060 * to be compared and on the result of converting the string-value of that
3061 * node to a number using the number function is true.
3062 *
3063 * Returns 0 or 1 depending on the results of the test.
3064 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003065static int
Owen Taylor3473f882001-02-23 17:55:21 +00003066xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3067 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3068 int i, ret = 0;
3069 xmlNodeSetPtr ns;
3070 xmlChar *str2;
3071
3072 if ((f == NULL) || (arg == NULL) ||
3073 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3074 xmlXPathFreeObject(arg);
3075 xmlXPathFreeObject(f);
3076 return(0);
3077 }
3078 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003079 if (ns != NULL) {
3080 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003081 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003082 if (str2 != NULL) {
3083 valuePush(ctxt,
3084 xmlXPathNewString(str2));
3085 xmlFree(str2);
3086 xmlXPathNumberFunction(ctxt, 1);
3087 valuePush(ctxt, xmlXPathObjectCopy(f));
3088 ret = xmlXPathCompareValues(ctxt, inf, strict);
3089 if (ret)
3090 break;
3091 }
3092 }
Owen Taylor3473f882001-02-23 17:55:21 +00003093 }
3094 xmlXPathFreeObject(arg);
3095 xmlXPathFreeObject(f);
3096 return(ret);
3097}
3098
3099/**
3100 * xmlXPathCompareNodeSetString:
3101 * @ctxt: the XPath Parser context
3102 * @inf: less than (1) or greater than (0)
3103 * @strict: is the comparison strict
3104 * @arg: the node set
3105 * @s: the value
3106 *
3107 * Implement the compare operation between a nodeset and a string
3108 * @ns < @val (1, 1, ...
3109 * @ns <= @val (1, 0, ...
3110 * @ns > @val (0, 1, ...
3111 * @ns >= @val (0, 0, ...
3112 *
3113 * If one object to be compared is a node-set and the other is a string,
3114 * then the comparison will be true if and only if there is a node in
3115 * the node-set such that the result of performing the comparison on the
3116 * string-value of the node and the other string is true.
3117 *
3118 * Returns 0 or 1 depending on the results of the test.
3119 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003120static int
Owen Taylor3473f882001-02-23 17:55:21 +00003121xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3122 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3123 int i, ret = 0;
3124 xmlNodeSetPtr ns;
3125 xmlChar *str2;
3126
3127 if ((s == NULL) || (arg == NULL) ||
3128 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3129 xmlXPathFreeObject(arg);
3130 xmlXPathFreeObject(s);
3131 return(0);
3132 }
3133 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003134 if (ns != NULL) {
3135 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003136 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003137 if (str2 != NULL) {
3138 valuePush(ctxt,
3139 xmlXPathNewString(str2));
3140 xmlFree(str2);
3141 valuePush(ctxt, xmlXPathObjectCopy(s));
3142 ret = xmlXPathCompareValues(ctxt, inf, strict);
3143 if (ret)
3144 break;
3145 }
3146 }
Owen Taylor3473f882001-02-23 17:55:21 +00003147 }
3148 xmlXPathFreeObject(arg);
3149 xmlXPathFreeObject(s);
3150 return(ret);
3151}
3152
3153/**
3154 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003155 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003156 * @strict: is the comparison strict
3157 * @arg1: the fist node set object
3158 * @arg2: the second node set object
3159 *
3160 * Implement the compare operation on nodesets:
3161 *
3162 * If both objects to be compared are node-sets, then the comparison
3163 * will be true if and only if there is a node in the first node-set
3164 * and a node in the second node-set such that the result of performing
3165 * the comparison on the string-values of the two nodes is true.
3166 * ....
3167 * When neither object to be compared is a node-set and the operator
3168 * is <=, <, >= or >, then the objects are compared by converting both
3169 * objects to numbers and comparing the numbers according to IEEE 754.
3170 * ....
3171 * The number function converts its argument to a number as follows:
3172 * - a string that consists of optional whitespace followed by an
3173 * optional minus sign followed by a Number followed by whitespace
3174 * is converted to the IEEE 754 number that is nearest (according
3175 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3176 * represented by the string; any other string is converted to NaN
3177 *
3178 * Conclusion all nodes need to be converted first to their string value
3179 * and then the comparison must be done when possible
3180 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003181static int
3182xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003183 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3184 int i, j, init = 0;
3185 double val1;
3186 double *values2;
3187 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003188 xmlNodeSetPtr ns1;
3189 xmlNodeSetPtr ns2;
3190
3191 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003192 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3193 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003194 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003195 }
Owen Taylor3473f882001-02-23 17:55:21 +00003196 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003197 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3198 xmlXPathFreeObject(arg1);
3199 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003200 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003201 }
Owen Taylor3473f882001-02-23 17:55:21 +00003202
3203 ns1 = arg1->nodesetval;
3204 ns2 = arg2->nodesetval;
3205
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003206 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003207 xmlXPathFreeObject(arg1);
3208 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003209 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003210 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003211 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003212 xmlXPathFreeObject(arg1);
3213 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003214 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003215 }
Owen Taylor3473f882001-02-23 17:55:21 +00003216
3217 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3218 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003219 xmlXPathFreeObject(arg1);
3220 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003221 return(0);
3222 }
3223 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003224 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003225 if (isnan(val1))
3226 continue;
3227 for (j = 0;j < ns2->nodeNr;j++) {
3228 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003229 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003230 }
3231 if (isnan(values2[j]))
3232 continue;
3233 if (inf && strict)
3234 ret = (val1 < values2[j]);
3235 else if (inf && !strict)
3236 ret = (val1 <= values2[j]);
3237 else if (!inf && strict)
3238 ret = (val1 > values2[j]);
3239 else if (!inf && !strict)
3240 ret = (val1 >= values2[j]);
3241 if (ret)
3242 break;
3243 }
3244 if (ret)
3245 break;
3246 init = 1;
3247 }
3248 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003249 xmlXPathFreeObject(arg1);
3250 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003251 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003252}
3253
3254/**
3255 * xmlXPathCompareNodeSetValue:
3256 * @ctxt: the XPath Parser context
3257 * @inf: less than (1) or greater than (0)
3258 * @strict: is the comparison strict
3259 * @arg: the node set
3260 * @val: the value
3261 *
3262 * Implement the compare operation between a nodeset and a value
3263 * @ns < @val (1, 1, ...
3264 * @ns <= @val (1, 0, ...
3265 * @ns > @val (0, 1, ...
3266 * @ns >= @val (0, 0, ...
3267 *
3268 * If one object to be compared is a node-set and the other is a boolean,
3269 * then the comparison will be true if and only if the result of performing
3270 * the comparison on the boolean and on the result of converting
3271 * the node-set to a boolean using the boolean function is true.
3272 *
3273 * Returns 0 or 1 depending on the results of the test.
3274 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003275static int
Owen Taylor3473f882001-02-23 17:55:21 +00003276xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3277 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3278 if ((val == NULL) || (arg == NULL) ||
3279 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3280 return(0);
3281
3282 switch(val->type) {
3283 case XPATH_NUMBER:
3284 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3285 case XPATH_NODESET:
3286 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003287 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003288 case XPATH_STRING:
3289 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3290 case XPATH_BOOLEAN:
3291 valuePush(ctxt, arg);
3292 xmlXPathBooleanFunction(ctxt, 1);
3293 valuePush(ctxt, val);
3294 return(xmlXPathCompareValues(ctxt, inf, strict));
3295 default:
3296 TODO
3297 return(0);
3298 }
3299 return(0);
3300}
3301
3302/**
3303 * xmlXPathEqualNodeSetString
3304 * @arg: the nodeset object argument
3305 * @str: the string to compare to.
3306 *
3307 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3308 * If one object to be compared is a node-set and the other is a string,
3309 * then the comparison will be true if and only if there is a node in
3310 * the node-set such that the result of performing the comparison on the
3311 * string-value of the node and the other string is true.
3312 *
3313 * Returns 0 or 1 depending on the results of the test.
3314 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003315static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003316xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3317{
Owen Taylor3473f882001-02-23 17:55:21 +00003318 int i;
3319 xmlNodeSetPtr ns;
3320 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003321 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003322
3323 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003324 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3325 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003326 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003327 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003328 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003329 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003330 if (ns->nodeNr <= 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003331 return (0);
3332 for (i = 0; i < ns->nodeNr; i++) {
3333 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3334 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3335 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3336 xmlFree(str2);
3337 return (1);
3338 }
3339 if (str2 != NULL)
3340 xmlFree(str2);
3341 }
Owen Taylor3473f882001-02-23 17:55:21 +00003342 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003343 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003344}
3345
3346/**
3347 * xmlXPathEqualNodeSetFloat
3348 * @arg: the nodeset object argument
3349 * @f: the float to compare to
3350 *
3351 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3352 * If one object to be compared is a node-set and the other is a number,
3353 * then the comparison will be true if and only if there is a node in
3354 * the node-set such that the result of performing the comparison on the
3355 * number to be compared and on the result of converting the string-value
3356 * of that node to a number using the number function is true.
3357 *
3358 * Returns 0 or 1 depending on the results of the test.
3359 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003360static int
Owen Taylor3473f882001-02-23 17:55:21 +00003361xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3362 char buf[100] = "";
3363
3364 if ((arg == NULL) ||
3365 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3366 return(0);
3367
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003368 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003369 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3370}
3371
3372
3373/**
3374 * xmlXPathEqualNodeSets
3375 * @arg1: first nodeset object argument
3376 * @arg2: second nodeset object argument
3377 *
3378 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3379 * If both objects to be compared are node-sets, then the comparison
3380 * will be true if and only if there is a node in the first node-set and
3381 * a node in the second node-set such that the result of performing the
3382 * comparison on the string-values of the two nodes is true.
3383 *
3384 * (needless to say, this is a costly operation)
3385 *
3386 * Returns 0 or 1 depending on the results of the test.
3387 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003388static int
Owen Taylor3473f882001-02-23 17:55:21 +00003389xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3390 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003391 unsigned int *hashs1;
3392 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003393 xmlChar **values1;
3394 xmlChar **values2;
3395 int ret = 0;
3396 xmlNodeSetPtr ns1;
3397 xmlNodeSetPtr ns2;
3398
3399 if ((arg1 == NULL) ||
3400 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3401 return(0);
3402 if ((arg2 == NULL) ||
3403 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3404 return(0);
3405
3406 ns1 = arg1->nodesetval;
3407 ns2 = arg2->nodesetval;
3408
Daniel Veillard911f49a2001-04-07 15:39:35 +00003409 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003410 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003411 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003412 return(0);
3413
3414 /*
3415 * check if there is a node pertaining to both sets
3416 */
3417 for (i = 0;i < ns1->nodeNr;i++)
3418 for (j = 0;j < ns2->nodeNr;j++)
3419 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3420 return(1);
3421
3422 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3423 if (values1 == NULL)
3424 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003425 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3426 if (hashs1 == NULL) {
3427 xmlFree(values1);
3428 return(0);
3429 }
Owen Taylor3473f882001-02-23 17:55:21 +00003430 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3431 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3432 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003433 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003434 xmlFree(values1);
3435 return(0);
3436 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003437 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3438 if (hashs2 == NULL) {
3439 xmlFree(hashs1);
3440 xmlFree(values1);
3441 xmlFree(values2);
3442 return(0);
3443 }
Owen Taylor3473f882001-02-23 17:55:21 +00003444 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3445 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003446 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003447 for (j = 0;j < ns2->nodeNr;j++) {
3448 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003449 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
3450 if (hashs1[i] == hashs2[j]) {
3451 if (values1[i] == NULL)
3452 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3453 if (values2[j] == NULL)
3454 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3455 ret = xmlStrEqual(values1[i], values2[j]);
3456 if (ret)
3457 break;
3458 }
Owen Taylor3473f882001-02-23 17:55:21 +00003459 }
3460 if (ret)
3461 break;
3462 }
3463 for (i = 0;i < ns1->nodeNr;i++)
3464 if (values1[i] != NULL)
3465 xmlFree(values1[i]);
3466 for (j = 0;j < ns2->nodeNr;j++)
3467 if (values2[j] != NULL)
3468 xmlFree(values2[j]);
3469 xmlFree(values1);
3470 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003471 xmlFree(hashs1);
3472 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00003473 return(ret);
3474}
3475
3476/**
3477 * xmlXPathEqualValues:
3478 * @ctxt: the XPath Parser context
3479 *
3480 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3481 *
3482 * Returns 0 or 1 depending on the results of the test.
3483 */
3484int
3485xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
3486 xmlXPathObjectPtr arg1, arg2;
3487 int ret = 0;
3488
3489 arg1 = valuePop(ctxt);
3490 if (arg1 == NULL)
3491 XP_ERROR0(XPATH_INVALID_OPERAND);
3492
3493 arg2 = valuePop(ctxt);
3494 if (arg2 == NULL) {
3495 xmlXPathFreeObject(arg1);
3496 XP_ERROR0(XPATH_INVALID_OPERAND);
3497 }
3498
3499 if (arg1 == arg2) {
3500#ifdef DEBUG_EXPR
3501 xmlGenericError(xmlGenericErrorContext,
3502 "Equal: by pointer\n");
3503#endif
3504 return(1);
3505 }
3506
3507 switch (arg1->type) {
3508 case XPATH_UNDEFINED:
3509#ifdef DEBUG_EXPR
3510 xmlGenericError(xmlGenericErrorContext,
3511 "Equal: undefined\n");
3512#endif
3513 break;
3514 case XPATH_XSLT_TREE:
3515 case XPATH_NODESET:
3516 switch (arg2->type) {
3517 case XPATH_UNDEFINED:
3518#ifdef DEBUG_EXPR
3519 xmlGenericError(xmlGenericErrorContext,
3520 "Equal: undefined\n");
3521#endif
3522 break;
3523 case XPATH_XSLT_TREE:
3524 case XPATH_NODESET:
3525 ret = xmlXPathEqualNodeSets(arg1, arg2);
3526 break;
3527 case XPATH_BOOLEAN:
3528 if ((arg1->nodesetval == NULL) ||
3529 (arg1->nodesetval->nodeNr == 0)) ret = 0;
3530 else
3531 ret = 1;
3532 ret = (ret == arg2->boolval);
3533 break;
3534 case XPATH_NUMBER:
3535 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
3536 break;
3537 case XPATH_STRING:
3538 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
3539 break;
3540 case XPATH_USERS:
3541 case XPATH_POINT:
3542 case XPATH_RANGE:
3543 case XPATH_LOCATIONSET:
3544 TODO
3545 break;
3546 }
3547 break;
3548 case XPATH_BOOLEAN:
3549 switch (arg2->type) {
3550 case XPATH_UNDEFINED:
3551#ifdef DEBUG_EXPR
3552 xmlGenericError(xmlGenericErrorContext,
3553 "Equal: undefined\n");
3554#endif
3555 break;
3556 case XPATH_NODESET:
3557 case XPATH_XSLT_TREE:
3558 if ((arg2->nodesetval == NULL) ||
3559 (arg2->nodesetval->nodeNr == 0)) ret = 0;
3560 else
3561 ret = 1;
3562 break;
3563 case XPATH_BOOLEAN:
3564#ifdef DEBUG_EXPR
3565 xmlGenericError(xmlGenericErrorContext,
3566 "Equal: %d boolean %d \n",
3567 arg1->boolval, arg2->boolval);
3568#endif
3569 ret = (arg1->boolval == arg2->boolval);
3570 break;
3571 case XPATH_NUMBER:
3572 if (arg2->floatval) ret = 1;
3573 else ret = 0;
3574 ret = (arg1->boolval == ret);
3575 break;
3576 case XPATH_STRING:
3577 if ((arg2->stringval == NULL) ||
3578 (arg2->stringval[0] == 0)) ret = 0;
3579 else
3580 ret = 1;
3581 ret = (arg1->boolval == ret);
3582 break;
3583 case XPATH_USERS:
3584 case XPATH_POINT:
3585 case XPATH_RANGE:
3586 case XPATH_LOCATIONSET:
3587 TODO
3588 break;
3589 }
3590 break;
3591 case XPATH_NUMBER:
3592 switch (arg2->type) {
3593 case XPATH_UNDEFINED:
3594#ifdef DEBUG_EXPR
3595 xmlGenericError(xmlGenericErrorContext,
3596 "Equal: undefined\n");
3597#endif
3598 break;
3599 case XPATH_NODESET:
3600 case XPATH_XSLT_TREE:
3601 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
3602 break;
3603 case XPATH_BOOLEAN:
3604 if (arg1->floatval) ret = 1;
3605 else ret = 0;
3606 ret = (arg2->boolval == ret);
3607 break;
3608 case XPATH_STRING:
3609 valuePush(ctxt, arg2);
3610 xmlXPathNumberFunction(ctxt, 1);
3611 arg2 = valuePop(ctxt);
3612 /* no break on purpose */
3613 case XPATH_NUMBER:
3614 ret = (arg1->floatval == arg2->floatval);
3615 break;
3616 case XPATH_USERS:
3617 case XPATH_POINT:
3618 case XPATH_RANGE:
3619 case XPATH_LOCATIONSET:
3620 TODO
3621 break;
3622 }
3623 break;
3624 case XPATH_STRING:
3625 switch (arg2->type) {
3626 case XPATH_UNDEFINED:
3627#ifdef DEBUG_EXPR
3628 xmlGenericError(xmlGenericErrorContext,
3629 "Equal: undefined\n");
3630#endif
3631 break;
3632 case XPATH_NODESET:
3633 case XPATH_XSLT_TREE:
3634 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
3635 break;
3636 case XPATH_BOOLEAN:
3637 if ((arg1->stringval == NULL) ||
3638 (arg1->stringval[0] == 0)) ret = 0;
3639 else
3640 ret = 1;
3641 ret = (arg2->boolval == ret);
3642 break;
3643 case XPATH_STRING:
3644 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
3645 break;
3646 case XPATH_NUMBER:
3647 valuePush(ctxt, arg1);
3648 xmlXPathNumberFunction(ctxt, 1);
3649 arg1 = valuePop(ctxt);
3650 ret = (arg1->floatval == arg2->floatval);
3651 break;
3652 case XPATH_USERS:
3653 case XPATH_POINT:
3654 case XPATH_RANGE:
3655 case XPATH_LOCATIONSET:
3656 TODO
3657 break;
3658 }
3659 break;
3660 case XPATH_USERS:
3661 case XPATH_POINT:
3662 case XPATH_RANGE:
3663 case XPATH_LOCATIONSET:
3664 TODO
3665 break;
3666 }
3667 xmlXPathFreeObject(arg1);
3668 xmlXPathFreeObject(arg2);
3669 return(ret);
3670}
3671
3672
3673/**
3674 * xmlXPathCompareValues:
3675 * @ctxt: the XPath Parser context
3676 * @inf: less than (1) or greater than (0)
3677 * @strict: is the comparison strict
3678 *
3679 * Implement the compare operation on XPath objects:
3680 * @arg1 < @arg2 (1, 1, ...
3681 * @arg1 <= @arg2 (1, 0, ...
3682 * @arg1 > @arg2 (0, 1, ...
3683 * @arg1 >= @arg2 (0, 0, ...
3684 *
3685 * When neither object to be compared is a node-set and the operator is
3686 * <=, <, >=, >, then the objects are compared by converted both objects
3687 * to numbers and comparing the numbers according to IEEE 754. The <
3688 * comparison will be true if and only if the first number is less than the
3689 * second number. The <= comparison will be true if and only if the first
3690 * number is less than or equal to the second number. The > comparison
3691 * will be true if and only if the first number is greater than the second
3692 * number. The >= comparison will be true if and only if the first number
3693 * is greater than or equal to the second number.
3694 *
3695 * Returns 1 if the comparaison succeeded, 0 if it failed
3696 */
3697int
3698xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3699 int ret = 0;
3700 xmlXPathObjectPtr arg1, arg2;
3701
3702 arg2 = valuePop(ctxt);
3703 if (arg2 == NULL) {
3704 XP_ERROR0(XPATH_INVALID_OPERAND);
3705 }
3706
3707 arg1 = valuePop(ctxt);
3708 if (arg1 == NULL) {
3709 xmlXPathFreeObject(arg2);
3710 XP_ERROR0(XPATH_INVALID_OPERAND);
3711 }
3712
3713 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3714 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003715 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003716 } else {
3717 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003718 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3719 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003720 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003721 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3722 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003723 }
3724 }
3725 return(ret);
3726 }
3727
3728 if (arg1->type != XPATH_NUMBER) {
3729 valuePush(ctxt, arg1);
3730 xmlXPathNumberFunction(ctxt, 1);
3731 arg1 = valuePop(ctxt);
3732 }
3733 if (arg1->type != XPATH_NUMBER) {
3734 xmlXPathFreeObject(arg1);
3735 xmlXPathFreeObject(arg2);
3736 XP_ERROR0(XPATH_INVALID_OPERAND);
3737 }
3738 if (arg2->type != XPATH_NUMBER) {
3739 valuePush(ctxt, arg2);
3740 xmlXPathNumberFunction(ctxt, 1);
3741 arg2 = valuePop(ctxt);
3742 }
3743 if (arg2->type != XPATH_NUMBER) {
3744 xmlXPathFreeObject(arg1);
3745 xmlXPathFreeObject(arg2);
3746 XP_ERROR0(XPATH_INVALID_OPERAND);
3747 }
3748 /*
3749 * Add tests for infinity and nan
3750 * => feedback on 3.4 for Inf and NaN
3751 */
3752 if (inf && strict)
3753 ret = (arg1->floatval < arg2->floatval);
3754 else if (inf && !strict)
3755 ret = (arg1->floatval <= arg2->floatval);
3756 else if (!inf && strict)
3757 ret = (arg1->floatval > arg2->floatval);
3758 else if (!inf && !strict)
3759 ret = (arg1->floatval >= arg2->floatval);
3760 xmlXPathFreeObject(arg1);
3761 xmlXPathFreeObject(arg2);
3762 return(ret);
3763}
3764
3765/**
3766 * xmlXPathValueFlipSign:
3767 * @ctxt: the XPath Parser context
3768 *
3769 * Implement the unary - operation on an XPath object
3770 * The numeric operators convert their operands to numbers as if
3771 * by calling the number function.
3772 */
3773void
3774xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003775 CAST_TO_NUMBER;
3776 CHECK_TYPE(XPATH_NUMBER);
3777 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00003778}
3779
3780/**
3781 * xmlXPathAddValues:
3782 * @ctxt: the XPath Parser context
3783 *
3784 * Implement the add operation on XPath objects:
3785 * The numeric operators convert their operands to numbers as if
3786 * by calling the number function.
3787 */
3788void
3789xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3790 xmlXPathObjectPtr arg;
3791 double val;
3792
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003793 arg = valuePop(ctxt);
3794 if (arg == NULL)
3795 XP_ERROR(XPATH_INVALID_OPERAND);
3796 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003797 xmlXPathFreeObject(arg);
3798
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003799 CAST_TO_NUMBER;
3800 CHECK_TYPE(XPATH_NUMBER);
3801 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00003802}
3803
3804/**
3805 * xmlXPathSubValues:
3806 * @ctxt: the XPath Parser context
3807 *
3808 * Implement the substraction operation on XPath objects:
3809 * The numeric operators convert their operands to numbers as if
3810 * by calling the number function.
3811 */
3812void
3813xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3814 xmlXPathObjectPtr arg;
3815 double val;
3816
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003817 arg = valuePop(ctxt);
3818 if (arg == NULL)
3819 XP_ERROR(XPATH_INVALID_OPERAND);
3820 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003821 xmlXPathFreeObject(arg);
3822
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003823 CAST_TO_NUMBER;
3824 CHECK_TYPE(XPATH_NUMBER);
3825 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003826}
3827
3828/**
3829 * xmlXPathMultValues:
3830 * @ctxt: the XPath Parser context
3831 *
3832 * Implement the multiply operation on XPath objects:
3833 * The numeric operators convert their operands to numbers as if
3834 * by calling the number function.
3835 */
3836void
3837xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3838 xmlXPathObjectPtr arg;
3839 double val;
3840
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003841 arg = valuePop(ctxt);
3842 if (arg == NULL)
3843 XP_ERROR(XPATH_INVALID_OPERAND);
3844 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003845 xmlXPathFreeObject(arg);
3846
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003847 CAST_TO_NUMBER;
3848 CHECK_TYPE(XPATH_NUMBER);
3849 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003850}
3851
3852/**
3853 * xmlXPathDivValues:
3854 * @ctxt: the XPath Parser context
3855 *
3856 * Implement the div operation on XPath objects @arg1 / @arg2:
3857 * The numeric operators convert their operands to numbers as if
3858 * by calling the number function.
3859 */
3860void
3861xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3862 xmlXPathObjectPtr arg;
3863 double val;
3864
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003865 arg = valuePop(ctxt);
3866 if (arg == NULL)
3867 XP_ERROR(XPATH_INVALID_OPERAND);
3868 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003869 xmlXPathFreeObject(arg);
3870
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003871 CAST_TO_NUMBER;
3872 CHECK_TYPE(XPATH_NUMBER);
3873 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003874}
3875
3876/**
3877 * xmlXPathModValues:
3878 * @ctxt: the XPath Parser context
3879 *
3880 * Implement the mod operation on XPath objects: @arg1 / @arg2
3881 * The numeric operators convert their operands to numbers as if
3882 * by calling the number function.
3883 */
3884void
3885xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3886 xmlXPathObjectPtr arg;
3887 int arg1, arg2;
3888
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003889 arg = valuePop(ctxt);
3890 if (arg == NULL)
3891 XP_ERROR(XPATH_INVALID_OPERAND);
3892 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003893 xmlXPathFreeObject(arg);
3894
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003895 CAST_TO_NUMBER;
3896 CHECK_TYPE(XPATH_NUMBER);
3897 arg1 = (int) ctxt->value->floatval;
3898 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00003899}
3900
3901/************************************************************************
3902 * *
3903 * The traversal functions *
3904 * *
3905 ************************************************************************/
3906
Owen Taylor3473f882001-02-23 17:55:21 +00003907/*
3908 * A traversal function enumerates nodes along an axis.
3909 * Initially it must be called with NULL, and it indicates
3910 * termination on the axis by returning NULL.
3911 */
3912typedef xmlNodePtr (*xmlXPathTraversalFunction)
3913 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3914
3915/**
3916 * xmlXPathNextSelf:
3917 * @ctxt: the XPath Parser context
3918 * @cur: the current node in the traversal
3919 *
3920 * Traversal function for the "self" direction
3921 * The self axis contains just the context node itself
3922 *
3923 * Returns the next element following that axis
3924 */
3925xmlNodePtr
3926xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3927 if (cur == NULL)
3928 return(ctxt->context->node);
3929 return(NULL);
3930}
3931
3932/**
3933 * xmlXPathNextChild:
3934 * @ctxt: the XPath Parser context
3935 * @cur: the current node in the traversal
3936 *
3937 * Traversal function for the "child" direction
3938 * The child axis contains the children of the context node in document order.
3939 *
3940 * Returns the next element following that axis
3941 */
3942xmlNodePtr
3943xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3944 if (cur == NULL) {
3945 if (ctxt->context->node == NULL) return(NULL);
3946 switch (ctxt->context->node->type) {
3947 case XML_ELEMENT_NODE:
3948 case XML_TEXT_NODE:
3949 case XML_CDATA_SECTION_NODE:
3950 case XML_ENTITY_REF_NODE:
3951 case XML_ENTITY_NODE:
3952 case XML_PI_NODE:
3953 case XML_COMMENT_NODE:
3954 case XML_NOTATION_NODE:
3955 case XML_DTD_NODE:
3956 return(ctxt->context->node->children);
3957 case XML_DOCUMENT_NODE:
3958 case XML_DOCUMENT_TYPE_NODE:
3959 case XML_DOCUMENT_FRAG_NODE:
3960 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003961#ifdef LIBXML_DOCB_ENABLED
3962 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003963#endif
3964 return(((xmlDocPtr) ctxt->context->node)->children);
3965 case XML_ELEMENT_DECL:
3966 case XML_ATTRIBUTE_DECL:
3967 case XML_ENTITY_DECL:
3968 case XML_ATTRIBUTE_NODE:
3969 case XML_NAMESPACE_DECL:
3970 case XML_XINCLUDE_START:
3971 case XML_XINCLUDE_END:
3972 return(NULL);
3973 }
3974 return(NULL);
3975 }
3976 if ((cur->type == XML_DOCUMENT_NODE) ||
3977 (cur->type == XML_HTML_DOCUMENT_NODE))
3978 return(NULL);
3979 return(cur->next);
3980}
3981
3982/**
3983 * xmlXPathNextDescendant:
3984 * @ctxt: the XPath Parser context
3985 * @cur: the current node in the traversal
3986 *
3987 * Traversal function for the "descendant" direction
3988 * the descendant axis contains the descendants of the context node in document
3989 * order; a descendant is a child or a child of a child and so on.
3990 *
3991 * Returns the next element following that axis
3992 */
3993xmlNodePtr
3994xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3995 if (cur == NULL) {
3996 if (ctxt->context->node == NULL)
3997 return(NULL);
3998 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3999 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4000 return(NULL);
4001
4002 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4003 return(ctxt->context->doc->children);
4004 return(ctxt->context->node->children);
4005 }
4006
4007 if (cur->children != NULL)
4008 {
4009 if (cur->children->type != XML_ENTITY_DECL)
4010 return(cur->children);
4011 }
4012 if (cur->next != NULL) return(cur->next);
4013
4014 do {
4015 cur = cur->parent;
4016 if (cur == NULL) return(NULL);
4017 if (cur == ctxt->context->node) return(NULL);
4018 if (cur->next != NULL) {
4019 cur = cur->next;
4020 return(cur);
4021 }
4022 } while (cur != NULL);
4023 return(cur);
4024}
4025
4026/**
4027 * xmlXPathNextDescendantOrSelf:
4028 * @ctxt: the XPath Parser context
4029 * @cur: the current node in the traversal
4030 *
4031 * Traversal function for the "descendant-or-self" direction
4032 * the descendant-or-self axis contains the context node and the descendants
4033 * of the context node in document order; thus the context node is the first
4034 * node on the axis, and the first child of the context node is the second node
4035 * on the axis
4036 *
4037 * Returns the next element following that axis
4038 */
4039xmlNodePtr
4040xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4041 if (cur == NULL) {
4042 if (ctxt->context->node == NULL)
4043 return(NULL);
4044 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4045 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4046 return(NULL);
4047 return(ctxt->context->node);
4048 }
4049
4050 return(xmlXPathNextDescendant(ctxt, cur));
4051}
4052
4053/**
4054 * xmlXPathNextParent:
4055 * @ctxt: the XPath Parser context
4056 * @cur: the current node in the traversal
4057 *
4058 * Traversal function for the "parent" direction
4059 * The parent axis contains the parent of the context node, if there is one.
4060 *
4061 * Returns the next element following that axis
4062 */
4063xmlNodePtr
4064xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4065 /*
4066 * the parent of an attribute or namespace node is the element
4067 * to which the attribute or namespace node is attached
4068 * Namespace handling !!!
4069 */
4070 if (cur == NULL) {
4071 if (ctxt->context->node == NULL) return(NULL);
4072 switch (ctxt->context->node->type) {
4073 case XML_ELEMENT_NODE:
4074 case XML_TEXT_NODE:
4075 case XML_CDATA_SECTION_NODE:
4076 case XML_ENTITY_REF_NODE:
4077 case XML_ENTITY_NODE:
4078 case XML_PI_NODE:
4079 case XML_COMMENT_NODE:
4080 case XML_NOTATION_NODE:
4081 case XML_DTD_NODE:
4082 case XML_ELEMENT_DECL:
4083 case XML_ATTRIBUTE_DECL:
4084 case XML_XINCLUDE_START:
4085 case XML_XINCLUDE_END:
4086 case XML_ENTITY_DECL:
4087 if (ctxt->context->node->parent == NULL)
4088 return((xmlNodePtr) ctxt->context->doc);
4089 return(ctxt->context->node->parent);
4090 case XML_ATTRIBUTE_NODE: {
4091 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4092
4093 return(att->parent);
4094 }
4095 case XML_DOCUMENT_NODE:
4096 case XML_DOCUMENT_TYPE_NODE:
4097 case XML_DOCUMENT_FRAG_NODE:
4098 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004099#ifdef LIBXML_DOCB_ENABLED
4100 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004101#endif
4102 return(NULL);
4103 case XML_NAMESPACE_DECL:
4104 /*
4105 * TODO !!! may require extending struct _xmlNs with
4106 * parent field
4107 * C.f. Infoset case...
4108 */
4109 return(NULL);
4110 }
4111 }
4112 return(NULL);
4113}
4114
4115/**
4116 * xmlXPathNextAncestor:
4117 * @ctxt: the XPath Parser context
4118 * @cur: the current node in the traversal
4119 *
4120 * Traversal function for the "ancestor" direction
4121 * the ancestor axis contains the ancestors of the context node; the ancestors
4122 * of the context node consist of the parent of context node and the parent's
4123 * parent and so on; the nodes are ordered in reverse document order; thus the
4124 * parent is the first node on the axis, and the parent's parent is the second
4125 * node on the axis
4126 *
4127 * Returns the next element following that axis
4128 */
4129xmlNodePtr
4130xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4131 /*
4132 * the parent of an attribute or namespace node is the element
4133 * to which the attribute or namespace node is attached
4134 * !!!!!!!!!!!!!
4135 */
4136 if (cur == NULL) {
4137 if (ctxt->context->node == NULL) return(NULL);
4138 switch (ctxt->context->node->type) {
4139 case XML_ELEMENT_NODE:
4140 case XML_TEXT_NODE:
4141 case XML_CDATA_SECTION_NODE:
4142 case XML_ENTITY_REF_NODE:
4143 case XML_ENTITY_NODE:
4144 case XML_PI_NODE:
4145 case XML_COMMENT_NODE:
4146 case XML_DTD_NODE:
4147 case XML_ELEMENT_DECL:
4148 case XML_ATTRIBUTE_DECL:
4149 case XML_ENTITY_DECL:
4150 case XML_NOTATION_NODE:
4151 case XML_XINCLUDE_START:
4152 case XML_XINCLUDE_END:
4153 if (ctxt->context->node->parent == NULL)
4154 return((xmlNodePtr) ctxt->context->doc);
4155 return(ctxt->context->node->parent);
4156 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004157 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004158
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004159 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004160 }
4161 case XML_DOCUMENT_NODE:
4162 case XML_DOCUMENT_TYPE_NODE:
4163 case XML_DOCUMENT_FRAG_NODE:
4164 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004165#ifdef LIBXML_DOCB_ENABLED
4166 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004167#endif
4168 return(NULL);
4169 case XML_NAMESPACE_DECL:
4170 /*
4171 * TODO !!! may require extending struct _xmlNs with
4172 * parent field
4173 * C.f. Infoset case...
4174 */
4175 return(NULL);
4176 }
4177 return(NULL);
4178 }
4179 if (cur == ctxt->context->doc->children)
4180 return((xmlNodePtr) ctxt->context->doc);
4181 if (cur == (xmlNodePtr) ctxt->context->doc)
4182 return(NULL);
4183 switch (cur->type) {
4184 case XML_ELEMENT_NODE:
4185 case XML_TEXT_NODE:
4186 case XML_CDATA_SECTION_NODE:
4187 case XML_ENTITY_REF_NODE:
4188 case XML_ENTITY_NODE:
4189 case XML_PI_NODE:
4190 case XML_COMMENT_NODE:
4191 case XML_NOTATION_NODE:
4192 case XML_DTD_NODE:
4193 case XML_ELEMENT_DECL:
4194 case XML_ATTRIBUTE_DECL:
4195 case XML_ENTITY_DECL:
4196 case XML_XINCLUDE_START:
4197 case XML_XINCLUDE_END:
4198 return(cur->parent);
4199 case XML_ATTRIBUTE_NODE: {
4200 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4201
4202 return(att->parent);
4203 }
4204 case XML_DOCUMENT_NODE:
4205 case XML_DOCUMENT_TYPE_NODE:
4206 case XML_DOCUMENT_FRAG_NODE:
4207 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004208#ifdef LIBXML_DOCB_ENABLED
4209 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004210#endif
4211 return(NULL);
4212 case XML_NAMESPACE_DECL:
4213 /*
4214 * TODO !!! may require extending struct _xmlNs with
4215 * parent field
4216 * C.f. Infoset case...
4217 */
4218 return(NULL);
4219 }
4220 return(NULL);
4221}
4222
4223/**
4224 * xmlXPathNextAncestorOrSelf:
4225 * @ctxt: the XPath Parser context
4226 * @cur: the current node in the traversal
4227 *
4228 * Traversal function for the "ancestor-or-self" direction
4229 * he ancestor-or-self axis contains the context node and ancestors of
4230 * the context node in reverse document order; thus the context node is
4231 * the first node on the axis, and the context node's parent the second;
4232 * parent here is defined the same as with the parent axis.
4233 *
4234 * Returns the next element following that axis
4235 */
4236xmlNodePtr
4237xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4238 if (cur == NULL)
4239 return(ctxt->context->node);
4240 return(xmlXPathNextAncestor(ctxt, cur));
4241}
4242
4243/**
4244 * xmlXPathNextFollowingSibling:
4245 * @ctxt: the XPath Parser context
4246 * @cur: the current node in the traversal
4247 *
4248 * Traversal function for the "following-sibling" direction
4249 * The following-sibling axis contains the following siblings of the context
4250 * node in document order.
4251 *
4252 * Returns the next element following that axis
4253 */
4254xmlNodePtr
4255xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4256 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4257 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4258 return(NULL);
4259 if (cur == (xmlNodePtr) ctxt->context->doc)
4260 return(NULL);
4261 if (cur == NULL)
4262 return(ctxt->context->node->next);
4263 return(cur->next);
4264}
4265
4266/**
4267 * xmlXPathNextPrecedingSibling:
4268 * @ctxt: the XPath Parser context
4269 * @cur: the current node in the traversal
4270 *
4271 * Traversal function for the "preceding-sibling" direction
4272 * The preceding-sibling axis contains the preceding siblings of the context
4273 * node in reverse document order; the first preceding sibling is first on the
4274 * axis; the sibling preceding that node is the second on the axis and so on.
4275 *
4276 * Returns the next element following that axis
4277 */
4278xmlNodePtr
4279xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4280 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4281 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4282 return(NULL);
4283 if (cur == (xmlNodePtr) ctxt->context->doc)
4284 return(NULL);
4285 if (cur == NULL)
4286 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004287 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4288 cur = cur->prev;
4289 if (cur == NULL)
4290 return(ctxt->context->node->prev);
4291 }
Owen Taylor3473f882001-02-23 17:55:21 +00004292 return(cur->prev);
4293}
4294
4295/**
4296 * xmlXPathNextFollowing:
4297 * @ctxt: the XPath Parser context
4298 * @cur: the current node in the traversal
4299 *
4300 * Traversal function for the "following" direction
4301 * The following axis contains all nodes in the same document as the context
4302 * node that are after the context node in document order, excluding any
4303 * descendants and excluding attribute nodes and namespace nodes; the nodes
4304 * are ordered in document order
4305 *
4306 * Returns the next element following that axis
4307 */
4308xmlNodePtr
4309xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4310 if (cur != NULL && cur->children != NULL)
4311 return cur->children ;
4312 if (cur == NULL) cur = ctxt->context->node;
4313 if (cur == NULL) return(NULL) ; /* ERROR */
4314 if (cur->next != NULL) return(cur->next) ;
4315 do {
4316 cur = cur->parent;
4317 if (cur == NULL) return(NULL);
4318 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4319 if (cur->next != NULL) return(cur->next);
4320 } while (cur != NULL);
4321 return(cur);
4322}
4323
4324/*
4325 * xmlXPathIsAncestor:
4326 * @ancestor: the ancestor node
4327 * @node: the current node
4328 *
4329 * Check that @ancestor is a @node's ancestor
4330 *
4331 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4332 */
4333static int
4334xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4335 if ((ancestor == NULL) || (node == NULL)) return(0);
4336 /* nodes need to be in the same document */
4337 if (ancestor->doc != node->doc) return(0);
4338 /* avoid searching if ancestor or node is the root node */
4339 if (ancestor == (xmlNodePtr) node->doc) return(1);
4340 if (node == (xmlNodePtr) ancestor->doc) return(0);
4341 while (node->parent != NULL) {
4342 if (node->parent == ancestor)
4343 return(1);
4344 node = node->parent;
4345 }
4346 return(0);
4347}
4348
4349/**
4350 * xmlXPathNextPreceding:
4351 * @ctxt: the XPath Parser context
4352 * @cur: the current node in the traversal
4353 *
4354 * Traversal function for the "preceding" direction
4355 * the preceding axis contains all nodes in the same document as the context
4356 * node that are before the context node in document order, excluding any
4357 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4358 * ordered in reverse document order
4359 *
4360 * Returns the next element following that axis
4361 */
4362xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004363xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4364{
Owen Taylor3473f882001-02-23 17:55:21 +00004365 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004366 cur = ctxt->context->node;
4367 if (cur == NULL)
4368 return (NULL);
4369 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4370 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004371 do {
4372 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004373 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4374 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004375 }
4376
4377 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004378 if (cur == NULL)
4379 return (NULL);
4380 if (cur == ctxt->context->doc->children)
4381 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004382 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004383 return (cur);
4384}
4385
4386/**
4387 * xmlXPathNextPrecedingInternal:
4388 * @ctxt: the XPath Parser context
4389 * @cur: the current node in the traversal
4390 *
4391 * Traversal function for the "preceding" direction
4392 * the preceding axis contains all nodes in the same document as the context
4393 * node that are before the context node in document order, excluding any
4394 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4395 * ordered in reverse document order
4396 * This is a faster implementation but internal only since it requires a
4397 * state kept in the parser context: ctxt->ancestor.
4398 *
4399 * Returns the next element following that axis
4400 */
4401static xmlNodePtr
4402xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4403 xmlNodePtr cur)
4404{
4405 if (cur == NULL) {
4406 cur = ctxt->context->node;
4407 if (cur == NULL)
4408 return (NULL);
4409 ctxt->ancestor = cur->parent;
4410 }
4411 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4412 cur = cur->prev;
4413 while (cur->prev == NULL) {
4414 cur = cur->parent;
4415 if (cur == NULL)
4416 return (NULL);
4417 if (cur == ctxt->context->doc->children)
4418 return (NULL);
4419 if (cur != ctxt->ancestor)
4420 return (cur);
4421 ctxt->ancestor = cur->parent;
4422 }
4423 cur = cur->prev;
4424 while (cur->last != NULL)
4425 cur = cur->last;
4426 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004427}
4428
4429/**
4430 * xmlXPathNextNamespace:
4431 * @ctxt: the XPath Parser context
4432 * @cur: the current attribute in the traversal
4433 *
4434 * Traversal function for the "namespace" direction
4435 * the namespace axis contains the namespace nodes of the context node;
4436 * the order of nodes on this axis is implementation-defined; the axis will
4437 * be empty unless the context node is an element
4438 *
4439 * Returns the next element following that axis
4440 */
4441xmlNodePtr
4442xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4443 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
4444 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
4445 if (ctxt->context->namespaces != NULL)
4446 xmlFree(ctxt->context->namespaces);
4447 ctxt->context->namespaces =
4448 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
4449 if (ctxt->context->namespaces == NULL) return(NULL);
4450 ctxt->context->nsNr = 0;
4451 }
4452 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
4453}
4454
4455/**
4456 * xmlXPathNextAttribute:
4457 * @ctxt: the XPath Parser context
4458 * @cur: the current attribute in the traversal
4459 *
4460 * Traversal function for the "attribute" direction
4461 * TODO: support DTD inherited default attributes
4462 *
4463 * Returns the next element following that axis
4464 */
4465xmlNodePtr
4466xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00004467 if (ctxt->context->node == NULL)
4468 return(NULL);
4469 if (ctxt->context->node->type != XML_ELEMENT_NODE)
4470 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004471 if (cur == NULL) {
4472 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4473 return(NULL);
4474 return((xmlNodePtr)ctxt->context->node->properties);
4475 }
4476 return((xmlNodePtr)cur->next);
4477}
4478
4479/************************************************************************
4480 * *
4481 * NodeTest Functions *
4482 * *
4483 ************************************************************************/
4484
Owen Taylor3473f882001-02-23 17:55:21 +00004485#define IS_FUNCTION 200
4486
Owen Taylor3473f882001-02-23 17:55:21 +00004487
4488/************************************************************************
4489 * *
4490 * Implicit tree core function library *
4491 * *
4492 ************************************************************************/
4493
4494/**
4495 * xmlXPathRoot:
4496 * @ctxt: the XPath Parser context
4497 *
4498 * Initialize the context to the root of the document
4499 */
4500void
4501xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
4502 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
4503 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4504}
4505
4506/************************************************************************
4507 * *
4508 * The explicit core function library *
4509 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
4510 * *
4511 ************************************************************************/
4512
4513
4514/**
4515 * xmlXPathLastFunction:
4516 * @ctxt: the XPath Parser context
4517 * @nargs: the number of arguments
4518 *
4519 * Implement the last() XPath function
4520 * number last()
4521 * The last function returns the number of nodes in the context node list.
4522 */
4523void
4524xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4525 CHECK_ARITY(0);
4526 if (ctxt->context->contextSize >= 0) {
4527 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
4528#ifdef DEBUG_EXPR
4529 xmlGenericError(xmlGenericErrorContext,
4530 "last() : %d\n", ctxt->context->contextSize);
4531#endif
4532 } else {
4533 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
4534 }
4535}
4536
4537/**
4538 * xmlXPathPositionFunction:
4539 * @ctxt: the XPath Parser context
4540 * @nargs: the number of arguments
4541 *
4542 * Implement the position() XPath function
4543 * number position()
4544 * The position function returns the position of the context node in the
4545 * context node list. The first position is 1, and so the last positionr
4546 * will be equal to last().
4547 */
4548void
4549xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4550 CHECK_ARITY(0);
4551 if (ctxt->context->proximityPosition >= 0) {
4552 valuePush(ctxt,
4553 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
4554#ifdef DEBUG_EXPR
4555 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
4556 ctxt->context->proximityPosition);
4557#endif
4558 } else {
4559 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
4560 }
4561}
4562
4563/**
4564 * xmlXPathCountFunction:
4565 * @ctxt: the XPath Parser context
4566 * @nargs: the number of arguments
4567 *
4568 * Implement the count() XPath function
4569 * number count(node-set)
4570 */
4571void
4572xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4573 xmlXPathObjectPtr cur;
4574
4575 CHECK_ARITY(1);
4576 if ((ctxt->value == NULL) ||
4577 ((ctxt->value->type != XPATH_NODESET) &&
4578 (ctxt->value->type != XPATH_XSLT_TREE)))
4579 XP_ERROR(XPATH_INVALID_TYPE);
4580 cur = valuePop(ctxt);
4581
Daniel Veillard911f49a2001-04-07 15:39:35 +00004582 if ((cur == NULL) || (cur->nodesetval == NULL))
4583 valuePush(ctxt, xmlXPathNewFloat((double) 0));
4584 else
4585 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00004586 xmlXPathFreeObject(cur);
4587}
4588
4589/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004590 * xmlXPathGetElementsByIds:
4591 * @doc: the document
4592 * @ids: a whitespace separated list of IDs
4593 *
4594 * Selects elements by their unique ID.
4595 *
4596 * Returns a node-set of selected elements.
4597 */
4598static xmlNodeSetPtr
4599xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
4600 xmlNodeSetPtr ret;
4601 const xmlChar *cur = ids;
4602 xmlChar *ID;
4603 xmlAttrPtr attr;
4604 xmlNodePtr elem = NULL;
4605
4606 ret = xmlXPathNodeSetCreate(NULL);
4607
4608 while (IS_BLANK(*cur)) cur++;
4609 while (*cur != 0) {
4610 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
4611 (*cur == '.') || (*cur == '-') ||
4612 (*cur == '_') || (*cur == ':') ||
4613 (IS_COMBINING(*cur)) ||
4614 (IS_EXTENDER(*cur)))
4615 cur++;
4616
4617 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
4618
4619 ID = xmlStrndup(ids, cur - ids);
4620 attr = xmlGetID(doc, ID);
4621 if (attr != NULL) {
4622 elem = attr->parent;
4623 xmlXPathNodeSetAdd(ret, elem);
4624 }
4625 if (ID != NULL)
4626 xmlFree(ID);
4627
4628 while (IS_BLANK(*cur)) cur++;
4629 ids = cur;
4630 }
4631 return(ret);
4632}
4633
4634/**
Owen Taylor3473f882001-02-23 17:55:21 +00004635 * xmlXPathIdFunction:
4636 * @ctxt: the XPath Parser context
4637 * @nargs: the number of arguments
4638 *
4639 * Implement the id() XPath function
4640 * node-set id(object)
4641 * The id function selects elements by their unique ID
4642 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
4643 * then the result is the union of the result of applying id to the
4644 * string value of each of the nodes in the argument node-set. When the
4645 * argument to id is of any other type, the argument is converted to a
4646 * string as if by a call to the string function; the string is split
4647 * into a whitespace-separated list of tokens (whitespace is any sequence
4648 * of characters matching the production S); the result is a node-set
4649 * containing the elements in the same document as the context node that
4650 * have a unique ID equal to any of the tokens in the list.
4651 */
4652void
4653xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004654 xmlChar *tokens;
4655 xmlNodeSetPtr ret;
4656 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00004657
4658 CHECK_ARITY(1);
4659 obj = valuePop(ctxt);
4660 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
4661 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004662 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00004663 int i;
4664
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004665 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004666
Daniel Veillard911f49a2001-04-07 15:39:35 +00004667 if (obj->nodesetval != NULL) {
4668 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004669 tokens =
4670 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
4671 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
4672 ret = xmlXPathNodeSetMerge(ret, ns);
4673 xmlXPathFreeNodeSet(ns);
4674 if (tokens != NULL)
4675 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004676 }
Owen Taylor3473f882001-02-23 17:55:21 +00004677 }
4678
4679 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004680 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004681 return;
4682 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004683 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00004684
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004685 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
4686 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004687
Owen Taylor3473f882001-02-23 17:55:21 +00004688 xmlXPathFreeObject(obj);
4689 return;
4690}
4691
4692/**
4693 * xmlXPathLocalNameFunction:
4694 * @ctxt: the XPath Parser context
4695 * @nargs: the number of arguments
4696 *
4697 * Implement the local-name() XPath function
4698 * string local-name(node-set?)
4699 * The local-name function returns a string containing the local part
4700 * of the name of the node in the argument node-set that is first in
4701 * document order. If the node-set is empty or the first node has no
4702 * name, an empty string is returned. If the argument is omitted it
4703 * defaults to the context node.
4704 */
4705void
4706xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4707 xmlXPathObjectPtr cur;
4708
4709 if (nargs == 0) {
4710 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4711 nargs = 1;
4712 }
4713
4714 CHECK_ARITY(1);
4715 if ((ctxt->value == NULL) ||
4716 ((ctxt->value->type != XPATH_NODESET) &&
4717 (ctxt->value->type != XPATH_XSLT_TREE)))
4718 XP_ERROR(XPATH_INVALID_TYPE);
4719 cur = valuePop(ctxt);
4720
Daniel Veillard911f49a2001-04-07 15:39:35 +00004721 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004722 valuePush(ctxt, xmlXPathNewCString(""));
4723 } else {
4724 int i = 0; /* Should be first in document order !!!!! */
4725 switch (cur->nodesetval->nodeTab[i]->type) {
4726 case XML_ELEMENT_NODE:
4727 case XML_ATTRIBUTE_NODE:
4728 case XML_PI_NODE:
4729 valuePush(ctxt,
4730 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4731 break;
4732 case XML_NAMESPACE_DECL:
4733 valuePush(ctxt, xmlXPathNewString(
4734 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4735 break;
4736 default:
4737 valuePush(ctxt, xmlXPathNewCString(""));
4738 }
4739 }
4740 xmlXPathFreeObject(cur);
4741}
4742
4743/**
4744 * xmlXPathNamespaceURIFunction:
4745 * @ctxt: the XPath Parser context
4746 * @nargs: the number of arguments
4747 *
4748 * Implement the namespace-uri() XPath function
4749 * string namespace-uri(node-set?)
4750 * The namespace-uri function returns a string containing the
4751 * namespace URI of the expanded name of the node in the argument
4752 * node-set that is first in document order. If the node-set is empty,
4753 * the first node has no name, or the expanded name has no namespace
4754 * URI, an empty string is returned. If the argument is omitted it
4755 * defaults to the context node.
4756 */
4757void
4758xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4759 xmlXPathObjectPtr cur;
4760
4761 if (nargs == 0) {
4762 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4763 nargs = 1;
4764 }
4765 CHECK_ARITY(1);
4766 if ((ctxt->value == NULL) ||
4767 ((ctxt->value->type != XPATH_NODESET) &&
4768 (ctxt->value->type != XPATH_XSLT_TREE)))
4769 XP_ERROR(XPATH_INVALID_TYPE);
4770 cur = valuePop(ctxt);
4771
Daniel Veillard911f49a2001-04-07 15:39:35 +00004772 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004773 valuePush(ctxt, xmlXPathNewCString(""));
4774 } else {
4775 int i = 0; /* Should be first in document order !!!!! */
4776 switch (cur->nodesetval->nodeTab[i]->type) {
4777 case XML_ELEMENT_NODE:
4778 case XML_ATTRIBUTE_NODE:
4779 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4780 valuePush(ctxt, xmlXPathNewCString(""));
4781 else
4782 valuePush(ctxt, xmlXPathNewString(
4783 cur->nodesetval->nodeTab[i]->ns->href));
4784 break;
4785 default:
4786 valuePush(ctxt, xmlXPathNewCString(""));
4787 }
4788 }
4789 xmlXPathFreeObject(cur);
4790}
4791
4792/**
4793 * xmlXPathNameFunction:
4794 * @ctxt: the XPath Parser context
4795 * @nargs: the number of arguments
4796 *
4797 * Implement the name() XPath function
4798 * string name(node-set?)
4799 * The name function returns a string containing a QName representing
4800 * the name of the node in the argument node-set that is first in documenti
4801 * order. The QName must represent the name with respect to the namespace
4802 * declarations in effect on the node whose name is being represented.
4803 * Typically, this will be the form in which the name occurred in the XML
4804 * source. This need not be the case if there are namespace declarations
4805 * in effect on the node that associate multiple prefixes with the same
4806 * namespace. However, an implementation may include information about
4807 * the original prefix in its representation of nodes; in this case, an
4808 * implementation can ensure that the returned string is always the same
4809 * as the QName used in the XML source. If the argument it omitted it
4810 * defaults to the context node.
4811 * Libxml keep the original prefix so the "real qualified name" used is
4812 * returned.
4813 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004814static void
Owen Taylor3473f882001-02-23 17:55:21 +00004815xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4816 xmlXPathObjectPtr cur;
4817
4818 if (nargs == 0) {
4819 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4820 nargs = 1;
4821 }
4822
4823 CHECK_ARITY(1);
4824 if ((ctxt->value == NULL) ||
4825 ((ctxt->value->type != XPATH_NODESET) &&
4826 (ctxt->value->type != XPATH_XSLT_TREE)))
4827 XP_ERROR(XPATH_INVALID_TYPE);
4828 cur = valuePop(ctxt);
4829
Daniel Veillard911f49a2001-04-07 15:39:35 +00004830 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004831 valuePush(ctxt, xmlXPathNewCString(""));
4832 } else {
4833 int i = 0; /* Should be first in document order !!!!! */
4834
4835 switch (cur->nodesetval->nodeTab[i]->type) {
4836 case XML_ELEMENT_NODE:
4837 case XML_ATTRIBUTE_NODE:
4838 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4839 valuePush(ctxt, xmlXPathNewString(
4840 cur->nodesetval->nodeTab[i]->name));
4841
4842 else {
4843 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004844 snprintf(name, sizeof(name), "%s:%s",
4845 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4846 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004847 name[sizeof(name) - 1] = 0;
4848 valuePush(ctxt, xmlXPathNewCString(name));
4849 }
4850 break;
4851 default:
4852 valuePush(ctxt,
4853 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4854 xmlXPathLocalNameFunction(ctxt, 1);
4855 }
4856 }
4857 xmlXPathFreeObject(cur);
4858}
4859
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004860
4861/**
Owen Taylor3473f882001-02-23 17:55:21 +00004862 * xmlXPathStringFunction:
4863 * @ctxt: the XPath Parser context
4864 * @nargs: the number of arguments
4865 *
4866 * Implement the string() XPath function
4867 * string string(object?)
4868 * he string function converts an object to a string as follows:
4869 * - A node-set is converted to a string by returning the value of
4870 * the node in the node-set that is first in document order.
4871 * If the node-set is empty, an empty string is returned.
4872 * - A number is converted to a string as follows
4873 * + NaN is converted to the string NaN
4874 * + positive zero is converted to the string 0
4875 * + negative zero is converted to the string 0
4876 * + positive infinity is converted to the string Infinity
4877 * + negative infinity is converted to the string -Infinity
4878 * + if the number is an integer, the number is represented in
4879 * decimal form as a Number with no decimal point and no leading
4880 * zeros, preceded by a minus sign (-) if the number is negative
4881 * + otherwise, the number is represented in decimal form as a
4882 * Number including a decimal point with at least one digit
4883 * before the decimal point and at least one digit after the
4884 * decimal point, preceded by a minus sign (-) if the number
4885 * is negative; there must be no leading zeros before the decimal
4886 * point apart possibly from the one required digit immediatelyi
4887 * before the decimal point; beyond the one required digit
4888 * after the decimal point there must be as many, but only as
4889 * many, more digits as are needed to uniquely distinguish the
4890 * number from all other IEEE 754 numeric values.
4891 * - The boolean false value is converted to the string false.
4892 * The boolean true value is converted to the string true.
4893 *
4894 * If the argument is omitted, it defaults to a node-set with the
4895 * context node as its only member.
4896 */
4897void
4898xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4899 xmlXPathObjectPtr cur;
4900
4901 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004902 valuePush(ctxt,
4903 xmlXPathWrapString(
4904 xmlXPathCastNodeToString(ctxt->context->node)));
4905 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004906 }
4907
4908 CHECK_ARITY(1);
4909 cur = valuePop(ctxt);
4910 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004911 cur = xmlXPathConvertString(cur);
4912 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004913}
4914
4915/**
4916 * xmlXPathStringLengthFunction:
4917 * @ctxt: the XPath Parser context
4918 * @nargs: the number of arguments
4919 *
4920 * Implement the string-length() XPath function
4921 * number string-length(string?)
4922 * The string-length returns the number of characters in the string
4923 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4924 * the context node converted to a string, in other words the value
4925 * of the context node.
4926 */
4927void
4928xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4929 xmlXPathObjectPtr cur;
4930
4931 if (nargs == 0) {
4932 if (ctxt->context->node == NULL) {
4933 valuePush(ctxt, xmlXPathNewFloat(0));
4934 } else {
4935 xmlChar *content;
4936
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004937 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004938 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004939 xmlFree(content);
4940 }
4941 return;
4942 }
4943 CHECK_ARITY(1);
4944 CAST_TO_STRING;
4945 CHECK_TYPE(XPATH_STRING);
4946 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004947 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004948 xmlXPathFreeObject(cur);
4949}
4950
4951/**
4952 * xmlXPathConcatFunction:
4953 * @ctxt: the XPath Parser context
4954 * @nargs: the number of arguments
4955 *
4956 * Implement the concat() XPath function
4957 * string concat(string, string, string*)
4958 * The concat function returns the concatenation of its arguments.
4959 */
4960void
4961xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4962 xmlXPathObjectPtr cur, newobj;
4963 xmlChar *tmp;
4964
4965 if (nargs < 2) {
4966 CHECK_ARITY(2);
4967 }
4968
4969 CAST_TO_STRING;
4970 cur = valuePop(ctxt);
4971 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4972 xmlXPathFreeObject(cur);
4973 return;
4974 }
4975 nargs--;
4976
4977 while (nargs > 0) {
4978 CAST_TO_STRING;
4979 newobj = valuePop(ctxt);
4980 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4981 xmlXPathFreeObject(newobj);
4982 xmlXPathFreeObject(cur);
4983 XP_ERROR(XPATH_INVALID_TYPE);
4984 }
4985 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4986 newobj->stringval = cur->stringval;
4987 cur->stringval = tmp;
4988
4989 xmlXPathFreeObject(newobj);
4990 nargs--;
4991 }
4992 valuePush(ctxt, cur);
4993}
4994
4995/**
4996 * xmlXPathContainsFunction:
4997 * @ctxt: the XPath Parser context
4998 * @nargs: the number of arguments
4999 *
5000 * Implement the contains() XPath function
5001 * boolean contains(string, string)
5002 * The contains function returns true if the first argument string
5003 * contains the second argument string, and otherwise returns false.
5004 */
5005void
5006xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5007 xmlXPathObjectPtr hay, needle;
5008
5009 CHECK_ARITY(2);
5010 CAST_TO_STRING;
5011 CHECK_TYPE(XPATH_STRING);
5012 needle = valuePop(ctxt);
5013 CAST_TO_STRING;
5014 hay = valuePop(ctxt);
5015 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5016 xmlXPathFreeObject(hay);
5017 xmlXPathFreeObject(needle);
5018 XP_ERROR(XPATH_INVALID_TYPE);
5019 }
5020 if (xmlStrstr(hay->stringval, needle->stringval))
5021 valuePush(ctxt, xmlXPathNewBoolean(1));
5022 else
5023 valuePush(ctxt, xmlXPathNewBoolean(0));
5024 xmlXPathFreeObject(hay);
5025 xmlXPathFreeObject(needle);
5026}
5027
5028/**
5029 * xmlXPathStartsWithFunction:
5030 * @ctxt: the XPath Parser context
5031 * @nargs: the number of arguments
5032 *
5033 * Implement the starts-with() XPath function
5034 * boolean starts-with(string, string)
5035 * The starts-with function returns true if the first argument string
5036 * starts with the second argument string, and otherwise returns false.
5037 */
5038void
5039xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5040 xmlXPathObjectPtr hay, needle;
5041 int n;
5042
5043 CHECK_ARITY(2);
5044 CAST_TO_STRING;
5045 CHECK_TYPE(XPATH_STRING);
5046 needle = valuePop(ctxt);
5047 CAST_TO_STRING;
5048 hay = valuePop(ctxt);
5049 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5050 xmlXPathFreeObject(hay);
5051 xmlXPathFreeObject(needle);
5052 XP_ERROR(XPATH_INVALID_TYPE);
5053 }
5054 n = xmlStrlen(needle->stringval);
5055 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5056 valuePush(ctxt, xmlXPathNewBoolean(0));
5057 else
5058 valuePush(ctxt, xmlXPathNewBoolean(1));
5059 xmlXPathFreeObject(hay);
5060 xmlXPathFreeObject(needle);
5061}
5062
5063/**
5064 * xmlXPathSubstringFunction:
5065 * @ctxt: the XPath Parser context
5066 * @nargs: the number of arguments
5067 *
5068 * Implement the substring() XPath function
5069 * string substring(string, number, number?)
5070 * The substring function returns the substring of the first argument
5071 * starting at the position specified in the second argument with
5072 * length specified in the third argument. For example,
5073 * substring("12345",2,3) returns "234". If the third argument is not
5074 * specified, it returns the substring starting at the position specified
5075 * in the second argument and continuing to the end of the string. For
5076 * example, substring("12345",2) returns "2345". More precisely, each
5077 * character in the string (see [3.6 Strings]) is considered to have a
5078 * numeric position: the position of the first character is 1, the position
5079 * of the second character is 2 and so on. The returned substring contains
5080 * those characters for which the position of the character is greater than
5081 * or equal to the second argument and, if the third argument is specified,
5082 * less than the sum of the second and third arguments; the comparisons
5083 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5084 * - substring("12345", 1.5, 2.6) returns "234"
5085 * - substring("12345", 0, 3) returns "12"
5086 * - substring("12345", 0 div 0, 3) returns ""
5087 * - substring("12345", 1, 0 div 0) returns ""
5088 * - substring("12345", -42, 1 div 0) returns "12345"
5089 * - substring("12345", -1 div 0, 1 div 0) returns ""
5090 */
5091void
5092xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5093 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005094 double le=0, in;
5095 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005096 xmlChar *ret;
5097
Owen Taylor3473f882001-02-23 17:55:21 +00005098 if (nargs < 2) {
5099 CHECK_ARITY(2);
5100 }
5101 if (nargs > 3) {
5102 CHECK_ARITY(3);
5103 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005104 /*
5105 * take care of possible last (position) argument
5106 */
Owen Taylor3473f882001-02-23 17:55:21 +00005107 if (nargs == 3) {
5108 CAST_TO_NUMBER;
5109 CHECK_TYPE(XPATH_NUMBER);
5110 len = valuePop(ctxt);
5111 le = len->floatval;
5112 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005113 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005114
Owen Taylor3473f882001-02-23 17:55:21 +00005115 CAST_TO_NUMBER;
5116 CHECK_TYPE(XPATH_NUMBER);
5117 start = valuePop(ctxt);
5118 in = start->floatval;
5119 xmlXPathFreeObject(start);
5120 CAST_TO_STRING;
5121 CHECK_TYPE(XPATH_STRING);
5122 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005123 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005124
Daniel Veillard97ac1312001-05-30 19:14:17 +00005125 /*
5126 * If last pos not present, calculate last position
5127 */
5128 if (nargs != 3)
5129 le = m;
5130
5131 /*
5132 * To meet our requirements, initial index calculations
5133 * must be done before we convert to integer format
5134 *
5135 * First we normalize indices
5136 */
5137 in -= 1.0;
5138 le += in;
5139 if (in < 0.0)
5140 in = 0.0;
5141 if (le > (double)m)
5142 le = (double)m;
5143
5144 /*
5145 * Now we go to integer form, rounding up
5146 */
Owen Taylor3473f882001-02-23 17:55:21 +00005147 i = (int) in;
5148 if (((double)i) != in) i++;
5149
Owen Taylor3473f882001-02-23 17:55:21 +00005150 l = (int) le;
5151 if (((double)l) != le) l++;
5152
Daniel Veillard97ac1312001-05-30 19:14:17 +00005153 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005154
5155 /* number of chars to copy */
5156 l -= i;
5157
Daniel Veillard97ac1312001-05-30 19:14:17 +00005158 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005159 if (ret == NULL)
5160 valuePush(ctxt, xmlXPathNewCString(""));
5161 else {
5162 valuePush(ctxt, xmlXPathNewString(ret));
5163 xmlFree(ret);
5164 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005165
Owen Taylor3473f882001-02-23 17:55:21 +00005166 xmlXPathFreeObject(str);
5167}
5168
5169/**
5170 * xmlXPathSubstringBeforeFunction:
5171 * @ctxt: the XPath Parser context
5172 * @nargs: the number of arguments
5173 *
5174 * Implement the substring-before() XPath function
5175 * string substring-before(string, string)
5176 * The substring-before function returns the substring of the first
5177 * argument string that precedes the first occurrence of the second
5178 * argument string in the first argument string, or the empty string
5179 * if the first argument string does not contain the second argument
5180 * string. For example, substring-before("1999/04/01","/") returns 1999.
5181 */
5182void
5183xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5184 xmlXPathObjectPtr str;
5185 xmlXPathObjectPtr find;
5186 xmlBufferPtr target;
5187 const xmlChar *point;
5188 int offset;
5189
5190 CHECK_ARITY(2);
5191 CAST_TO_STRING;
5192 find = valuePop(ctxt);
5193 CAST_TO_STRING;
5194 str = valuePop(ctxt);
5195
5196 target = xmlBufferCreate();
5197 if (target) {
5198 point = xmlStrstr(str->stringval, find->stringval);
5199 if (point) {
5200 offset = (int)(point - str->stringval);
5201 xmlBufferAdd(target, str->stringval, offset);
5202 }
5203 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5204 xmlBufferFree(target);
5205 }
5206
5207 xmlXPathFreeObject(str);
5208 xmlXPathFreeObject(find);
5209}
5210
5211/**
5212 * xmlXPathSubstringAfterFunction:
5213 * @ctxt: the XPath Parser context
5214 * @nargs: the number of arguments
5215 *
5216 * Implement the substring-after() XPath function
5217 * string substring-after(string, string)
5218 * The substring-after function returns the substring of the first
5219 * argument string that follows the first occurrence of the second
5220 * argument string in the first argument string, or the empty stringi
5221 * if the first argument string does not contain the second argument
5222 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5223 * and substring-after("1999/04/01","19") returns 99/04/01.
5224 */
5225void
5226xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5227 xmlXPathObjectPtr str;
5228 xmlXPathObjectPtr find;
5229 xmlBufferPtr target;
5230 const xmlChar *point;
5231 int offset;
5232
5233 CHECK_ARITY(2);
5234 CAST_TO_STRING;
5235 find = valuePop(ctxt);
5236 CAST_TO_STRING;
5237 str = valuePop(ctxt);
5238
5239 target = xmlBufferCreate();
5240 if (target) {
5241 point = xmlStrstr(str->stringval, find->stringval);
5242 if (point) {
5243 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5244 xmlBufferAdd(target, &str->stringval[offset],
5245 xmlStrlen(str->stringval) - offset);
5246 }
5247 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5248 xmlBufferFree(target);
5249 }
5250
5251 xmlXPathFreeObject(str);
5252 xmlXPathFreeObject(find);
5253}
5254
5255/**
5256 * xmlXPathNormalizeFunction:
5257 * @ctxt: the XPath Parser context
5258 * @nargs: the number of arguments
5259 *
5260 * Implement the normalize-space() XPath function
5261 * string normalize-space(string?)
5262 * The normalize-space function returns the argument string with white
5263 * space normalized by stripping leading and trailing whitespace
5264 * and replacing sequences of whitespace characters by a single
5265 * space. Whitespace characters are the same allowed by the S production
5266 * in XML. If the argument is omitted, it defaults to the context
5267 * node converted to a string, in other words the value of the context node.
5268 */
5269void
5270xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5271 xmlXPathObjectPtr obj = NULL;
5272 xmlChar *source = NULL;
5273 xmlBufferPtr target;
5274 xmlChar blank;
5275
5276 if (nargs == 0) {
5277 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005278 valuePush(ctxt,
5279 xmlXPathWrapString(
5280 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005281 nargs = 1;
5282 }
5283
5284 CHECK_ARITY(1);
5285 CAST_TO_STRING;
5286 CHECK_TYPE(XPATH_STRING);
5287 obj = valuePop(ctxt);
5288 source = obj->stringval;
5289
5290 target = xmlBufferCreate();
5291 if (target && source) {
5292
5293 /* Skip leading whitespaces */
5294 while (IS_BLANK(*source))
5295 source++;
5296
5297 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5298 blank = 0;
5299 while (*source) {
5300 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005301 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005302 } else {
5303 if (blank) {
5304 xmlBufferAdd(target, &blank, 1);
5305 blank = 0;
5306 }
5307 xmlBufferAdd(target, source, 1);
5308 }
5309 source++;
5310 }
5311
5312 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5313 xmlBufferFree(target);
5314 }
5315 xmlXPathFreeObject(obj);
5316}
5317
5318/**
5319 * xmlXPathTranslateFunction:
5320 * @ctxt: the XPath Parser context
5321 * @nargs: the number of arguments
5322 *
5323 * Implement the translate() XPath function
5324 * string translate(string, string, string)
5325 * The translate function returns the first argument string with
5326 * occurrences of characters in the second argument string replaced
5327 * by the character at the corresponding position in the third argument
5328 * string. For example, translate("bar","abc","ABC") returns the string
5329 * BAr. If there is a character in the second argument string with no
5330 * character at a corresponding position in the third argument string
5331 * (because the second argument string is longer than the third argument
5332 * string), then occurrences of that character in the first argument
5333 * string are removed. For example, translate("--aaa--","abc-","ABC")
5334 * returns "AAA". If a character occurs more than once in second
5335 * argument string, then the first occurrence determines the replacement
5336 * character. If the third argument string is longer than the second
5337 * argument string, then excess characters are ignored.
5338 */
5339void
5340xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005341 xmlXPathObjectPtr str;
5342 xmlXPathObjectPtr from;
5343 xmlXPathObjectPtr to;
5344 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005345 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005346 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005347 xmlChar *point;
5348 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005349
Daniel Veillarde043ee12001-04-16 14:08:07 +00005350 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005351
Daniel Veillarde043ee12001-04-16 14:08:07 +00005352 CAST_TO_STRING;
5353 to = valuePop(ctxt);
5354 CAST_TO_STRING;
5355 from = valuePop(ctxt);
5356 CAST_TO_STRING;
5357 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005358
Daniel Veillarde043ee12001-04-16 14:08:07 +00005359 target = xmlBufferCreate();
5360 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005361 max = xmlUTF8Strlen(to->stringval);
5362 for (cptr = str->stringval; (ch=*cptr); ) {
5363 offset = xmlUTF8Strloc(from->stringval, cptr);
5364 if (offset >= 0) {
5365 if (offset < max) {
5366 point = xmlUTF8Strpos(to->stringval, offset);
5367 if (point)
5368 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5369 }
5370 } else
5371 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5372
5373 /* Step to next character in input */
5374 cptr++;
5375 if ( ch & 0x80 ) {
5376 /* if not simple ascii, verify proper format */
5377 if ( (ch & 0xc0) != 0xc0 ) {
5378 xmlGenericError(xmlGenericErrorContext,
5379 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5380 break;
5381 }
5382 /* then skip over remaining bytes for this char */
5383 while ( (ch <<= 1) & 0x80 )
5384 if ( (*cptr++ & 0xc0) != 0x80 ) {
5385 xmlGenericError(xmlGenericErrorContext,
5386 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5387 break;
5388 }
5389 if (ch & 0x80) /* must have had error encountered */
5390 break;
5391 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005392 }
Owen Taylor3473f882001-02-23 17:55:21 +00005393 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005394 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5395 xmlBufferFree(target);
5396 xmlXPathFreeObject(str);
5397 xmlXPathFreeObject(from);
5398 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005399}
5400
5401/**
5402 * xmlXPathBooleanFunction:
5403 * @ctxt: the XPath Parser context
5404 * @nargs: the number of arguments
5405 *
5406 * Implement the boolean() XPath function
5407 * boolean boolean(object)
5408 * he boolean function converts its argument to a boolean as follows:
5409 * - a number is true if and only if it is neither positive or
5410 * negative zero nor NaN
5411 * - a node-set is true if and only if it is non-empty
5412 * - a string is true if and only if its length is non-zero
5413 */
5414void
5415xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5416 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005417
5418 CHECK_ARITY(1);
5419 cur = valuePop(ctxt);
5420 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005421 cur = xmlXPathConvertBoolean(cur);
5422 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005423}
5424
5425/**
5426 * xmlXPathNotFunction:
5427 * @ctxt: the XPath Parser context
5428 * @nargs: the number of arguments
5429 *
5430 * Implement the not() XPath function
5431 * boolean not(boolean)
5432 * The not function returns true if its argument is false,
5433 * and false otherwise.
5434 */
5435void
5436xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5437 CHECK_ARITY(1);
5438 CAST_TO_BOOLEAN;
5439 CHECK_TYPE(XPATH_BOOLEAN);
5440 ctxt->value->boolval = ! ctxt->value->boolval;
5441}
5442
5443/**
5444 * xmlXPathTrueFunction:
5445 * @ctxt: the XPath Parser context
5446 * @nargs: the number of arguments
5447 *
5448 * Implement the true() XPath function
5449 * boolean true()
5450 */
5451void
5452xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5453 CHECK_ARITY(0);
5454 valuePush(ctxt, xmlXPathNewBoolean(1));
5455}
5456
5457/**
5458 * xmlXPathFalseFunction:
5459 * @ctxt: the XPath Parser context
5460 * @nargs: the number of arguments
5461 *
5462 * Implement the false() XPath function
5463 * boolean false()
5464 */
5465void
5466xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5467 CHECK_ARITY(0);
5468 valuePush(ctxt, xmlXPathNewBoolean(0));
5469}
5470
5471/**
5472 * xmlXPathLangFunction:
5473 * @ctxt: the XPath Parser context
5474 * @nargs: the number of arguments
5475 *
5476 * Implement the lang() XPath function
5477 * boolean lang(string)
5478 * The lang function returns true or false depending on whether the
5479 * language of the context node as specified by xml:lang attributes
5480 * is the same as or is a sublanguage of the language specified by
5481 * the argument string. The language of the context node is determined
5482 * by the value of the xml:lang attribute on the context node, or, if
5483 * the context node has no xml:lang attribute, by the value of the
5484 * xml:lang attribute on the nearest ancestor of the context node that
5485 * has an xml:lang attribute. If there is no such attribute, then lang
5486 * returns false. If there is such an attribute, then lang returns
5487 * true if the attribute value is equal to the argument ignoring case,
5488 * or if there is some suffix starting with - such that the attribute
5489 * value is equal to the argument ignoring that suffix of the attribute
5490 * value and ignoring case.
5491 */
5492void
5493xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5494 xmlXPathObjectPtr val;
5495 const xmlChar *theLang;
5496 const xmlChar *lang;
5497 int ret = 0;
5498 int i;
5499
5500 CHECK_ARITY(1);
5501 CAST_TO_STRING;
5502 CHECK_TYPE(XPATH_STRING);
5503 val = valuePop(ctxt);
5504 lang = val->stringval;
5505 theLang = xmlNodeGetLang(ctxt->context->node);
5506 if ((theLang != NULL) && (lang != NULL)) {
5507 for (i = 0;lang[i] != 0;i++)
5508 if (toupper(lang[i]) != toupper(theLang[i]))
5509 goto not_equal;
5510 ret = 1;
5511 }
5512not_equal:
5513 xmlXPathFreeObject(val);
5514 valuePush(ctxt, xmlXPathNewBoolean(ret));
5515}
5516
5517/**
5518 * xmlXPathNumberFunction:
5519 * @ctxt: the XPath Parser context
5520 * @nargs: the number of arguments
5521 *
5522 * Implement the number() XPath function
5523 * number number(object?)
5524 */
5525void
5526xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5527 xmlXPathObjectPtr cur;
5528 double res;
5529
5530 if (nargs == 0) {
5531 if (ctxt->context->node == NULL) {
5532 valuePush(ctxt, xmlXPathNewFloat(0.0));
5533 } else {
5534 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
5535
5536 res = xmlXPathStringEvalNumber(content);
5537 valuePush(ctxt, xmlXPathNewFloat(res));
5538 xmlFree(content);
5539 }
5540 return;
5541 }
5542
5543 CHECK_ARITY(1);
5544 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005545 cur = xmlXPathConvertNumber(cur);
5546 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005547}
5548
5549/**
5550 * xmlXPathSumFunction:
5551 * @ctxt: the XPath Parser context
5552 * @nargs: the number of arguments
5553 *
5554 * Implement the sum() XPath function
5555 * number sum(node-set)
5556 * The sum function returns the sum of the values of the nodes in
5557 * the argument node-set.
5558 */
5559void
5560xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5561 xmlXPathObjectPtr cur;
5562 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005563 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00005564
5565 CHECK_ARITY(1);
5566 if ((ctxt->value == NULL) ||
5567 ((ctxt->value->type != XPATH_NODESET) &&
5568 (ctxt->value->type != XPATH_XSLT_TREE)))
5569 XP_ERROR(XPATH_INVALID_TYPE);
5570 cur = valuePop(ctxt);
5571
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005572 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005573 valuePush(ctxt, xmlXPathNewFloat(0.0));
5574 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005575 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
5576 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00005577 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005578 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00005579 }
5580 xmlXPathFreeObject(cur);
5581}
5582
5583/**
5584 * xmlXPathFloorFunction:
5585 * @ctxt: the XPath Parser context
5586 * @nargs: the number of arguments
5587 *
5588 * Implement the floor() XPath function
5589 * number floor(number)
5590 * The floor function returns the largest (closest to positive infinity)
5591 * number that is not greater than the argument and that is an integer.
5592 */
5593void
5594xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5595 CHECK_ARITY(1);
5596 CAST_TO_NUMBER;
5597 CHECK_TYPE(XPATH_NUMBER);
5598#if 0
5599 ctxt->value->floatval = floor(ctxt->value->floatval);
5600#else
5601 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5602 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5603#endif
5604}
5605
5606/**
5607 * xmlXPathCeilingFunction:
5608 * @ctxt: the XPath Parser context
5609 * @nargs: the number of arguments
5610 *
5611 * Implement the ceiling() XPath function
5612 * number ceiling(number)
5613 * The ceiling function returns the smallest (closest to negative infinity)
5614 * number that is not less than the argument and that is an integer.
5615 */
5616void
5617xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5618 double f;
5619
5620 CHECK_ARITY(1);
5621 CAST_TO_NUMBER;
5622 CHECK_TYPE(XPATH_NUMBER);
5623
5624#if 0
5625 ctxt->value->floatval = ceil(ctxt->value->floatval);
5626#else
5627 f = (double)((int) ctxt->value->floatval);
5628 if (f != ctxt->value->floatval)
5629 ctxt->value->floatval = f + 1;
5630#endif
5631}
5632
5633/**
5634 * xmlXPathRoundFunction:
5635 * @ctxt: the XPath Parser context
5636 * @nargs: the number of arguments
5637 *
5638 * Implement the round() XPath function
5639 * number round(number)
5640 * The round function returns the number that is closest to the
5641 * argument and that is an integer. If there are two such numbers,
5642 * then the one that is even is returned.
5643 */
5644void
5645xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5646 double f;
5647
5648 CHECK_ARITY(1);
5649 CAST_TO_NUMBER;
5650 CHECK_TYPE(XPATH_NUMBER);
5651
5652 if ((ctxt->value->floatval == xmlXPathNAN) ||
5653 (ctxt->value->floatval == xmlXPathPINF) ||
5654 (ctxt->value->floatval == xmlXPathNINF) ||
5655 (ctxt->value->floatval == 0.0))
5656 return;
5657
5658#if 0
5659 f = floor(ctxt->value->floatval);
5660#else
5661 f = (double)((int) ctxt->value->floatval);
5662#endif
5663 if (ctxt->value->floatval < f + 0.5)
5664 ctxt->value->floatval = f;
5665 else
5666 ctxt->value->floatval = f + 1;
5667}
5668
5669/************************************************************************
5670 * *
5671 * The Parser *
5672 * *
5673 ************************************************************************/
5674
5675/*
5676 * a couple of forward declarations since we use a recursive call based
5677 * implementation.
5678 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005679static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005680static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005681static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005682#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005683static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5684#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005685#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005686static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005687#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005688static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5689 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005690
5691/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005692 * xmlXPathCurrentChar:
5693 * @ctxt: the XPath parser context
5694 * @cur: pointer to the beginning of the char
5695 * @len: pointer to the length of the char read
5696 *
5697 * The current char value, if using UTF-8 this may actaully span multiple
5698 * bytes in the input buffer.
5699 *
5700 * Returns the current char value and its lenght
5701 */
5702
5703static int
5704xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5705 unsigned char c;
5706 unsigned int val;
5707 const xmlChar *cur;
5708
5709 if (ctxt == NULL)
5710 return(0);
5711 cur = ctxt->cur;
5712
5713 /*
5714 * We are supposed to handle UTF8, check it's valid
5715 * From rfc2044: encoding of the Unicode values on UTF-8:
5716 *
5717 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5718 * 0000 0000-0000 007F 0xxxxxxx
5719 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5720 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5721 *
5722 * Check for the 0x110000 limit too
5723 */
5724 c = *cur;
5725 if (c & 0x80) {
5726 if ((cur[1] & 0xc0) != 0x80)
5727 goto encoding_error;
5728 if ((c & 0xe0) == 0xe0) {
5729
5730 if ((cur[2] & 0xc0) != 0x80)
5731 goto encoding_error;
5732 if ((c & 0xf0) == 0xf0) {
5733 if (((c & 0xf8) != 0xf0) ||
5734 ((cur[3] & 0xc0) != 0x80))
5735 goto encoding_error;
5736 /* 4-byte code */
5737 *len = 4;
5738 val = (cur[0] & 0x7) << 18;
5739 val |= (cur[1] & 0x3f) << 12;
5740 val |= (cur[2] & 0x3f) << 6;
5741 val |= cur[3] & 0x3f;
5742 } else {
5743 /* 3-byte code */
5744 *len = 3;
5745 val = (cur[0] & 0xf) << 12;
5746 val |= (cur[1] & 0x3f) << 6;
5747 val |= cur[2] & 0x3f;
5748 }
5749 } else {
5750 /* 2-byte code */
5751 *len = 2;
5752 val = (cur[0] & 0x1f) << 6;
5753 val |= cur[1] & 0x3f;
5754 }
5755 if (!IS_CHAR(val)) {
5756 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5757 }
5758 return(val);
5759 } else {
5760 /* 1-byte code */
5761 *len = 1;
5762 return((int) *cur);
5763 }
5764encoding_error:
5765 /*
5766 * If we detect an UTF8 error that probably mean that the
5767 * input encoding didn't get properly advertized in the
5768 * declaration header. Report the error and switch the encoding
5769 * to ISO-Latin-1 (if you don't like this policy, just declare the
5770 * encoding !)
5771 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00005772 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00005773 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005774}
5775
5776/**
Owen Taylor3473f882001-02-23 17:55:21 +00005777 * xmlXPathParseNCName:
5778 * @ctxt: the XPath Parser context
5779 *
5780 * parse an XML namespace non qualified name.
5781 *
5782 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5783 *
5784 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5785 * CombiningChar | Extender
5786 *
5787 * Returns the namespace name or NULL
5788 */
5789
5790xmlChar *
5791xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005792 const xmlChar *in;
5793 xmlChar *ret;
5794 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005795
Daniel Veillard2156a562001-04-28 12:24:34 +00005796 /*
5797 * Accelerator for simple ASCII names
5798 */
5799 in = ctxt->cur;
5800 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5801 ((*in >= 0x41) && (*in <= 0x5A)) ||
5802 (*in == '_')) {
5803 in++;
5804 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5805 ((*in >= 0x41) && (*in <= 0x5A)) ||
5806 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00005807 (*in == '_') || (*in == '.') ||
5808 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00005809 in++;
5810 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5811 (*in == '[') || (*in == ']') || (*in == ':') ||
5812 (*in == '@') || (*in == '*')) {
5813 count = in - ctxt->cur;
5814 if (count == 0)
5815 return(NULL);
5816 ret = xmlStrndup(ctxt->cur, count);
5817 ctxt->cur = in;
5818 return(ret);
5819 }
5820 }
5821 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005822}
5823
Daniel Veillard2156a562001-04-28 12:24:34 +00005824
Owen Taylor3473f882001-02-23 17:55:21 +00005825/**
5826 * xmlXPathParseQName:
5827 * @ctxt: the XPath Parser context
5828 * @prefix: a xmlChar **
5829 *
5830 * parse an XML qualified name
5831 *
5832 * [NS 5] QName ::= (Prefix ':')? LocalPart
5833 *
5834 * [NS 6] Prefix ::= NCName
5835 *
5836 * [NS 7] LocalPart ::= NCName
5837 *
5838 * Returns the function returns the local part, and prefix is updated
5839 * to get the Prefix if any.
5840 */
5841
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005842static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005843xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5844 xmlChar *ret = NULL;
5845
5846 *prefix = NULL;
5847 ret = xmlXPathParseNCName(ctxt);
5848 if (CUR == ':') {
5849 *prefix = ret;
5850 NEXT;
5851 ret = xmlXPathParseNCName(ctxt);
5852 }
5853 return(ret);
5854}
5855
5856/**
5857 * xmlXPathParseName:
5858 * @ctxt: the XPath Parser context
5859 *
5860 * parse an XML name
5861 *
5862 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5863 * CombiningChar | Extender
5864 *
5865 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5866 *
5867 * Returns the namespace name or NULL
5868 */
5869
5870xmlChar *
5871xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005872 const xmlChar *in;
5873 xmlChar *ret;
5874 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005875
Daniel Veillard61d80a22001-04-27 17:13:01 +00005876 /*
5877 * Accelerator for simple ASCII names
5878 */
5879 in = ctxt->cur;
5880 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5881 ((*in >= 0x41) && (*in <= 0x5A)) ||
5882 (*in == '_') || (*in == ':')) {
5883 in++;
5884 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5885 ((*in >= 0x41) && (*in <= 0x5A)) ||
5886 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00005887 (*in == '_') || (*in == '-') ||
5888 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00005889 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00005890 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005891 count = in - ctxt->cur;
5892 ret = xmlStrndup(ctxt->cur, count);
5893 ctxt->cur = in;
5894 return(ret);
5895 }
5896 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005897 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005898}
5899
Daniel Veillard61d80a22001-04-27 17:13:01 +00005900static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005901xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005902 xmlChar buf[XML_MAX_NAMELEN + 5];
5903 int len = 0, l;
5904 int c;
5905
5906 /*
5907 * Handler for more complex cases
5908 */
5909 c = CUR_CHAR(l);
5910 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005911 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5912 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005913 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005914 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005915 return(NULL);
5916 }
5917
5918 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5919 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5920 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005921 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005922 (IS_COMBINING(c)) ||
5923 (IS_EXTENDER(c)))) {
5924 COPY_BUF(l,buf,len,c);
5925 NEXTL(l);
5926 c = CUR_CHAR(l);
5927 if (len >= XML_MAX_NAMELEN) {
5928 /*
5929 * Okay someone managed to make a huge name, so he's ready to pay
5930 * for the processing speed.
5931 */
5932 xmlChar *buffer;
5933 int max = len * 2;
5934
5935 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5936 if (buffer == NULL) {
5937 XP_ERROR0(XPATH_MEMORY_ERROR);
5938 }
5939 memcpy(buffer, buf, len);
5940 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5941 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005942 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005943 (IS_COMBINING(c)) ||
5944 (IS_EXTENDER(c))) {
5945 if (len + 10 > max) {
5946 max *= 2;
5947 buffer = (xmlChar *) xmlRealloc(buffer,
5948 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00005949 if (buffer == NULL) {
5950 XP_ERROR0(XPATH_MEMORY_ERROR);
5951 }
5952 }
5953 COPY_BUF(l,buffer,len,c);
5954 NEXTL(l);
5955 c = CUR_CHAR(l);
5956 }
5957 buffer[len] = 0;
5958 return(buffer);
5959 }
5960 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005961 if (len == 0)
5962 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005963 return(xmlStrndup(buf, len));
5964}
Owen Taylor3473f882001-02-23 17:55:21 +00005965/**
5966 * xmlXPathStringEvalNumber:
5967 * @str: A string to scan
5968 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005969 * [30a] Float ::= Number ('e' Digits?)?
5970 *
Owen Taylor3473f882001-02-23 17:55:21 +00005971 * [30] Number ::= Digits ('.' Digits?)?
5972 * | '.' Digits
5973 * [31] Digits ::= [0-9]+
5974 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005975 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005976 * In complement of the Number expression, this function also handles
5977 * negative values : '-' Number.
5978 *
5979 * Returns the double value.
5980 */
5981double
5982xmlXPathStringEvalNumber(const xmlChar *str) {
5983 const xmlChar *cur = str;
5984 double ret = 0.0;
5985 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005986 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005987 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005988 int exponent = 0;
5989 int is_exponent_negative = 0;
5990
Owen Taylor3473f882001-02-23 17:55:21 +00005991 while (IS_BLANK(*cur)) cur++;
5992 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5993 return(xmlXPathNAN);
5994 }
5995 if (*cur == '-') {
5996 isneg = 1;
5997 cur++;
5998 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005999 /*
6000 * tmp is a workaroudn against a gcc compiler bug
6001 */
Owen Taylor3473f882001-02-23 17:55:21 +00006002 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006003 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006004 ok = 1;
6005 cur++;
6006 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006007 ret = (double) tmp;
6008
Owen Taylor3473f882001-02-23 17:55:21 +00006009 if (*cur == '.') {
6010 cur++;
6011 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6012 return(xmlXPathNAN);
6013 }
6014 while ((*cur >= '0') && (*cur <= '9')) {
6015 mult /= 10;
6016 ret = ret + (*cur - '0') * mult;
6017 cur++;
6018 }
6019 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006020 if ((*cur == 'e') || (*cur == 'E')) {
6021 cur++;
6022 if (*cur == '-') {
6023 is_exponent_negative = 1;
6024 cur++;
6025 }
6026 while ((*cur >= '0') && (*cur <= '9')) {
6027 exponent = exponent * 10 + (*cur - '0');
6028 cur++;
6029 }
6030 }
Owen Taylor3473f882001-02-23 17:55:21 +00006031 while (IS_BLANK(*cur)) cur++;
6032 if (*cur != 0) return(xmlXPathNAN);
6033 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006034 if (is_exponent_negative) exponent = -exponent;
6035 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006036 return(ret);
6037}
6038
6039/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006040 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006041 * @ctxt: the XPath Parser context
6042 *
6043 * [30] Number ::= Digits ('.' Digits?)?
6044 * | '.' Digits
6045 * [31] Digits ::= [0-9]+
6046 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006047 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006048 *
6049 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006050static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006051xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6052{
Owen Taylor3473f882001-02-23 17:55:21 +00006053 double ret = 0.0;
6054 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006055 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006056 int exponent = 0;
6057 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006058
6059 CHECK_ERROR;
6060 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6061 XP_ERROR(XPATH_NUMBER_ERROR);
6062 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006063 /*
6064 * Try to work around a gcc optimizer bug
6065 */
Owen Taylor3473f882001-02-23 17:55:21 +00006066 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006067 tmp = tmp * 10 + (CUR - '0');
6068 ok = 1;
6069 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006070 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006071 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006072 if (CUR == '.') {
6073 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006074 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6075 XP_ERROR(XPATH_NUMBER_ERROR);
6076 }
6077 while ((CUR >= '0') && (CUR <= '9')) {
6078 mult /= 10;
6079 ret = ret + (CUR - '0') * mult;
6080 NEXT;
6081 }
Owen Taylor3473f882001-02-23 17:55:21 +00006082 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006083 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006084 NEXT;
6085 if (CUR == '-') {
6086 is_exponent_negative = 1;
6087 NEXT;
6088 }
6089 while ((CUR >= '0') && (CUR <= '9')) {
6090 exponent = exponent * 10 + (CUR - '0');
6091 NEXT;
6092 }
6093 if (is_exponent_negative)
6094 exponent = -exponent;
6095 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006096 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006097 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006098 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006099}
6100
6101/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006102 * xmlXPathParseLiteral:
6103 * @ctxt: the XPath Parser context
6104 *
6105 * Parse a Literal
6106 *
6107 * [29] Literal ::= '"' [^"]* '"'
6108 * | "'" [^']* "'"
6109 *
6110 * Returns the value found or NULL in case of error
6111 */
6112static xmlChar *
6113xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6114 const xmlChar *q;
6115 xmlChar *ret = NULL;
6116
6117 if (CUR == '"') {
6118 NEXT;
6119 q = CUR_PTR;
6120 while ((IS_CHAR(CUR)) && (CUR != '"'))
6121 NEXT;
6122 if (!IS_CHAR(CUR)) {
6123 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6124 } else {
6125 ret = xmlStrndup(q, CUR_PTR - q);
6126 NEXT;
6127 }
6128 } else if (CUR == '\'') {
6129 NEXT;
6130 q = CUR_PTR;
6131 while ((IS_CHAR(CUR)) && (CUR != '\''))
6132 NEXT;
6133 if (!IS_CHAR(CUR)) {
6134 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6135 } else {
6136 ret = xmlStrndup(q, CUR_PTR - q);
6137 NEXT;
6138 }
6139 } else {
6140 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6141 }
6142 return(ret);
6143}
6144
6145/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006146 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006147 * @ctxt: the XPath Parser context
6148 *
6149 * Parse a Literal and push it on the stack.
6150 *
6151 * [29] Literal ::= '"' [^"]* '"'
6152 * | "'" [^']* "'"
6153 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006154 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006155 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006156static void
6157xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006158 const xmlChar *q;
6159 xmlChar *ret = NULL;
6160
6161 if (CUR == '"') {
6162 NEXT;
6163 q = CUR_PTR;
6164 while ((IS_CHAR(CUR)) && (CUR != '"'))
6165 NEXT;
6166 if (!IS_CHAR(CUR)) {
6167 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6168 } else {
6169 ret = xmlStrndup(q, CUR_PTR - q);
6170 NEXT;
6171 }
6172 } else if (CUR == '\'') {
6173 NEXT;
6174 q = CUR_PTR;
6175 while ((IS_CHAR(CUR)) && (CUR != '\''))
6176 NEXT;
6177 if (!IS_CHAR(CUR)) {
6178 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6179 } else {
6180 ret = xmlStrndup(q, CUR_PTR - q);
6181 NEXT;
6182 }
6183 } else {
6184 XP_ERROR(XPATH_START_LITERAL_ERROR);
6185 }
6186 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006187 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6188 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006189 xmlFree(ret);
6190}
6191
6192/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006193 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006194 * @ctxt: the XPath Parser context
6195 *
6196 * Parse a VariableReference, evaluate it and push it on the stack.
6197 *
6198 * The variable bindings consist of a mapping from variable names
6199 * to variable values. The value of a variable is an object, which
6200 * of any of the types that are possible for the value of an expression,
6201 * and may also be of additional types not specified here.
6202 *
6203 * Early evaluation is possible since:
6204 * The variable bindings [...] used to evaluate a subexpression are
6205 * always the same as those used to evaluate the containing expression.
6206 *
6207 * [36] VariableReference ::= '$' QName
6208 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006209static void
6210xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006211 xmlChar *name;
6212 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006213
6214 SKIP_BLANKS;
6215 if (CUR != '$') {
6216 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6217 }
6218 NEXT;
6219 name = xmlXPathParseQName(ctxt, &prefix);
6220 if (name == NULL) {
6221 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6222 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006223 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006224 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6225 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006226 SKIP_BLANKS;
6227}
6228
6229/**
6230 * xmlXPathIsNodeType:
6231 * @ctxt: the XPath Parser context
6232 * @name: a name string
6233 *
6234 * Is the name given a NodeType one.
6235 *
6236 * [38] NodeType ::= 'comment'
6237 * | 'text'
6238 * | 'processing-instruction'
6239 * | 'node'
6240 *
6241 * Returns 1 if true 0 otherwise
6242 */
6243int
6244xmlXPathIsNodeType(const xmlChar *name) {
6245 if (name == NULL)
6246 return(0);
6247
6248 if (xmlStrEqual(name, BAD_CAST "comment"))
6249 return(1);
6250 if (xmlStrEqual(name, BAD_CAST "text"))
6251 return(1);
6252 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6253 return(1);
6254 if (xmlStrEqual(name, BAD_CAST "node"))
6255 return(1);
6256 return(0);
6257}
6258
6259/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006260 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006261 * @ctxt: the XPath Parser context
6262 *
6263 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6264 * [17] Argument ::= Expr
6265 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006266 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006267 * pushed on the stack
6268 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006269static void
6270xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006271 xmlChar *name;
6272 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006273 int nbargs = 0;
6274
6275 name = xmlXPathParseQName(ctxt, &prefix);
6276 if (name == NULL) {
6277 XP_ERROR(XPATH_EXPR_ERROR);
6278 }
6279 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006280#ifdef DEBUG_EXPR
6281 if (prefix == NULL)
6282 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6283 name);
6284 else
6285 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6286 prefix, name);
6287#endif
6288
Owen Taylor3473f882001-02-23 17:55:21 +00006289 if (CUR != '(') {
6290 XP_ERROR(XPATH_EXPR_ERROR);
6291 }
6292 NEXT;
6293 SKIP_BLANKS;
6294
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006295 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006296 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006297 int op1 = ctxt->comp->last;
6298 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006299 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006300 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006301 nbargs++;
6302 if (CUR == ')') break;
6303 if (CUR != ',') {
6304 XP_ERROR(XPATH_EXPR_ERROR);
6305 }
6306 NEXT;
6307 SKIP_BLANKS;
6308 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006309 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6310 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006311 NEXT;
6312 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006313}
6314
6315/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006316 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006317 * @ctxt: the XPath Parser context
6318 *
6319 * [15] PrimaryExpr ::= VariableReference
6320 * | '(' Expr ')'
6321 * | Literal
6322 * | Number
6323 * | FunctionCall
6324 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006325 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006326 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006327static void
6328xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006329 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006330 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006331 else if (CUR == '(') {
6332 NEXT;
6333 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006334 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006335 if (CUR != ')') {
6336 XP_ERROR(XPATH_EXPR_ERROR);
6337 }
6338 NEXT;
6339 SKIP_BLANKS;
6340 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006341 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006342 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006343 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006344 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006345 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006346 }
6347 SKIP_BLANKS;
6348}
6349
6350/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006351 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006352 * @ctxt: the XPath Parser context
6353 *
6354 * [20] FilterExpr ::= PrimaryExpr
6355 * | FilterExpr Predicate
6356 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006357 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006358 * Square brackets are used to filter expressions in the same way that
6359 * they are used in location paths. It is an error if the expression to
6360 * be filtered does not evaluate to a node-set. The context node list
6361 * used for evaluating the expression in square brackets is the node-set
6362 * to be filtered listed in document order.
6363 */
6364
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006365static void
6366xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6367 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006368 CHECK_ERROR;
6369 SKIP_BLANKS;
6370
6371 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006372 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006373 SKIP_BLANKS;
6374 }
6375
6376
6377}
6378
6379/**
6380 * xmlXPathScanName:
6381 * @ctxt: the XPath Parser context
6382 *
6383 * Trickery: parse an XML name but without consuming the input flow
6384 * Needed to avoid insanity in the parser state.
6385 *
6386 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6387 * CombiningChar | Extender
6388 *
6389 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6390 *
6391 * [6] Names ::= Name (S Name)*
6392 *
6393 * Returns the Name parsed or NULL
6394 */
6395
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006396static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006397xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6398 xmlChar buf[XML_MAX_NAMELEN];
6399 int len = 0;
6400
6401 SKIP_BLANKS;
6402 if (!IS_LETTER(CUR) && (CUR != '_') &&
6403 (CUR != ':')) {
6404 return(NULL);
6405 }
6406
6407 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6408 (NXT(len) == '.') || (NXT(len) == '-') ||
6409 (NXT(len) == '_') || (NXT(len) == ':') ||
6410 (IS_COMBINING(NXT(len))) ||
6411 (IS_EXTENDER(NXT(len)))) {
6412 buf[len] = NXT(len);
6413 len++;
6414 if (len >= XML_MAX_NAMELEN) {
6415 xmlGenericError(xmlGenericErrorContext,
6416 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6417 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6418 (NXT(len) == '.') || (NXT(len) == '-') ||
6419 (NXT(len) == '_') || (NXT(len) == ':') ||
6420 (IS_COMBINING(NXT(len))) ||
6421 (IS_EXTENDER(NXT(len))))
6422 len++;
6423 break;
6424 }
6425 }
6426 return(xmlStrndup(buf, len));
6427}
6428
6429/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006430 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006431 * @ctxt: the XPath Parser context
6432 *
6433 * [19] PathExpr ::= LocationPath
6434 * | FilterExpr
6435 * | FilterExpr '/' RelativeLocationPath
6436 * | FilterExpr '//' RelativeLocationPath
6437 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006438 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006439 * The / operator and // operators combine an arbitrary expression
6440 * and a relative location path. It is an error if the expression
6441 * does not evaluate to a node-set.
6442 * The / operator does composition in the same way as when / is
6443 * used in a location path. As in location paths, // is short for
6444 * /descendant-or-self::node()/.
6445 */
6446
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006447static void
6448xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006449 int lc = 1; /* Should we branch to LocationPath ? */
6450 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6451
6452 SKIP_BLANKS;
6453 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6454 (CUR == '\'') || (CUR == '"')) {
6455 lc = 0;
6456 } else if (CUR == '*') {
6457 /* relative or absolute location path */
6458 lc = 1;
6459 } else if (CUR == '/') {
6460 /* relative or absolute location path */
6461 lc = 1;
6462 } else if (CUR == '@') {
6463 /* relative abbreviated attribute location path */
6464 lc = 1;
6465 } else if (CUR == '.') {
6466 /* relative abbreviated attribute location path */
6467 lc = 1;
6468 } else {
6469 /*
6470 * Problem is finding if we have a name here whether it's:
6471 * - a nodetype
6472 * - a function call in which case it's followed by '('
6473 * - an axis in which case it's followed by ':'
6474 * - a element name
6475 * We do an a priori analysis here rather than having to
6476 * maintain parsed token content through the recursive function
6477 * calls. This looks uglier but makes the code quite easier to
6478 * read/write/debug.
6479 */
6480 SKIP_BLANKS;
6481 name = xmlXPathScanName(ctxt);
6482 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6483#ifdef DEBUG_STEP
6484 xmlGenericError(xmlGenericErrorContext,
6485 "PathExpr: Axis\n");
6486#endif
6487 lc = 1;
6488 xmlFree(name);
6489 } else if (name != NULL) {
6490 int len =xmlStrlen(name);
6491 int blank = 0;
6492
6493
6494 while (NXT(len) != 0) {
6495 if (NXT(len) == '/') {
6496 /* element name */
6497#ifdef DEBUG_STEP
6498 xmlGenericError(xmlGenericErrorContext,
6499 "PathExpr: AbbrRelLocation\n");
6500#endif
6501 lc = 1;
6502 break;
6503 } else if (IS_BLANK(NXT(len))) {
6504 /* skip to next */
6505 blank = 1;
6506 } else if (NXT(len) == ':') {
6507#ifdef DEBUG_STEP
6508 xmlGenericError(xmlGenericErrorContext,
6509 "PathExpr: AbbrRelLocation\n");
6510#endif
6511 lc = 1;
6512 break;
6513 } else if ((NXT(len) == '(')) {
6514 /* Note Type or Function */
6515 if (xmlXPathIsNodeType(name)) {
6516#ifdef DEBUG_STEP
6517 xmlGenericError(xmlGenericErrorContext,
6518 "PathExpr: Type search\n");
6519#endif
6520 lc = 1;
6521 } else {
6522#ifdef DEBUG_STEP
6523 xmlGenericError(xmlGenericErrorContext,
6524 "PathExpr: function call\n");
6525#endif
6526 lc = 0;
6527 }
6528 break;
6529 } else if ((NXT(len) == '[')) {
6530 /* element name */
6531#ifdef DEBUG_STEP
6532 xmlGenericError(xmlGenericErrorContext,
6533 "PathExpr: AbbrRelLocation\n");
6534#endif
6535 lc = 1;
6536 break;
6537 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6538 (NXT(len) == '=')) {
6539 lc = 1;
6540 break;
6541 } else {
6542 lc = 1;
6543 break;
6544 }
6545 len++;
6546 }
6547 if (NXT(len) == 0) {
6548#ifdef DEBUG_STEP
6549 xmlGenericError(xmlGenericErrorContext,
6550 "PathExpr: AbbrRelLocation\n");
6551#endif
6552 /* element name */
6553 lc = 1;
6554 }
6555 xmlFree(name);
6556 } else {
6557 /* make sure all cases are covered explicitely */
6558 XP_ERROR(XPATH_EXPR_ERROR);
6559 }
6560 }
6561
6562 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006563 if (CUR == '/') {
6564 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6565 } else {
6566 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006567 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006568 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006569 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006570 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006571 CHECK_ERROR;
6572 if ((CUR == '/') && (NXT(1) == '/')) {
6573 SKIP(2);
6574 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006575
6576 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6577 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6578 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6579
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006580 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006581 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006582 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006583 }
6584 }
6585 SKIP_BLANKS;
6586}
6587
6588/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006589 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006590 * @ctxt: the XPath Parser context
6591 *
6592 * [18] UnionExpr ::= PathExpr
6593 * | UnionExpr '|' PathExpr
6594 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006595 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006596 */
6597
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006598static void
6599xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6600 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006601 CHECK_ERROR;
6602 SKIP_BLANKS;
6603 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006604 int op1 = ctxt->comp->last;
6605 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006606
6607 NEXT;
6608 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006609 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006610
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006611 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6612
Owen Taylor3473f882001-02-23 17:55:21 +00006613 SKIP_BLANKS;
6614 }
Owen Taylor3473f882001-02-23 17:55:21 +00006615}
6616
6617/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006618 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006619 * @ctxt: the XPath Parser context
6620 *
6621 * [27] UnaryExpr ::= UnionExpr
6622 * | '-' UnaryExpr
6623 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006624 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006625 */
6626
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006627static void
6628xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006629 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006630 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006631
6632 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006633 while (CUR == '-') {
6634 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006635 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006636 NEXT;
6637 SKIP_BLANKS;
6638 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006639
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006640 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006641 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006642 if (found) {
6643 if (minus)
6644 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6645 else
6646 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006647 }
6648}
6649
6650/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006651 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006652 * @ctxt: the XPath Parser context
6653 *
6654 * [26] MultiplicativeExpr ::= UnaryExpr
6655 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6656 * | MultiplicativeExpr 'div' UnaryExpr
6657 * | MultiplicativeExpr 'mod' UnaryExpr
6658 * [34] MultiplyOperator ::= '*'
6659 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006660 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006661 */
6662
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006663static void
6664xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6665 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006666 CHECK_ERROR;
6667 SKIP_BLANKS;
6668 while ((CUR == '*') ||
6669 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6670 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6671 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006672 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006673
6674 if (CUR == '*') {
6675 op = 0;
6676 NEXT;
6677 } else if (CUR == 'd') {
6678 op = 1;
6679 SKIP(3);
6680 } else if (CUR == 'm') {
6681 op = 2;
6682 SKIP(3);
6683 }
6684 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006685 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006686 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006687 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006688 SKIP_BLANKS;
6689 }
6690}
6691
6692/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006693 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006694 * @ctxt: the XPath Parser context
6695 *
6696 * [25] AdditiveExpr ::= MultiplicativeExpr
6697 * | AdditiveExpr '+' MultiplicativeExpr
6698 * | AdditiveExpr '-' MultiplicativeExpr
6699 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006700 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006701 */
6702
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006703static void
6704xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006705
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006706 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006707 CHECK_ERROR;
6708 SKIP_BLANKS;
6709 while ((CUR == '+') || (CUR == '-')) {
6710 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006711 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006712
6713 if (CUR == '+') plus = 1;
6714 else plus = 0;
6715 NEXT;
6716 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006717 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006718 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006719 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006720 SKIP_BLANKS;
6721 }
6722}
6723
6724/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006725 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006726 * @ctxt: the XPath Parser context
6727 *
6728 * [24] RelationalExpr ::= AdditiveExpr
6729 * | RelationalExpr '<' AdditiveExpr
6730 * | RelationalExpr '>' AdditiveExpr
6731 * | RelationalExpr '<=' AdditiveExpr
6732 * | RelationalExpr '>=' AdditiveExpr
6733 *
6734 * A <= B > C is allowed ? Answer from James, yes with
6735 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6736 * which is basically what got implemented.
6737 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006738 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006739 * on the stack
6740 */
6741
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006742static void
6743xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6744 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006745 CHECK_ERROR;
6746 SKIP_BLANKS;
6747 while ((CUR == '<') ||
6748 (CUR == '>') ||
6749 ((CUR == '<') && (NXT(1) == '=')) ||
6750 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006751 int inf, strict;
6752 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006753
6754 if (CUR == '<') inf = 1;
6755 else inf = 0;
6756 if (NXT(1) == '=') strict = 0;
6757 else strict = 1;
6758 NEXT;
6759 if (!strict) NEXT;
6760 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006761 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006762 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006763 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006764 SKIP_BLANKS;
6765 }
6766}
6767
6768/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006769 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006770 * @ctxt: the XPath Parser context
6771 *
6772 * [23] EqualityExpr ::= RelationalExpr
6773 * | EqualityExpr '=' RelationalExpr
6774 * | EqualityExpr '!=' RelationalExpr
6775 *
6776 * A != B != C is allowed ? Answer from James, yes with
6777 * (RelationalExpr = RelationalExpr) = RelationalExpr
6778 * (RelationalExpr != RelationalExpr) != RelationalExpr
6779 * which is basically what got implemented.
6780 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006781 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006782 *
6783 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006784static void
6785xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6786 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006787 CHECK_ERROR;
6788 SKIP_BLANKS;
6789 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006790 int eq;
6791 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006792
6793 if (CUR == '=') eq = 1;
6794 else eq = 0;
6795 NEXT;
6796 if (!eq) NEXT;
6797 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006798 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006799 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006800 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006801 SKIP_BLANKS;
6802 }
6803}
6804
6805/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006806 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006807 * @ctxt: the XPath Parser context
6808 *
6809 * [22] AndExpr ::= EqualityExpr
6810 * | AndExpr 'and' EqualityExpr
6811 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006812 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006813 *
6814 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006815static void
6816xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6817 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006818 CHECK_ERROR;
6819 SKIP_BLANKS;
6820 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006821 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006822 SKIP(3);
6823 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006824 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006825 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006826 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006827 SKIP_BLANKS;
6828 }
6829}
6830
6831/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006832 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006833 * @ctxt: the XPath Parser context
6834 *
6835 * [14] Expr ::= OrExpr
6836 * [21] OrExpr ::= AndExpr
6837 * | OrExpr 'or' AndExpr
6838 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006839 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006840 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006841static void
6842xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6843 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006844 CHECK_ERROR;
6845 SKIP_BLANKS;
6846 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006847 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006848 SKIP(2);
6849 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006850 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006851 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006852 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6853 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006854 SKIP_BLANKS;
6855 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006856 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6857 /* more ops could be optimized too */
6858 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6859 }
Owen Taylor3473f882001-02-23 17:55:21 +00006860}
6861
6862/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006863 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006864 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006865 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006866 *
6867 * [8] Predicate ::= '[' PredicateExpr ']'
6868 * [9] PredicateExpr ::= Expr
6869 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006870 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006871 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006872static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006873xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006874 int op1 = ctxt->comp->last;
6875
6876 SKIP_BLANKS;
6877 if (CUR != '[') {
6878 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6879 }
6880 NEXT;
6881 SKIP_BLANKS;
6882
6883 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006884 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006885 CHECK_ERROR;
6886
6887 if (CUR != ']') {
6888 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6889 }
6890
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006891 if (filter)
6892 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6893 else
6894 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006895
6896 NEXT;
6897 SKIP_BLANKS;
6898}
6899
6900/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006901 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006902 * @ctxt: the XPath Parser context
6903 * @test: pointer to a xmlXPathTestVal
6904 * @type: pointer to a xmlXPathTypeVal
6905 * @prefix: placeholder for a possible name prefix
6906 *
6907 * [7] NodeTest ::= NameTest
6908 * | NodeType '(' ')'
6909 * | 'processing-instruction' '(' Literal ')'
6910 *
6911 * [37] NameTest ::= '*'
6912 * | NCName ':' '*'
6913 * | QName
6914 * [38] NodeType ::= 'comment'
6915 * | 'text'
6916 * | 'processing-instruction'
6917 * | 'node'
6918 *
6919 * Returns the name found and update @test, @type and @prefix appropriately
6920 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006921static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006922xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6923 xmlXPathTypeVal *type, const xmlChar **prefix,
6924 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006925 int blanks;
6926
6927 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6928 STRANGE;
6929 return(NULL);
6930 }
6931 *type = 0;
6932 *test = 0;
6933 *prefix = NULL;
6934 SKIP_BLANKS;
6935
6936 if ((name == NULL) && (CUR == '*')) {
6937 /*
6938 * All elements
6939 */
6940 NEXT;
6941 *test = NODE_TEST_ALL;
6942 return(NULL);
6943 }
6944
6945 if (name == NULL)
6946 name = xmlXPathParseNCName(ctxt);
6947 if (name == NULL) {
6948 XP_ERROR0(XPATH_EXPR_ERROR);
6949 }
6950
6951 blanks = IS_BLANK(CUR);
6952 SKIP_BLANKS;
6953 if (CUR == '(') {
6954 NEXT;
6955 /*
6956 * NodeType or PI search
6957 */
6958 if (xmlStrEqual(name, BAD_CAST "comment"))
6959 *type = NODE_TYPE_COMMENT;
6960 else if (xmlStrEqual(name, BAD_CAST "node"))
6961 *type = NODE_TYPE_NODE;
6962 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6963 *type = NODE_TYPE_PI;
6964 else if (xmlStrEqual(name, BAD_CAST "text"))
6965 *type = NODE_TYPE_TEXT;
6966 else {
6967 if (name != NULL)
6968 xmlFree(name);
6969 XP_ERROR0(XPATH_EXPR_ERROR);
6970 }
6971
6972 *test = NODE_TEST_TYPE;
6973
6974 SKIP_BLANKS;
6975 if (*type == NODE_TYPE_PI) {
6976 /*
6977 * Specific case: search a PI by name.
6978 */
Owen Taylor3473f882001-02-23 17:55:21 +00006979 if (name != NULL)
6980 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006981 name = NULL;
6982 if (CUR != ')') {
6983 name = xmlXPathParseLiteral(ctxt);
6984 CHECK_ERROR 0;
6985 SKIP_BLANKS;
6986 }
Owen Taylor3473f882001-02-23 17:55:21 +00006987 }
6988 if (CUR != ')') {
6989 if (name != NULL)
6990 xmlFree(name);
6991 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6992 }
6993 NEXT;
6994 return(name);
6995 }
6996 *test = NODE_TEST_NAME;
6997 if ((!blanks) && (CUR == ':')) {
6998 NEXT;
6999
7000 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007001 * Since currently the parser context don't have a
7002 * namespace list associated:
7003 * The namespace name for this prefix can be computed
7004 * only at evaluation time. The compilation is done
7005 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007006 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007007#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007008 *prefix = xmlXPathNsLookup(ctxt->context, name);
7009 if (name != NULL)
7010 xmlFree(name);
7011 if (*prefix == NULL) {
7012 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7013 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007014#else
7015 *prefix = name;
7016#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007017
7018 if (CUR == '*') {
7019 /*
7020 * All elements
7021 */
7022 NEXT;
7023 *test = NODE_TEST_ALL;
7024 return(NULL);
7025 }
7026
7027 name = xmlXPathParseNCName(ctxt);
7028 if (name == NULL) {
7029 XP_ERROR0(XPATH_EXPR_ERROR);
7030 }
7031 }
7032 return(name);
7033}
7034
7035/**
7036 * xmlXPathIsAxisName:
7037 * @name: a preparsed name token
7038 *
7039 * [6] AxisName ::= 'ancestor'
7040 * | 'ancestor-or-self'
7041 * | 'attribute'
7042 * | 'child'
7043 * | 'descendant'
7044 * | 'descendant-or-self'
7045 * | 'following'
7046 * | 'following-sibling'
7047 * | 'namespace'
7048 * | 'parent'
7049 * | 'preceding'
7050 * | 'preceding-sibling'
7051 * | 'self'
7052 *
7053 * Returns the axis or 0
7054 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007055static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007056xmlXPathIsAxisName(const xmlChar *name) {
7057 xmlXPathAxisVal ret = 0;
7058 switch (name[0]) {
7059 case 'a':
7060 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7061 ret = AXIS_ANCESTOR;
7062 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7063 ret = AXIS_ANCESTOR_OR_SELF;
7064 if (xmlStrEqual(name, BAD_CAST "attribute"))
7065 ret = AXIS_ATTRIBUTE;
7066 break;
7067 case 'c':
7068 if (xmlStrEqual(name, BAD_CAST "child"))
7069 ret = AXIS_CHILD;
7070 break;
7071 case 'd':
7072 if (xmlStrEqual(name, BAD_CAST "descendant"))
7073 ret = AXIS_DESCENDANT;
7074 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7075 ret = AXIS_DESCENDANT_OR_SELF;
7076 break;
7077 case 'f':
7078 if (xmlStrEqual(name, BAD_CAST "following"))
7079 ret = AXIS_FOLLOWING;
7080 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7081 ret = AXIS_FOLLOWING_SIBLING;
7082 break;
7083 case 'n':
7084 if (xmlStrEqual(name, BAD_CAST "namespace"))
7085 ret = AXIS_NAMESPACE;
7086 break;
7087 case 'p':
7088 if (xmlStrEqual(name, BAD_CAST "parent"))
7089 ret = AXIS_PARENT;
7090 if (xmlStrEqual(name, BAD_CAST "preceding"))
7091 ret = AXIS_PRECEDING;
7092 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7093 ret = AXIS_PRECEDING_SIBLING;
7094 break;
7095 case 's':
7096 if (xmlStrEqual(name, BAD_CAST "self"))
7097 ret = AXIS_SELF;
7098 break;
7099 }
7100 return(ret);
7101}
7102
7103/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007104 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007105 * @ctxt: the XPath Parser context
7106 *
7107 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7108 * | AbbreviatedStep
7109 *
7110 * [12] AbbreviatedStep ::= '.' | '..'
7111 *
7112 * [5] AxisSpecifier ::= AxisName '::'
7113 * | AbbreviatedAxisSpecifier
7114 *
7115 * [13] AbbreviatedAxisSpecifier ::= '@'?
7116 *
7117 * Modified for XPtr range support as:
7118 *
7119 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7120 * | AbbreviatedStep
7121 * | 'range-to' '(' Expr ')' Predicate*
7122 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007123 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007124 * A location step of . is short for self::node(). This is
7125 * particularly useful in conjunction with //. For example, the
7126 * location path .//para is short for
7127 * self::node()/descendant-or-self::node()/child::para
7128 * and so will select all para descendant elements of the context
7129 * node.
7130 * Similarly, a location step of .. is short for parent::node().
7131 * For example, ../title is short for parent::node()/child::title
7132 * and so will select the title children of the parent of the context
7133 * node.
7134 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007135static void
7136xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007137#ifdef LIBXML_XPTR_ENABLED
7138 int rangeto = 0;
7139 int op2 = -1;
7140#endif
7141
Owen Taylor3473f882001-02-23 17:55:21 +00007142 SKIP_BLANKS;
7143 if ((CUR == '.') && (NXT(1) == '.')) {
7144 SKIP(2);
7145 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007146 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7147 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007148 } else if (CUR == '.') {
7149 NEXT;
7150 SKIP_BLANKS;
7151 } else {
7152 xmlChar *name = NULL;
7153 const xmlChar *prefix = NULL;
7154 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007155 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007156 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007157 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007158
7159 /*
7160 * The modification needed for XPointer change to the production
7161 */
7162#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007163 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007164 name = xmlXPathParseNCName(ctxt);
7165 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007166 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007167 xmlFree(name);
7168 SKIP_BLANKS;
7169 if (CUR != '(') {
7170 XP_ERROR(XPATH_EXPR_ERROR);
7171 }
7172 NEXT;
7173 SKIP_BLANKS;
7174
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007175 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007176 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007177 CHECK_ERROR;
7178
7179 SKIP_BLANKS;
7180 if (CUR != ')') {
7181 XP_ERROR(XPATH_EXPR_ERROR);
7182 }
7183 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007184 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007185 goto eval_predicates;
7186 }
7187 }
7188#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007189 if (CUR == '*') {
7190 axis = AXIS_CHILD;
7191 } else {
7192 if (name == NULL)
7193 name = xmlXPathParseNCName(ctxt);
7194 if (name != NULL) {
7195 axis = xmlXPathIsAxisName(name);
7196 if (axis != 0) {
7197 SKIP_BLANKS;
7198 if ((CUR == ':') && (NXT(1) == ':')) {
7199 SKIP(2);
7200 xmlFree(name);
7201 name = NULL;
7202 } else {
7203 /* an element name can conflict with an axis one :-\ */
7204 axis = AXIS_CHILD;
7205 }
Owen Taylor3473f882001-02-23 17:55:21 +00007206 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007207 axis = AXIS_CHILD;
7208 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007209 } else if (CUR == '@') {
7210 NEXT;
7211 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007212 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007213 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007214 }
Owen Taylor3473f882001-02-23 17:55:21 +00007215 }
7216
7217 CHECK_ERROR;
7218
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007219 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007220 if (test == 0)
7221 return;
7222
7223#ifdef DEBUG_STEP
7224 xmlGenericError(xmlGenericErrorContext,
7225 "Basis : computing new set\n");
7226#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007227
Owen Taylor3473f882001-02-23 17:55:21 +00007228#ifdef DEBUG_STEP
7229 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007230 if (ctxt->value == NULL)
7231 xmlGenericError(xmlGenericErrorContext, "no value\n");
7232 else if (ctxt->value->nodesetval == NULL)
7233 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7234 else
7235 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007236#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007237
7238eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007239 op1 = ctxt->comp->last;
7240 ctxt->comp->last = -1;
7241
Owen Taylor3473f882001-02-23 17:55:21 +00007242 SKIP_BLANKS;
7243 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007244 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007245 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007246
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007247#ifdef LIBXML_XPTR_ENABLED
7248 if (rangeto) {
7249 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7250 } else
7251#endif
7252 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7253 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007254
Owen Taylor3473f882001-02-23 17:55:21 +00007255 }
7256#ifdef DEBUG_STEP
7257 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007258 if (ctxt->value == NULL)
7259 xmlGenericError(xmlGenericErrorContext, "no value\n");
7260 else if (ctxt->value->nodesetval == NULL)
7261 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7262 else
7263 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7264 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007265#endif
7266}
7267
7268/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007269 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007270 * @ctxt: the XPath Parser context
7271 *
7272 * [3] RelativeLocationPath ::= Step
7273 * | RelativeLocationPath '/' Step
7274 * | AbbreviatedRelativeLocationPath
7275 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7276 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007277 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007278 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007279static void
Owen Taylor3473f882001-02-23 17:55:21 +00007280#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007281xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007282#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007283xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007284#endif
7285(xmlXPathParserContextPtr ctxt) {
7286 SKIP_BLANKS;
7287 if ((CUR == '/') && (NXT(1) == '/')) {
7288 SKIP(2);
7289 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007290 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7291 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007292 } else if (CUR == '/') {
7293 NEXT;
7294 SKIP_BLANKS;
7295 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007296 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007297 SKIP_BLANKS;
7298 while (CUR == '/') {
7299 if ((CUR == '/') && (NXT(1) == '/')) {
7300 SKIP(2);
7301 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007302 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007303 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007304 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007305 } else if (CUR == '/') {
7306 NEXT;
7307 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007308 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007309 }
7310 SKIP_BLANKS;
7311 }
7312}
7313
7314/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007315 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007316 * @ctxt: the XPath Parser context
7317 *
7318 * [1] LocationPath ::= RelativeLocationPath
7319 * | AbsoluteLocationPath
7320 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7321 * | AbbreviatedAbsoluteLocationPath
7322 * [10] AbbreviatedAbsoluteLocationPath ::=
7323 * '//' RelativeLocationPath
7324 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007325 * Compile a location path
7326 *
Owen Taylor3473f882001-02-23 17:55:21 +00007327 * // is short for /descendant-or-self::node()/. For example,
7328 * //para is short for /descendant-or-self::node()/child::para and
7329 * so will select any para element in the document (even a para element
7330 * that is a document element will be selected by //para since the
7331 * document element node is a child of the root node); div//para is
7332 * short for div/descendant-or-self::node()/child::para and so will
7333 * select all para descendants of div children.
7334 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007335static void
7336xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007337 SKIP_BLANKS;
7338 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007339 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007340 } else {
7341 while (CUR == '/') {
7342 if ((CUR == '/') && (NXT(1) == '/')) {
7343 SKIP(2);
7344 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007345 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7346 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007347 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007348 } else if (CUR == '/') {
7349 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007350 SKIP_BLANKS;
7351 if ((CUR != 0 ) &&
7352 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7353 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007354 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007355 }
7356 }
7357 }
7358}
7359
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007360/************************************************************************
7361 * *
7362 * XPath precompiled expression evaluation *
7363 * *
7364 ************************************************************************/
7365
Daniel Veillardf06307e2001-07-03 10:35:50 +00007366static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007367xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7368
7369/**
7370 * xmlXPathNodeCollectAndTest:
7371 * @ctxt: the XPath Parser context
7372 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007373 * @first: pointer to the first element in document order
7374 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007375 *
7376 * This is the function implementing a step: based on the current list
7377 * of nodes, it builds up a new list, looking at all nodes under that
7378 * axis and selecting them it also do the predicate filtering
7379 *
7380 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007381 *
7382 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007383 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007384static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007385xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007386 xmlXPathStepOpPtr op,
7387 xmlNodePtr * first, xmlNodePtr * last)
7388{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007389 xmlXPathAxisVal axis = op->value;
7390 xmlXPathTestVal test = op->value2;
7391 xmlXPathTypeVal type = op->value3;
7392 const xmlChar *prefix = op->value4;
7393 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007394 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007395
7396#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007397 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007398#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007399 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007400 xmlNodeSetPtr ret, list;
7401 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007402 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007403 xmlNodePtr cur = NULL;
7404 xmlXPathObjectPtr obj;
7405 xmlNodeSetPtr nodelist;
7406 xmlNodePtr tmp;
7407
Daniel Veillardf06307e2001-07-03 10:35:50 +00007408 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007409 obj = valuePop(ctxt);
7410 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007411 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007412 URI = xmlXPathNsLookup(ctxt->context, prefix);
7413 if (URI == NULL)
7414 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00007415 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007416#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007417 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007418#endif
7419 switch (axis) {
7420 case AXIS_ANCESTOR:
7421#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007422 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007423#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007424 first = NULL;
7425 next = xmlXPathNextAncestor;
7426 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007427 case AXIS_ANCESTOR_OR_SELF:
7428#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007429 xmlGenericError(xmlGenericErrorContext,
7430 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007431#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007432 first = NULL;
7433 next = xmlXPathNextAncestorOrSelf;
7434 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007435 case AXIS_ATTRIBUTE:
7436#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007437 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007438#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007439 first = NULL;
7440 last = NULL;
7441 next = xmlXPathNextAttribute;
7442 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007443 case AXIS_CHILD:
7444#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007445 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007446#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007447 last = NULL;
7448 next = xmlXPathNextChild;
7449 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007450 case AXIS_DESCENDANT:
7451#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007452 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007453#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007454 last = NULL;
7455 next = xmlXPathNextDescendant;
7456 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007457 case AXIS_DESCENDANT_OR_SELF:
7458#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007459 xmlGenericError(xmlGenericErrorContext,
7460 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007461#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007462 last = NULL;
7463 next = xmlXPathNextDescendantOrSelf;
7464 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007465 case AXIS_FOLLOWING:
7466#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007467 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007468#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007469 last = NULL;
7470 next = xmlXPathNextFollowing;
7471 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007472 case AXIS_FOLLOWING_SIBLING:
7473#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007474 xmlGenericError(xmlGenericErrorContext,
7475 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007476#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007477 last = NULL;
7478 next = xmlXPathNextFollowingSibling;
7479 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007480 case AXIS_NAMESPACE:
7481#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007482 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007483#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007484 first = NULL;
7485 last = NULL;
7486 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
7487 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007488 case AXIS_PARENT:
7489#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007490 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007491#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007492 first = NULL;
7493 next = xmlXPathNextParent;
7494 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007495 case AXIS_PRECEDING:
7496#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007497 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007498#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007499 first = NULL;
7500 next = xmlXPathNextPrecedingInternal;
7501 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007502 case AXIS_PRECEDING_SIBLING:
7503#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007504 xmlGenericError(xmlGenericErrorContext,
7505 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007506#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007507 first = NULL;
7508 next = xmlXPathNextPrecedingSibling;
7509 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007510 case AXIS_SELF:
7511#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007512 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007513#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007514 first = NULL;
7515 last = NULL;
7516 next = xmlXPathNextSelf;
7517 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007518 }
7519 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00007520 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007521
7522 nodelist = obj->nodesetval;
7523 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007524 xmlXPathFreeObject(obj);
7525 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7526 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007527 }
7528 addNode = xmlXPathNodeSetAddUnique;
7529 ret = NULL;
7530#ifdef DEBUG_STEP
7531 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007532 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007533 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007534 case NODE_TEST_NONE:
7535 xmlGenericError(xmlGenericErrorContext,
7536 " searching for none !!!\n");
7537 break;
7538 case NODE_TEST_TYPE:
7539 xmlGenericError(xmlGenericErrorContext,
7540 " searching for type %d\n", type);
7541 break;
7542 case NODE_TEST_PI:
7543 xmlGenericError(xmlGenericErrorContext,
7544 " searching for PI !!!\n");
7545 break;
7546 case NODE_TEST_ALL:
7547 xmlGenericError(xmlGenericErrorContext,
7548 " searching for *\n");
7549 break;
7550 case NODE_TEST_NS:
7551 xmlGenericError(xmlGenericErrorContext,
7552 " searching for namespace %s\n",
7553 prefix);
7554 break;
7555 case NODE_TEST_NAME:
7556 xmlGenericError(xmlGenericErrorContext,
7557 " searching for name %s\n", name);
7558 if (prefix != NULL)
7559 xmlGenericError(xmlGenericErrorContext,
7560 " with namespace %s\n", prefix);
7561 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007562 }
7563 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7564#endif
7565 /*
7566 * 2.3 Node Tests
7567 * - For the attribute axis, the principal node type is attribute.
7568 * - For the namespace axis, the principal node type is namespace.
7569 * - For other axes, the principal node type is element.
7570 *
7571 * A node test * is true for any node of the
7572 * principal node type. For example, child::* willi
7573 * select all element children of the context node
7574 */
7575 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007576 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007577 ctxt->context->node = nodelist->nodeTab[i];
7578
Daniel Veillardf06307e2001-07-03 10:35:50 +00007579 cur = NULL;
7580 list = xmlXPathNodeSetCreate(NULL);
7581 do {
7582 cur = next(ctxt, cur);
7583 if (cur == NULL)
7584 break;
7585 if ((first != NULL) && (*first == cur))
7586 break;
7587 if (((t % 256) == 0) &&
7588 (first != NULL) && (*first != NULL) &&
7589 (xmlXPathCmpNodes(*first, cur) >= 0))
7590 break;
7591 if ((last != NULL) && (*last == cur))
7592 break;
7593 if (((t % 256) == 0) &&
7594 (last != NULL) && (*last != NULL) &&
7595 (xmlXPathCmpNodes(cur, *last) >= 0))
7596 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007597 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007598#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007599 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7600#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007601 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007602 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007603 ctxt->context->node = tmp;
7604 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007605 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007606 if ((cur->type == type) ||
7607 ((type == NODE_TYPE_NODE) &&
7608 ((cur->type == XML_DOCUMENT_NODE) ||
7609 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7610 (cur->type == XML_ELEMENT_NODE) ||
7611 (cur->type == XML_PI_NODE) ||
7612 (cur->type == XML_COMMENT_NODE) ||
7613 (cur->type == XML_CDATA_SECTION_NODE) ||
7614 (cur->type == XML_TEXT_NODE)))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007615#ifdef DEBUG_STEP
7616 n++;
7617#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007618 addNode(list, cur);
7619 }
7620 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007621 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007622 if (cur->type == XML_PI_NODE) {
7623 if ((name != NULL) &&
7624 (!xmlStrEqual(name, cur->name)))
7625 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007626#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007627 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007628#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007629 addNode(list, cur);
7630 }
7631 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007632 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007633 if (axis == AXIS_ATTRIBUTE) {
7634 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007635#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007636 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007637#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007638 addNode(list, cur);
7639 }
7640 } else if (axis == AXIS_NAMESPACE) {
7641 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007642#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007643 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007644#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007645 addNode(list, cur);
7646 }
7647 } else {
7648 if (cur->type == XML_ELEMENT_NODE) {
7649 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007650#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007651 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007652#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007653 addNode(list, cur);
7654 } else if ((cur->ns != NULL) &&
7655 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007656#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007657 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007658#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007659 addNode(list, cur);
7660 }
7661 }
7662 }
7663 break;
7664 case NODE_TEST_NS:{
7665 TODO;
7666 break;
7667 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007668 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007669 switch (cur->type) {
7670 case XML_ELEMENT_NODE:
7671 if (xmlStrEqual(name, cur->name)) {
7672 if (prefix == NULL) {
7673 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007674#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007675 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007676#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007677 addNode(list, cur);
7678 }
7679 } else {
7680 if ((cur->ns != NULL) &&
7681 (xmlStrEqual(URI,
7682 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007683#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007684 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007685#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007686 addNode(list, cur);
7687 }
7688 }
7689 }
7690 break;
7691 case XML_ATTRIBUTE_NODE:{
7692 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007693
Daniel Veillardf06307e2001-07-03 10:35:50 +00007694 if (xmlStrEqual(name, attr->name)) {
7695 if (prefix == NULL) {
7696 if ((attr->ns == NULL) ||
7697 (attr->ns->prefix == NULL)) {
7698#ifdef DEBUG_STEP
7699 n++;
7700#endif
7701 addNode(list,
7702 (xmlNodePtr) attr);
7703 }
7704 } else {
7705 if ((attr->ns != NULL) &&
7706 (xmlStrEqual(URI,
7707 attr->ns->
7708 href))) {
7709#ifdef DEBUG_STEP
7710 n++;
7711#endif
7712 addNode(list,
7713 (xmlNodePtr) attr);
7714 }
7715 }
7716 }
7717 break;
7718 }
7719 case XML_NAMESPACE_DECL:
7720 if (cur->type == XML_NAMESPACE_DECL) {
7721 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007722
Daniel Veillardf06307e2001-07-03 10:35:50 +00007723 if ((ns->prefix != NULL) && (name != NULL)
7724 && (xmlStrEqual(ns->prefix, name))) {
7725#ifdef DEBUG_STEP
7726 n++;
7727#endif
7728 addNode(list, cur);
7729 }
7730 }
7731 break;
7732 default:
7733 break;
7734 }
7735 break;
7736 break;
7737 }
7738 } while (cur != NULL);
7739
7740 /*
7741 * If there is some predicate filtering do it now
7742 */
7743 if (op->ch2 != -1) {
7744 xmlXPathObjectPtr obj2;
7745
7746 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7747 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7748 CHECK_TYPE0(XPATH_NODESET);
7749 obj2 = valuePop(ctxt);
7750 list = obj2->nodesetval;
7751 obj2->nodesetval = NULL;
7752 xmlXPathFreeObject(obj2);
7753 }
7754 if (ret == NULL) {
7755 ret = list;
7756 } else {
7757 ret = xmlXPathNodeSetMerge(ret, list);
7758 xmlXPathFreeNodeSet(list);
7759 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007760 }
7761 ctxt->context->node = tmp;
7762#ifdef DEBUG_STEP
7763 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007764 "\nExamined %d nodes, found %d nodes at that step\n",
7765 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007766#endif
7767 xmlXPathFreeObject(obj);
7768 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +00007769 return(t);
7770}
7771
7772/**
7773 * xmlXPathNodeCollectAndTestNth:
7774 * @ctxt: the XPath Parser context
7775 * @op: the XPath precompiled step operation
7776 * @indx: the index to collect
7777 * @first: pointer to the first element in document order
7778 * @last: pointer to the last element in document order
7779 *
7780 * This is the function implementing a step: based on the current list
7781 * of nodes, it builds up a new list, looking at all nodes under that
7782 * axis and selecting them it also do the predicate filtering
7783 *
7784 * Pushes the new NodeSet resulting from the search.
7785 * Returns the number of node traversed
7786 */
7787static int
7788xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
7789 xmlXPathStepOpPtr op, int indx,
7790 xmlNodePtr * first, xmlNodePtr * last)
7791{
7792 xmlXPathAxisVal axis = op->value;
7793 xmlXPathTestVal test = op->value2;
7794 xmlXPathTypeVal type = op->value3;
7795 const xmlChar *prefix = op->value4;
7796 const xmlChar *name = op->value5;
7797 const xmlChar *URI = NULL;
7798 int n = 0, t = 0;
7799
7800 int i;
7801 xmlNodeSetPtr list;
7802 xmlXPathTraversalFunction next = NULL;
7803 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
7804 xmlNodePtr cur = NULL;
7805 xmlXPathObjectPtr obj;
7806 xmlNodeSetPtr nodelist;
7807 xmlNodePtr tmp;
7808
7809 CHECK_TYPE0(XPATH_NODESET);
7810 obj = valuePop(ctxt);
7811 addNode = xmlXPathNodeSetAdd;
7812 if (prefix != NULL) {
7813 URI = xmlXPathNsLookup(ctxt->context, prefix);
7814 if (URI == NULL)
7815 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7816 }
7817#ifdef DEBUG_STEP_NTH
7818 xmlGenericError(xmlGenericErrorContext, "new step : ");
7819 if (first != NULL) {
7820 if (*first != NULL)
7821 xmlGenericError(xmlGenericErrorContext, "first = %s ",
7822 (*first)->name);
7823 else
7824 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
7825 }
7826 if (last != NULL) {
7827 if (*last != NULL)
7828 xmlGenericError(xmlGenericErrorContext, "last = %s ",
7829 (*last)->name);
7830 else
7831 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
7832 }
7833#endif
7834 switch (axis) {
7835 case AXIS_ANCESTOR:
7836#ifdef DEBUG_STEP_NTH
7837 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
7838#endif
7839 first = NULL;
7840 next = xmlXPathNextAncestor;
7841 break;
7842 case AXIS_ANCESTOR_OR_SELF:
7843#ifdef DEBUG_STEP_NTH
7844 xmlGenericError(xmlGenericErrorContext,
7845 "axis 'ancestors-or-self' ");
7846#endif
7847 first = NULL;
7848 next = xmlXPathNextAncestorOrSelf;
7849 break;
7850 case AXIS_ATTRIBUTE:
7851#ifdef DEBUG_STEP_NTH
7852 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
7853#endif
7854 first = NULL;
7855 last = NULL;
7856 next = xmlXPathNextAttribute;
7857 break;
7858 case AXIS_CHILD:
7859#ifdef DEBUG_STEP_NTH
7860 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
7861#endif
7862 last = NULL;
7863 next = xmlXPathNextChild;
7864 break;
7865 case AXIS_DESCENDANT:
7866#ifdef DEBUG_STEP_NTH
7867 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
7868#endif
7869 last = NULL;
7870 next = xmlXPathNextDescendant;
7871 break;
7872 case AXIS_DESCENDANT_OR_SELF:
7873#ifdef DEBUG_STEP_NTH
7874 xmlGenericError(xmlGenericErrorContext,
7875 "axis 'descendant-or-self' ");
7876#endif
7877 last = NULL;
7878 next = xmlXPathNextDescendantOrSelf;
7879 break;
7880 case AXIS_FOLLOWING:
7881#ifdef DEBUG_STEP_NTH
7882 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
7883#endif
7884 last = NULL;
7885 next = xmlXPathNextFollowing;
7886 break;
7887 case AXIS_FOLLOWING_SIBLING:
7888#ifdef DEBUG_STEP_NTH
7889 xmlGenericError(xmlGenericErrorContext,
7890 "axis 'following-siblings' ");
7891#endif
7892 last = NULL;
7893 next = xmlXPathNextFollowingSibling;
7894 break;
7895 case AXIS_NAMESPACE:
7896#ifdef DEBUG_STEP_NTH
7897 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
7898#endif
7899 last = NULL;
7900 first = NULL;
7901 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
7902 break;
7903 case AXIS_PARENT:
7904#ifdef DEBUG_STEP_NTH
7905 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
7906#endif
7907 first = NULL;
7908 next = xmlXPathNextParent;
7909 break;
7910 case AXIS_PRECEDING:
7911#ifdef DEBUG_STEP_NTH
7912 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
7913#endif
7914 first = NULL;
7915 next = xmlXPathNextPrecedingInternal;
7916 break;
7917 case AXIS_PRECEDING_SIBLING:
7918#ifdef DEBUG_STEP_NTH
7919 xmlGenericError(xmlGenericErrorContext,
7920 "axis 'preceding-sibling' ");
7921#endif
7922 first = NULL;
7923 next = xmlXPathNextPrecedingSibling;
7924 break;
7925 case AXIS_SELF:
7926#ifdef DEBUG_STEP_NTH
7927 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
7928#endif
7929 first = NULL;
7930 last = NULL;
7931 next = xmlXPathNextSelf;
7932 break;
7933 }
7934 if (next == NULL)
7935 return(0);
7936
7937 nodelist = obj->nodesetval;
7938 if (nodelist == NULL) {
7939 xmlXPathFreeObject(obj);
7940 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7941 return(0);
7942 }
7943 addNode = xmlXPathNodeSetAddUnique;
7944#ifdef DEBUG_STEP_NTH
7945 xmlGenericError(xmlGenericErrorContext,
7946 " context contains %d nodes\n", nodelist->nodeNr);
7947 switch (test) {
7948 case NODE_TEST_NONE:
7949 xmlGenericError(xmlGenericErrorContext,
7950 " searching for none !!!\n");
7951 break;
7952 case NODE_TEST_TYPE:
7953 xmlGenericError(xmlGenericErrorContext,
7954 " searching for type %d\n", type);
7955 break;
7956 case NODE_TEST_PI:
7957 xmlGenericError(xmlGenericErrorContext,
7958 " searching for PI !!!\n");
7959 break;
7960 case NODE_TEST_ALL:
7961 xmlGenericError(xmlGenericErrorContext,
7962 " searching for *\n");
7963 break;
7964 case NODE_TEST_NS:
7965 xmlGenericError(xmlGenericErrorContext,
7966 " searching for namespace %s\n",
7967 prefix);
7968 break;
7969 case NODE_TEST_NAME:
7970 xmlGenericError(xmlGenericErrorContext,
7971 " searching for name %s\n", name);
7972 if (prefix != NULL)
7973 xmlGenericError(xmlGenericErrorContext,
7974 " with namespace %s\n", prefix);
7975 break;
7976 }
7977 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7978#endif
7979 /*
7980 * 2.3 Node Tests
7981 * - For the attribute axis, the principal node type is attribute.
7982 * - For the namespace axis, the principal node type is namespace.
7983 * - For other axes, the principal node type is element.
7984 *
7985 * A node test * is true for any node of the
7986 * principal node type. For example, child::* willi
7987 * select all element children of the context node
7988 */
7989 tmp = ctxt->context->node;
7990 list = xmlXPathNodeSetCreate(NULL);
7991 for (i = 0; i < nodelist->nodeNr; i++) {
7992 ctxt->context->node = nodelist->nodeTab[i];
7993
7994 cur = NULL;
7995 n = 0;
7996 do {
7997 cur = next(ctxt, cur);
7998 if (cur == NULL)
7999 break;
8000 if ((first != NULL) && (*first == cur))
8001 break;
8002 if (((t % 256) == 0) &&
8003 (first != NULL) && (*first != NULL) &&
8004 (xmlXPathCmpNodes(*first, cur) >= 0))
8005 break;
8006 if ((last != NULL) && (*last == cur))
8007 break;
8008 if (((t % 256) == 0) &&
8009 (last != NULL) && (*last != NULL) &&
8010 (xmlXPathCmpNodes(cur, *last) >= 0))
8011 break;
8012 t++;
8013 switch (test) {
8014 case NODE_TEST_NONE:
8015 ctxt->context->node = tmp;
8016 STRANGE return(0);
8017 case NODE_TEST_TYPE:
8018 if ((cur->type == type) ||
8019 ((type == NODE_TYPE_NODE) &&
8020 ((cur->type == XML_DOCUMENT_NODE) ||
8021 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8022 (cur->type == XML_ELEMENT_NODE) ||
8023 (cur->type == XML_PI_NODE) ||
8024 (cur->type == XML_COMMENT_NODE) ||
8025 (cur->type == XML_CDATA_SECTION_NODE) ||
8026 (cur->type == XML_TEXT_NODE)))) {
8027 n++;
8028 if (n == indx)
8029 addNode(list, cur);
8030 }
8031 break;
8032 case NODE_TEST_PI:
8033 if (cur->type == XML_PI_NODE) {
8034 if ((name != NULL) &&
8035 (!xmlStrEqual(name, cur->name)))
8036 break;
8037 n++;
8038 if (n == indx)
8039 addNode(list, cur);
8040 }
8041 break;
8042 case NODE_TEST_ALL:
8043 if (axis == AXIS_ATTRIBUTE) {
8044 if (cur->type == XML_ATTRIBUTE_NODE) {
8045 n++;
8046 if (n == indx)
8047 addNode(list, cur);
8048 }
8049 } else if (axis == AXIS_NAMESPACE) {
8050 if (cur->type == XML_NAMESPACE_DECL) {
8051 n++;
8052 if (n == indx)
8053 addNode(list, cur);
8054 }
8055 } else {
8056 if (cur->type == XML_ELEMENT_NODE) {
8057 if (prefix == NULL) {
8058 n++;
8059 if (n == indx)
8060 addNode(list, cur);
8061 } else if ((cur->ns != NULL) &&
8062 (xmlStrEqual(URI, cur->ns->href))) {
8063 n++;
8064 if (n == indx)
8065 addNode(list, cur);
8066 }
8067 }
8068 }
8069 break;
8070 case NODE_TEST_NS:{
8071 TODO;
8072 break;
8073 }
8074 case NODE_TEST_NAME:
8075 switch (cur->type) {
8076 case XML_ELEMENT_NODE:
8077 if (xmlStrEqual(name, cur->name)) {
8078 if (prefix == NULL) {
8079 if (cur->ns == NULL) {
8080 n++;
8081 if (n == indx)
8082 addNode(list, cur);
8083 }
8084 } else {
8085 if ((cur->ns != NULL) &&
8086 (xmlStrEqual(URI,
8087 cur->ns->href))) {
8088 n++;
8089 if (n == indx)
8090 addNode(list, cur);
8091 }
8092 }
8093 }
8094 break;
8095 case XML_ATTRIBUTE_NODE:{
8096 xmlAttrPtr attr = (xmlAttrPtr) cur;
8097
8098 if (xmlStrEqual(name, attr->name)) {
8099 if (prefix == NULL) {
8100 if ((attr->ns == NULL) ||
8101 (attr->ns->prefix == NULL)) {
8102 n++;
8103 if (n == indx)
8104 addNode(list, cur);
8105 }
8106 } else {
8107 if ((attr->ns != NULL) &&
8108 (xmlStrEqual(URI,
8109 attr->ns->
8110 href))) {
8111 n++;
8112 if (n == indx)
8113 addNode(list, cur);
8114 }
8115 }
8116 }
8117 break;
8118 }
8119 case XML_NAMESPACE_DECL:
8120 if (cur->type == XML_NAMESPACE_DECL) {
8121 xmlNsPtr ns = (xmlNsPtr) cur;
8122
8123 if ((ns->prefix != NULL) && (name != NULL)
8124 && (xmlStrEqual(ns->prefix, name))) {
8125 n++;
8126 if (n == indx)
8127 addNode(list, cur);
8128 }
8129 }
8130 break;
8131 default:
8132 break;
8133 }
8134 break;
8135 break;
8136 }
8137 } while (n < indx);
8138 }
8139 ctxt->context->node = tmp;
8140#ifdef DEBUG_STEP_NTH
8141 xmlGenericError(xmlGenericErrorContext,
8142 "\nExamined %d nodes, found %d nodes at that step\n",
8143 t, list->nodeNr);
8144#endif
8145 xmlXPathFreeObject(obj);
8146 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8147 return(t);
8148}
8149
8150/**
8151 * xmlXPathCompOpEvalFirst:
8152 * @ctxt: the XPath parser context with the compiled expression
8153 * @op: an XPath compiled operation
8154 * @first: the first elem found so far
8155 *
8156 * Evaluate the Precompiled XPath operation searching only the first
8157 * element in document order
8158 *
8159 * Returns the number of examined objects.
8160 */
8161static int
8162xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8163 xmlXPathStepOpPtr op, xmlNodePtr * first)
8164{
8165 int total = 0, cur;
8166 xmlXPathCompExprPtr comp;
8167 xmlXPathObjectPtr arg1, arg2;
8168
8169 comp = ctxt->comp;
8170 switch (op->op) {
8171 case XPATH_OP_END:
8172 return (0);
8173 case XPATH_OP_UNION:
8174 total =
8175 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8176 first);
8177 if ((ctxt->value != NULL)
8178 && (ctxt->value->type == XPATH_NODESET)
8179 && (ctxt->value->nodesetval != NULL)
8180 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8181 /*
8182 * limit tree traversing to first node in the result
8183 */
8184 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8185 *first = ctxt->value->nodesetval->nodeTab[0];
8186 }
8187 cur =
8188 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8189 first);
8190 CHECK_TYPE0(XPATH_NODESET);
8191 arg2 = valuePop(ctxt);
8192
8193 CHECK_TYPE0(XPATH_NODESET);
8194 arg1 = valuePop(ctxt);
8195
8196 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8197 arg2->nodesetval);
8198 valuePush(ctxt, arg1);
8199 xmlXPathFreeObject(arg2);
8200 /* optimizer */
8201 if (total > cur)
8202 xmlXPathCompSwap(op);
8203 return (total + cur);
8204 case XPATH_OP_ROOT:
8205 xmlXPathRoot(ctxt);
8206 return (0);
8207 case XPATH_OP_NODE:
8208 if (op->ch1 != -1)
8209 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8210 if (op->ch2 != -1)
8211 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8212 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8213 return (total);
8214 case XPATH_OP_RESET:
8215 if (op->ch1 != -1)
8216 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8217 if (op->ch2 != -1)
8218 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8219 ctxt->context->node = NULL;
8220 return (total);
8221 case XPATH_OP_COLLECT:{
8222 if (op->ch1 == -1)
8223 return (total);
8224
8225 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8226
8227 /*
8228 * Optimization for [n] selection where n is a number
8229 */
8230 if ((op->ch2 != -1) &&
8231 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8232 (comp->steps[op->ch2].ch1 == -1) &&
8233 (comp->steps[op->ch2].ch2 != -1) &&
8234 (comp->steps[comp->steps[op->ch2].ch2].op ==
8235 XPATH_OP_VALUE)) {
8236 xmlXPathObjectPtr val;
8237
8238 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8239 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8240 int indx = (int) val->floatval;
8241
8242 if (val->floatval == (float) indx) {
8243 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8244 first, NULL);
8245 return (total);
8246 }
8247 }
8248 }
8249 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8250 return (total);
8251 }
8252 case XPATH_OP_VALUE:
8253 valuePush(ctxt,
8254 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8255 return (0);
8256 case XPATH_OP_SORT:
8257 if (op->ch1 != -1)
8258 total +=
8259 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8260 first);
8261 if ((ctxt->value != NULL)
8262 && (ctxt->value->type == XPATH_NODESET)
8263 && (ctxt->value->nodesetval != NULL))
8264 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8265 return (total);
8266 default:
8267 return (xmlXPathCompOpEval(ctxt, op));
8268 }
8269}
8270
8271/**
8272 * xmlXPathCompOpEvalLast:
8273 * @ctxt: the XPath parser context with the compiled expression
8274 * @op: an XPath compiled operation
8275 * @last: the last elem found so far
8276 *
8277 * Evaluate the Precompiled XPath operation searching only the last
8278 * element in document order
8279 *
8280 * Returns the number of node traversed
8281 */
8282static int
8283xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8284 xmlNodePtr * last)
8285{
8286 int total = 0, cur;
8287 xmlXPathCompExprPtr comp;
8288 xmlXPathObjectPtr arg1, arg2;
8289
8290 comp = ctxt->comp;
8291 switch (op->op) {
8292 case XPATH_OP_END:
8293 return (0);
8294 case XPATH_OP_UNION:
8295 total =
8296 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8297 if ((ctxt->value != NULL)
8298 && (ctxt->value->type == XPATH_NODESET)
8299 && (ctxt->value->nodesetval != NULL)
8300 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8301 /*
8302 * limit tree traversing to first node in the result
8303 */
8304 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8305 *last =
8306 ctxt->value->nodesetval->nodeTab[ctxt->value->
8307 nodesetval->nodeNr -
8308 1];
8309 }
8310 cur =
8311 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8312 if ((ctxt->value != NULL)
8313 && (ctxt->value->type == XPATH_NODESET)
8314 && (ctxt->value->nodesetval != NULL)
8315 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8316 }
8317 CHECK_TYPE0(XPATH_NODESET);
8318 arg2 = valuePop(ctxt);
8319
8320 CHECK_TYPE0(XPATH_NODESET);
8321 arg1 = valuePop(ctxt);
8322
8323 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8324 arg2->nodesetval);
8325 valuePush(ctxt, arg1);
8326 xmlXPathFreeObject(arg2);
8327 /* optimizer */
8328 if (total > cur)
8329 xmlXPathCompSwap(op);
8330 return (total + cur);
8331 case XPATH_OP_ROOT:
8332 xmlXPathRoot(ctxt);
8333 return (0);
8334 case XPATH_OP_NODE:
8335 if (op->ch1 != -1)
8336 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8337 if (op->ch2 != -1)
8338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8339 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8340 return (total);
8341 case XPATH_OP_RESET:
8342 if (op->ch1 != -1)
8343 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8344 if (op->ch2 != -1)
8345 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8346 ctxt->context->node = NULL;
8347 return (total);
8348 case XPATH_OP_COLLECT:{
8349 if (op->ch1 == -1)
8350 return (0);
8351
8352 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8353
8354 /*
8355 * Optimization for [n] selection where n is a number
8356 */
8357 if ((op->ch2 != -1) &&
8358 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8359 (comp->steps[op->ch2].ch1 == -1) &&
8360 (comp->steps[op->ch2].ch2 != -1) &&
8361 (comp->steps[comp->steps[op->ch2].ch2].op ==
8362 XPATH_OP_VALUE)) {
8363 xmlXPathObjectPtr val;
8364
8365 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8366 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8367 int indx = (int) val->floatval;
8368
8369 if (val->floatval == (float) indx) {
8370 total +=
8371 xmlXPathNodeCollectAndTestNth(ctxt, op,
8372 indx, NULL,
8373 last);
8374 return (total);
8375 }
8376 }
8377 }
8378 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8379 return (total);
8380 }
8381 case XPATH_OP_VALUE:
8382 valuePush(ctxt,
8383 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8384 return (0);
8385 case XPATH_OP_SORT:
8386 if (op->ch1 != -1)
8387 total +=
8388 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8389 last);
8390 if ((ctxt->value != NULL)
8391 && (ctxt->value->type == XPATH_NODESET)
8392 && (ctxt->value->nodesetval != NULL))
8393 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8394 return (total);
8395 default:
8396 return (xmlXPathCompOpEval(ctxt, op));
8397 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008398}
8399
Owen Taylor3473f882001-02-23 17:55:21 +00008400/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008401 * xmlXPathCompOpEval:
8402 * @ctxt: the XPath parser context with the compiled expression
8403 * @op: an XPath compiled operation
8404 *
8405 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008406 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008407 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008408static int
8409xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
8410{
8411 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008412 int equal, ret;
8413 xmlXPathCompExprPtr comp;
8414 xmlXPathObjectPtr arg1, arg2;
8415
8416 comp = ctxt->comp;
8417 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008418 case XPATH_OP_END:
8419 return (0);
8420 case XPATH_OP_AND:
8421 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8422 xmlXPathBooleanFunction(ctxt, 1);
8423 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
8424 return (total);
8425 arg2 = valuePop(ctxt);
8426 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8427 xmlXPathBooleanFunction(ctxt, 1);
8428 arg1 = valuePop(ctxt);
8429 arg1->boolval &= arg2->boolval;
8430 valuePush(ctxt, arg1);
8431 xmlXPathFreeObject(arg2);
8432 return (total);
8433 case XPATH_OP_OR:
8434 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8435 xmlXPathBooleanFunction(ctxt, 1);
8436 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
8437 return (total);
8438 arg2 = valuePop(ctxt);
8439 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8440 xmlXPathBooleanFunction(ctxt, 1);
8441 arg1 = valuePop(ctxt);
8442 arg1->boolval |= arg2->boolval;
8443 valuePush(ctxt, arg1);
8444 xmlXPathFreeObject(arg2);
8445 return (total);
8446 case XPATH_OP_EQUAL:
8447 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8448 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8449 equal = xmlXPathEqualValues(ctxt);
8450 if (op->value)
8451 valuePush(ctxt, xmlXPathNewBoolean(equal));
8452 else
8453 valuePush(ctxt, xmlXPathNewBoolean(!equal));
8454 return (total);
8455 case XPATH_OP_CMP:
8456 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8457 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8458 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
8459 valuePush(ctxt, xmlXPathNewBoolean(ret));
8460 return (total);
8461 case XPATH_OP_PLUS:
8462 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8463 if (op->ch2 != -1)
8464 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8465 if (op->value == 0)
8466 xmlXPathSubValues(ctxt);
8467 else if (op->value == 1)
8468 xmlXPathAddValues(ctxt);
8469 else if (op->value == 2)
8470 xmlXPathValueFlipSign(ctxt);
8471 else if (op->value == 3) {
8472 CAST_TO_NUMBER;
8473 CHECK_TYPE0(XPATH_NUMBER);
8474 }
8475 return (total);
8476 case XPATH_OP_MULT:
8477 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8478 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8479 if (op->value == 0)
8480 xmlXPathMultValues(ctxt);
8481 else if (op->value == 1)
8482 xmlXPathDivValues(ctxt);
8483 else if (op->value == 2)
8484 xmlXPathModValues(ctxt);
8485 return (total);
8486 case XPATH_OP_UNION:
8487 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8488 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8489 CHECK_TYPE0(XPATH_NODESET);
8490 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008491
Daniel Veillardf06307e2001-07-03 10:35:50 +00008492 CHECK_TYPE0(XPATH_NODESET);
8493 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008494
Daniel Veillardf06307e2001-07-03 10:35:50 +00008495 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8496 arg2->nodesetval);
8497 valuePush(ctxt, arg1);
8498 xmlXPathFreeObject(arg2);
8499 return (total);
8500 case XPATH_OP_ROOT:
8501 xmlXPathRoot(ctxt);
8502 return (total);
8503 case XPATH_OP_NODE:
8504 if (op->ch1 != -1)
8505 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8506 if (op->ch2 != -1)
8507 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8508 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8509 return (total);
8510 case XPATH_OP_RESET:
8511 if (op->ch1 != -1)
8512 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8513 if (op->ch2 != -1)
8514 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8515 ctxt->context->node = NULL;
8516 return (total);
8517 case XPATH_OP_COLLECT:{
8518 if (op->ch1 == -1)
8519 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008520
Daniel Veillardf06307e2001-07-03 10:35:50 +00008521 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008522
Daniel Veillardf06307e2001-07-03 10:35:50 +00008523 /*
8524 * Optimization for [n] selection where n is a number
8525 */
8526 if ((op->ch2 != -1) &&
8527 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8528 (comp->steps[op->ch2].ch1 == -1) &&
8529 (comp->steps[op->ch2].ch2 != -1) &&
8530 (comp->steps[comp->steps[op->ch2].ch2].op ==
8531 XPATH_OP_VALUE)) {
8532 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00008533
Daniel Veillardf06307e2001-07-03 10:35:50 +00008534 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8535 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8536 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008537
Daniel Veillardf06307e2001-07-03 10:35:50 +00008538 if (val->floatval == (float) indx) {
8539 total +=
8540 xmlXPathNodeCollectAndTestNth(ctxt, op,
8541 indx, NULL,
8542 NULL);
8543 return (total);
8544 }
8545 }
8546 }
8547 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
8548 return (total);
8549 }
8550 case XPATH_OP_VALUE:
8551 valuePush(ctxt,
8552 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8553 return (total);
8554 case XPATH_OP_VARIABLE:{
8555 if (op->ch1 != -1)
8556 total +=
8557 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8558 if (op->value5 == NULL)
8559 valuePush(ctxt,
8560 xmlXPathVariableLookup(ctxt->context,
8561 op->value4));
8562 else {
8563 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008564
Daniel Veillardf06307e2001-07-03 10:35:50 +00008565 URI = xmlXPathNsLookup(ctxt->context, op->value5);
8566 if (URI == NULL) {
8567 xmlGenericError(xmlGenericErrorContext,
8568 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
8569 op->value4, op->value5);
8570 return (total);
8571 }
8572 valuePush(ctxt,
8573 xmlXPathVariableLookupNS(ctxt->context,
8574 op->value4, URI));
8575 }
8576 return (total);
8577 }
8578 case XPATH_OP_FUNCTION:{
8579 xmlXPathFunction func;
8580 const xmlChar *oldFunc, *oldFuncURI;
8581
8582 if (op->ch1 != -1)
8583 total +=
8584 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8585 if (op->cache != NULL)
8586 func = (xmlXPathFunction) op->cache;
8587 else {
8588 const xmlChar *URI = NULL;
8589
8590 if (op->value5 == NULL)
8591 func =
8592 xmlXPathFunctionLookup(ctxt->context,
8593 op->value4);
8594 else {
8595 URI = xmlXPathNsLookup(ctxt->context, op->value5);
8596 if (URI == NULL) {
8597 xmlGenericError(xmlGenericErrorContext,
8598 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
8599 op->value4, op->value5);
8600 return (total);
8601 }
8602 func = xmlXPathFunctionLookupNS(ctxt->context,
8603 op->value4, URI);
8604 }
8605 if (func == NULL) {
8606 xmlGenericError(xmlGenericErrorContext,
8607 "xmlXPathRunEval: function %s not found\n",
8608 op->value4);
8609 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
8610 return (total);
8611 }
8612 op->cache = (void *) func;
8613 op->cacheURI = (void *) URI;
8614 }
8615 oldFunc = ctxt->context->function;
8616 oldFuncURI = ctxt->context->functionURI;
8617 ctxt->context->function = op->value4;
8618 ctxt->context->functionURI = op->cacheURI;
8619 func(ctxt, op->value);
8620 ctxt->context->function = oldFunc;
8621 ctxt->context->functionURI = oldFuncURI;
8622 return (total);
8623 }
8624 case XPATH_OP_ARG:
8625 if (op->ch1 != -1)
8626 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8627 if (op->ch2 != -1)
8628 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8629 return (total);
8630 case XPATH_OP_PREDICATE:
8631 case XPATH_OP_FILTER:{
8632 xmlXPathObjectPtr res;
8633 xmlXPathObjectPtr obj, tmp;
8634 xmlNodeSetPtr newset = NULL;
8635 xmlNodeSetPtr oldset;
8636 xmlNodePtr oldnode;
8637 int i;
8638
8639 /*
8640 * Optimization for ()[1] selection i.e. the first elem
8641 */
8642 if ((op->ch1 != -1) && (op->ch2 != -1) &&
8643 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
8644 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
8645 xmlXPathObjectPtr val;
8646
8647 val = comp->steps[op->ch2].value4;
8648 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
8649 (val->floatval == 1.0)) {
8650 xmlNodePtr first = NULL;
8651
8652 total +=
8653 xmlXPathCompOpEvalFirst(ctxt,
8654 &comp->steps[op->ch1],
8655 &first);
8656 /*
8657 * The nodeset should be in document order,
8658 * Keep only the first value
8659 */
8660 if ((ctxt->value != NULL) &&
8661 (ctxt->value->type == XPATH_NODESET) &&
8662 (ctxt->value->nodesetval != NULL) &&
8663 (ctxt->value->nodesetval->nodeNr > 1))
8664 ctxt->value->nodesetval->nodeNr = 1;
8665 return (total);
8666 }
8667 }
8668 /*
8669 * Optimization for ()[last()] selection i.e. the last elem
8670 */
8671 if ((op->ch1 != -1) && (op->ch2 != -1) &&
8672 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
8673 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
8674 int f = comp->steps[op->ch2].ch1;
8675
8676 if ((f != -1) &&
8677 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
8678 (comp->steps[f].value5 == NULL) &&
8679 (comp->steps[f].value == 0) &&
8680 (comp->steps[f].value4 != NULL) &&
8681 (xmlStrEqual
8682 (comp->steps[f].value4, BAD_CAST "last"))) {
8683 xmlNodePtr last = NULL;
8684
8685 total +=
8686 xmlXPathCompOpEvalLast(ctxt,
8687 &comp->steps[op->ch1],
8688 &last);
8689 /*
8690 * The nodeset should be in document order,
8691 * Keep only the last value
8692 */
8693 if ((ctxt->value != NULL) &&
8694 (ctxt->value->type == XPATH_NODESET) &&
8695 (ctxt->value->nodesetval != NULL) &&
8696 (ctxt->value->nodesetval->nodeTab != NULL) &&
8697 (ctxt->value->nodesetval->nodeNr > 1)) {
8698 ctxt->value->nodesetval->nodeTab[0] =
8699 ctxt->value->nodesetval->nodeTab[ctxt->
8700 value->
8701 nodesetval->
8702 nodeNr -
8703 1];
8704 ctxt->value->nodesetval->nodeNr = 1;
8705 }
8706 return (total);
8707 }
8708 }
8709
8710 if (op->ch1 != -1)
8711 total +=
8712 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8713 if (op->ch2 == -1)
8714 return (total);
8715 if (ctxt->value == NULL)
8716 return (total);
8717
8718 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008719
8720#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00008721 /*
8722 * Hum are we filtering the result of an XPointer expression
8723 */
8724 if (ctxt->value->type == XPATH_LOCATIONSET) {
8725 xmlLocationSetPtr newlocset = NULL;
8726 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008727
Daniel Veillardf06307e2001-07-03 10:35:50 +00008728 /*
8729 * Extract the old locset, and then evaluate the result of the
8730 * expression for all the element in the locset. use it to grow
8731 * up a new locset.
8732 */
8733 CHECK_TYPE0(XPATH_LOCATIONSET);
8734 obj = valuePop(ctxt);
8735 oldlocset = obj->user;
8736 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008737
Daniel Veillardf06307e2001-07-03 10:35:50 +00008738 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
8739 ctxt->context->contextSize = 0;
8740 ctxt->context->proximityPosition = 0;
8741 if (op->ch2 != -1)
8742 total +=
8743 xmlXPathCompOpEval(ctxt,
8744 &comp->steps[op->ch2]);
8745 res = valuePop(ctxt);
8746 if (res != NULL)
8747 xmlXPathFreeObject(res);
8748 valuePush(ctxt, obj);
8749 CHECK_ERROR0;
8750 return (total);
8751 }
8752 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008753
Daniel Veillardf06307e2001-07-03 10:35:50 +00008754 for (i = 0; i < oldlocset->locNr; i++) {
8755 /*
8756 * Run the evaluation with a node list made of a
8757 * single item in the nodelocset.
8758 */
8759 ctxt->context->node = oldlocset->locTab[i]->user;
8760 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8761 valuePush(ctxt, tmp);
8762 ctxt->context->contextSize = oldlocset->locNr;
8763 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008764
Daniel Veillardf06307e2001-07-03 10:35:50 +00008765 if (op->ch2 != -1)
8766 total +=
8767 xmlXPathCompOpEval(ctxt,
8768 &comp->steps[op->ch2]);
8769 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008770
Daniel Veillardf06307e2001-07-03 10:35:50 +00008771 /*
8772 * The result of the evaluation need to be tested to
8773 * decided whether the filter succeeded or not
8774 */
8775 res = valuePop(ctxt);
8776 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
8777 xmlXPtrLocationSetAdd(newlocset,
8778 xmlXPathObjectCopy
8779 (oldlocset->locTab[i]));
8780 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008781
Daniel Veillardf06307e2001-07-03 10:35:50 +00008782 /*
8783 * Cleanup
8784 */
8785 if (res != NULL)
8786 xmlXPathFreeObject(res);
8787 if (ctxt->value == tmp) {
8788 res = valuePop(ctxt);
8789 xmlXPathFreeObject(res);
8790 }
8791
8792 ctxt->context->node = NULL;
8793 }
8794
8795 /*
8796 * The result is used as the new evaluation locset.
8797 */
8798 xmlXPathFreeObject(obj);
8799 ctxt->context->node = NULL;
8800 ctxt->context->contextSize = -1;
8801 ctxt->context->proximityPosition = -1;
8802 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
8803 ctxt->context->node = oldnode;
8804 return (total);
8805 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008806#endif /* LIBXML_XPTR_ENABLED */
8807
Daniel Veillardf06307e2001-07-03 10:35:50 +00008808 /*
8809 * Extract the old set, and then evaluate the result of the
8810 * expression for all the element in the set. use it to grow
8811 * up a new set.
8812 */
8813 CHECK_TYPE0(XPATH_NODESET);
8814 obj = valuePop(ctxt);
8815 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00008816
Daniel Veillardf06307e2001-07-03 10:35:50 +00008817 oldnode = ctxt->context->node;
8818 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008819
Daniel Veillardf06307e2001-07-03 10:35:50 +00008820 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
8821 ctxt->context->contextSize = 0;
8822 ctxt->context->proximityPosition = 0;
8823 if (op->ch2 != -1)
8824 total +=
8825 xmlXPathCompOpEval(ctxt,
8826 &comp->steps[op->ch2]);
8827 res = valuePop(ctxt);
8828 if (res != NULL)
8829 xmlXPathFreeObject(res);
8830 valuePush(ctxt, obj);
8831 ctxt->context->node = oldnode;
8832 CHECK_ERROR0;
8833 } else {
8834 /*
8835 * Initialize the new set.
8836 */
8837 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008838
Daniel Veillardf06307e2001-07-03 10:35:50 +00008839 for (i = 0; i < oldset->nodeNr; i++) {
8840 /*
8841 * Run the evaluation with a node list made of
8842 * a single item in the nodeset.
8843 */
8844 ctxt->context->node = oldset->nodeTab[i];
8845 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8846 valuePush(ctxt, tmp);
8847 ctxt->context->contextSize = oldset->nodeNr;
8848 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008849
Daniel Veillardf06307e2001-07-03 10:35:50 +00008850 if (op->ch2 != -1)
8851 total +=
8852 xmlXPathCompOpEval(ctxt,
8853 &comp->steps[op->ch2]);
8854 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008855
Daniel Veillardf06307e2001-07-03 10:35:50 +00008856 /*
8857 * The result of the evaluation need to be tested to
8858 * decided whether the filter succeeded or not
8859 */
8860 res = valuePop(ctxt);
8861 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
8862 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
8863 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008864
Daniel Veillardf06307e2001-07-03 10:35:50 +00008865 /*
8866 * Cleanup
8867 */
8868 if (res != NULL)
8869 xmlXPathFreeObject(res);
8870 if (ctxt->value == tmp) {
8871 res = valuePop(ctxt);
8872 xmlXPathFreeObject(res);
8873 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008874
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 ctxt->context->node = NULL;
8876 }
8877
8878 /*
8879 * The result is used as the new evaluation set.
8880 */
8881 xmlXPathFreeObject(obj);
8882 ctxt->context->node = NULL;
8883 ctxt->context->contextSize = -1;
8884 ctxt->context->proximityPosition = -1;
8885 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
8886 }
8887 ctxt->context->node = oldnode;
8888 return (total);
8889 }
8890 case XPATH_OP_SORT:
8891 if (op->ch1 != -1)
8892 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8893 if ((ctxt->value != NULL) &&
8894 (ctxt->value->type == XPATH_NODESET) &&
8895 (ctxt->value->nodesetval != NULL))
8896 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8897 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008898#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899 case XPATH_OP_RANGETO:{
8900 xmlXPathObjectPtr range;
8901 xmlXPathObjectPtr res, obj;
8902 xmlXPathObjectPtr tmp;
8903 xmlLocationSetPtr newset = NULL;
8904 xmlNodeSetPtr oldset;
8905 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008906
Daniel Veillardf06307e2001-07-03 10:35:50 +00008907 if (op->ch1 != -1)
8908 total +=
8909 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8910 if (op->ch2 == -1)
8911 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008912
Daniel Veillardf06307e2001-07-03 10:35:50 +00008913 CHECK_TYPE0(XPATH_NODESET);
8914 obj = valuePop(ctxt);
8915 oldset = obj->nodesetval;
8916 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008917
Daniel Veillardf06307e2001-07-03 10:35:50 +00008918 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008919
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 if (oldset != NULL) {
8921 for (i = 0; i < oldset->nodeNr; i++) {
8922 /*
8923 * Run the evaluation with a node list made of a single item
8924 * in the nodeset.
8925 */
8926 ctxt->context->node = oldset->nodeTab[i];
8927 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8928 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008929
Daniel Veillardf06307e2001-07-03 10:35:50 +00008930 if (op->ch2 != -1)
8931 total +=
8932 xmlXPathCompOpEval(ctxt,
8933 &comp->steps[op->ch2]);
8934 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008935
Daniel Veillardf06307e2001-07-03 10:35:50 +00008936 /*
8937 * The result of the evaluation need to be tested to
8938 * decided whether the filter succeeded or not
8939 */
8940 res = valuePop(ctxt);
8941 range =
8942 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
8943 res);
8944 if (range != NULL) {
8945 xmlXPtrLocationSetAdd(newset, range);
8946 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008947
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948 /*
8949 * Cleanup
8950 */
8951 if (res != NULL)
8952 xmlXPathFreeObject(res);
8953 if (ctxt->value == tmp) {
8954 res = valuePop(ctxt);
8955 xmlXPathFreeObject(res);
8956 }
8957
8958 ctxt->context->node = NULL;
8959 }
8960 }
8961
8962 /*
8963 * The result is used as the new evaluation set.
8964 */
8965 xmlXPathFreeObject(obj);
8966 ctxt->context->node = NULL;
8967 ctxt->context->contextSize = -1;
8968 ctxt->context->proximityPosition = -1;
8969 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
8970 return (total);
8971 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008972#endif /* LIBXML_XPTR_ENABLED */
8973 }
8974 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 "XPath: unknown precompiled operation %d\n", op->op);
8976 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008977}
8978
8979/**
8980 * xmlXPathRunEval:
8981 * @ctxt: the XPath parser context with the compiled expression
8982 *
8983 * Evaluate the Precompiled XPath expression in the given context.
8984 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008985static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008986xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
8987 xmlXPathCompExprPtr comp;
8988
8989 if ((ctxt == NULL) || (ctxt->comp == NULL))
8990 return;
8991
8992 if (ctxt->valueTab == NULL) {
8993 /* Allocate the value stack */
8994 ctxt->valueTab = (xmlXPathObjectPtr *)
8995 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
8996 if (ctxt->valueTab == NULL) {
8997 xmlFree(ctxt);
8998 xmlGenericError(xmlGenericErrorContext,
8999 "xmlXPathRunEval: out of memory\n");
9000 return;
9001 }
9002 ctxt->valueNr = 0;
9003 ctxt->valueMax = 10;
9004 ctxt->value = NULL;
9005 }
9006 comp = ctxt->comp;
9007 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9008}
9009
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009010/************************************************************************
9011 * *
9012 * Public interfaces *
9013 * *
9014 ************************************************************************/
9015
9016/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009017 * xmlXPathEvalPredicate:
9018 * @ctxt: the XPath context
9019 * @res: the Predicate Expression evaluation result
9020 *
9021 * Evaluate a predicate result for the current node.
9022 * A PredicateExpr is evaluated by evaluating the Expr and converting
9023 * the result to a boolean. If the result is a number, the result will
9024 * be converted to true if the number is equal to the position of the
9025 * context node in the context node list (as returned by the position
9026 * function) and will be converted to false otherwise; if the result
9027 * is not a number, then the result will be converted as if by a call
9028 * to the boolean function.
9029 *
9030 * Return 1 if predicate is true, 0 otherwise
9031 */
9032int
9033xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9034 if (res == NULL) return(0);
9035 switch (res->type) {
9036 case XPATH_BOOLEAN:
9037 return(res->boolval);
9038 case XPATH_NUMBER:
9039 return(res->floatval == ctxt->proximityPosition);
9040 case XPATH_NODESET:
9041 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009042 if (res->nodesetval == NULL)
9043 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009044 return(res->nodesetval->nodeNr != 0);
9045 case XPATH_STRING:
9046 return((res->stringval != NULL) &&
9047 (xmlStrlen(res->stringval) != 0));
9048 default:
9049 STRANGE
9050 }
9051 return(0);
9052}
9053
9054/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009055 * xmlXPathEvaluatePredicateResult:
9056 * @ctxt: the XPath Parser context
9057 * @res: the Predicate Expression evaluation result
9058 *
9059 * Evaluate a predicate result for the current node.
9060 * A PredicateExpr is evaluated by evaluating the Expr and converting
9061 * the result to a boolean. If the result is a number, the result will
9062 * be converted to true if the number is equal to the position of the
9063 * context node in the context node list (as returned by the position
9064 * function) and will be converted to false otherwise; if the result
9065 * is not a number, then the result will be converted as if by a call
9066 * to the boolean function.
9067 *
9068 * Return 1 if predicate is true, 0 otherwise
9069 */
9070int
9071xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9072 xmlXPathObjectPtr res) {
9073 if (res == NULL) return(0);
9074 switch (res->type) {
9075 case XPATH_BOOLEAN:
9076 return(res->boolval);
9077 case XPATH_NUMBER:
9078 return(res->floatval == ctxt->context->proximityPosition);
9079 case XPATH_NODESET:
9080 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009081 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009082 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009083 return(res->nodesetval->nodeNr != 0);
9084 case XPATH_STRING:
9085 return((res->stringval != NULL) &&
9086 (xmlStrlen(res->stringval) != 0));
9087 default:
9088 STRANGE
9089 }
9090 return(0);
9091}
9092
9093/**
9094 * xmlXPathCompile:
9095 * @str: the XPath expression
9096 *
9097 * Compile an XPath expression
9098 *
9099 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9100 * the caller has to free the object.
9101 */
9102xmlXPathCompExprPtr
9103xmlXPathCompile(const xmlChar *str) {
9104 xmlXPathParserContextPtr ctxt;
9105 xmlXPathCompExprPtr comp;
9106
9107 xmlXPathInit();
9108
9109 ctxt = xmlXPathNewParserContext(str, NULL);
9110 xmlXPathCompileExpr(ctxt);
9111
Daniel Veillard40af6492001-04-22 08:50:55 +00009112 if (*ctxt->cur != 0) {
9113 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9114 comp = NULL;
9115 } else {
9116 comp = ctxt->comp;
9117 ctxt->comp = NULL;
9118 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009119 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120#ifdef DEBUG_EVAL_COUNTS
9121 if (comp != NULL) {
9122 comp->string = xmlStrdup(str);
9123 comp->nb = 0;
9124 }
9125#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009126 return(comp);
9127}
9128
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009129/**
9130 * xmlXPathCompiledEval:
9131 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009132 * @ctx: the XPath context
9133 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009134 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009135 *
9136 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9137 * the caller has to free the object.
9138 */
9139xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009140xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009141 xmlXPathParserContextPtr ctxt;
9142 xmlXPathObjectPtr res, tmp, init = NULL;
9143 int stack = 0;
9144
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009145 if ((comp == NULL) || (ctx == NULL))
9146 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009147 xmlXPathInit();
9148
9149 CHECK_CONTEXT(ctx)
9150
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151#ifdef DEBUG_EVAL_COUNTS
9152 comp->nb++;
9153 if ((comp->string != NULL) && (comp->nb > 100)) {
9154 fprintf(stderr, "100 x %s\n", comp->string);
9155 comp->nb = 0;
9156 }
9157#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009158 ctxt = xmlXPathCompParserContext(comp, ctx);
9159 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009160
9161 if (ctxt->value == NULL) {
9162 xmlGenericError(xmlGenericErrorContext,
9163 "xmlXPathEval: evaluation failed\n");
9164 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009165 } else {
9166 res = valuePop(ctxt);
9167 }
9168
Daniel Veillardf06307e2001-07-03 10:35:50 +00009169
Owen Taylor3473f882001-02-23 17:55:21 +00009170 do {
9171 tmp = valuePop(ctxt);
9172 if (tmp != NULL) {
9173 if (tmp != init)
9174 stack++;
9175 xmlXPathFreeObject(tmp);
9176 }
9177 } while (tmp != NULL);
9178 if ((stack != 0) && (res != NULL)) {
9179 xmlGenericError(xmlGenericErrorContext,
9180 "xmlXPathEval: %d object left on the stack\n",
9181 stack);
9182 }
9183 if (ctxt->error != XPATH_EXPRESSION_OK) {
9184 xmlXPathFreeObject(res);
9185 res = NULL;
9186 }
9187
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009188
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009189 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009190 xmlXPathFreeParserContext(ctxt);
9191 return(res);
9192}
9193
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009194/**
9195 * xmlXPathEvalExpr:
9196 * @ctxt: the XPath Parser context
9197 *
9198 * Parse and evaluate an XPath expression in the given context,
9199 * then push the result on the context stack
9200 */
9201void
9202xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9203 xmlXPathCompileExpr(ctxt);
9204 xmlXPathRunEval(ctxt);
9205}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009206
9207/**
9208 * xmlXPathEval:
9209 * @str: the XPath expression
9210 * @ctx: the XPath context
9211 *
9212 * Evaluate the XPath Location Path in the given context.
9213 *
9214 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9215 * the caller has to free the object.
9216 */
9217xmlXPathObjectPtr
9218xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9219 xmlXPathParserContextPtr ctxt;
9220 xmlXPathObjectPtr res, tmp, init = NULL;
9221 int stack = 0;
9222
9223 xmlXPathInit();
9224
9225 CHECK_CONTEXT(ctx)
9226
9227 ctxt = xmlXPathNewParserContext(str, ctx);
9228 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009229
9230 if (ctxt->value == NULL) {
9231 xmlGenericError(xmlGenericErrorContext,
9232 "xmlXPathEval: evaluation failed\n");
9233 res = NULL;
9234 } else if (*ctxt->cur != 0) {
9235 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9236 res = NULL;
9237 } else {
9238 res = valuePop(ctxt);
9239 }
9240
9241 do {
9242 tmp = valuePop(ctxt);
9243 if (tmp != NULL) {
9244 if (tmp != init)
9245 stack++;
9246 xmlXPathFreeObject(tmp);
9247 }
9248 } while (tmp != NULL);
9249 if ((stack != 0) && (res != NULL)) {
9250 xmlGenericError(xmlGenericErrorContext,
9251 "xmlXPathEval: %d object left on the stack\n",
9252 stack);
9253 }
9254 if (ctxt->error != XPATH_EXPRESSION_OK) {
9255 xmlXPathFreeObject(res);
9256 res = NULL;
9257 }
9258
Owen Taylor3473f882001-02-23 17:55:21 +00009259 xmlXPathFreeParserContext(ctxt);
9260 return(res);
9261}
9262
9263/**
9264 * xmlXPathEvalExpression:
9265 * @str: the XPath expression
9266 * @ctxt: the XPath context
9267 *
9268 * Evaluate the XPath expression in the given context.
9269 *
9270 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9271 * the caller has to free the object.
9272 */
9273xmlXPathObjectPtr
9274xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9275 xmlXPathParserContextPtr pctxt;
9276 xmlXPathObjectPtr res, tmp;
9277 int stack = 0;
9278
9279 xmlXPathInit();
9280
9281 CHECK_CONTEXT(ctxt)
9282
9283 pctxt = xmlXPathNewParserContext(str, ctxt);
9284 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009285
9286 if (*pctxt->cur != 0) {
9287 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9288 res = NULL;
9289 } else {
9290 res = valuePop(pctxt);
9291 }
9292 do {
9293 tmp = valuePop(pctxt);
9294 if (tmp != NULL) {
9295 xmlXPathFreeObject(tmp);
9296 stack++;
9297 }
9298 } while (tmp != NULL);
9299 if ((stack != 0) && (res != NULL)) {
9300 xmlGenericError(xmlGenericErrorContext,
9301 "xmlXPathEvalExpression: %d object left on the stack\n",
9302 stack);
9303 }
9304 xmlXPathFreeParserContext(pctxt);
9305 return(res);
9306}
9307
9308/**
9309 * xmlXPathRegisterAllFunctions:
9310 * @ctxt: the XPath context
9311 *
9312 * Registers all default XPath functions in this context
9313 */
9314void
9315xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9316{
9317 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9318 xmlXPathBooleanFunction);
9319 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9320 xmlXPathCeilingFunction);
9321 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9322 xmlXPathCountFunction);
9323 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9324 xmlXPathConcatFunction);
9325 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9326 xmlXPathContainsFunction);
9327 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9328 xmlXPathIdFunction);
9329 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9330 xmlXPathFalseFunction);
9331 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9332 xmlXPathFloorFunction);
9333 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9334 xmlXPathLastFunction);
9335 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9336 xmlXPathLangFunction);
9337 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9338 xmlXPathLocalNameFunction);
9339 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9340 xmlXPathNotFunction);
9341 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9342 xmlXPathNameFunction);
9343 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9344 xmlXPathNamespaceURIFunction);
9345 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9346 xmlXPathNormalizeFunction);
9347 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9348 xmlXPathNumberFunction);
9349 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9350 xmlXPathPositionFunction);
9351 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9352 xmlXPathRoundFunction);
9353 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9354 xmlXPathStringFunction);
9355 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9356 xmlXPathStringLengthFunction);
9357 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9358 xmlXPathStartsWithFunction);
9359 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9360 xmlXPathSubstringFunction);
9361 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9362 xmlXPathSubstringBeforeFunction);
9363 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9364 xmlXPathSubstringAfterFunction);
9365 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9366 xmlXPathSumFunction);
9367 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9368 xmlXPathTrueFunction);
9369 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9370 xmlXPathTranslateFunction);
9371}
9372
9373#endif /* LIBXML_XPATH_ENABLED */